Your IP : 216.73.217.77


Current Path : /home/users/unlimited/www/egrocer.codeskitter.site/public/assets/vendors/ckeditor/
Upload File :
Current File : /home/users/unlimited/www/egrocer.codeskitter.site/public/assets/vendors/ckeditor/ckeditor.js.map

{"version":3,"sources":["webpack://ClassicEditor/webpack/universalModuleDefinition","webpack://ClassicEditor/webpack/bootstrap","webpack://ClassicEditor/../ckeditor5-utils/src/ckeditorerror.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_root.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/isBuffer.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_nodeUtil.js","webpack://ClassicEditor/../ckeditor5-utils/src/version.js","webpack://ClassicEditor/../ckeditor5-ui/theme/components/responsive-form/responsiveform.css?6f59","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_freeGlobal.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_cloneBuffer.js","webpack://ClassicEditor/(webpack)/buildin/harmony-module.js","webpack://ClassicEditor/(webpack)/buildin/global.js","webpack://ClassicEditor/../ckeditor5-heading/theme/heading.css?e55a","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/stubFalse.js","webpack://ClassicEditor/../ckeditor5-engine/theme/placeholder.css?da8f","webpack://ClassicEditor/../ckeditor5-engine/theme/placeholder.css","webpack://ClassicEditor/../ckeditor5-ui/theme/globals/globals.css?2fbc","webpack://ClassicEditor/../ckeditor5-ui/theme/globals/globals.css","webpack://ClassicEditor/../ckeditor5-ui/theme/components/editorui/editorui.css?1b42","webpack://ClassicEditor/../ckeditor5-ui/theme/components/editorui/editorui.css","webpack://ClassicEditor/../ckeditor5-ui/theme/components/label/label.css?fe04","webpack://ClassicEditor/../ckeditor5-ui/theme/components/label/label.css","webpack://ClassicEditor/../ckeditor5-ui/theme/components/panel/stickypanel.css?4d41","webpack://ClassicEditor/../ckeditor5-ui/theme/components/panel/stickypanel.css","webpack://ClassicEditor/../ckeditor5-ui/theme/components/dropdown/dropdown.css?ed4c","webpack://ClassicEditor/../ckeditor5-ui/theme/components/dropdown/dropdown.css","webpack://ClassicEditor/../ckeditor5-ui/theme/components/icon/icon.css?5727","webpack://ClassicEditor/../ckeditor5-ui/theme/components/icon/icon.css","webpack://ClassicEditor/../ckeditor5-ui/theme/components/tooltip/tooltip.css?8e75","webpack://ClassicEditor/../ckeditor5-ui/theme/components/tooltip/tooltip.css","webpack://ClassicEditor/../ckeditor5-ui/theme/components/button/button.css?ce6e","webpack://ClassicEditor/../ckeditor5-ui/theme/components/button/button.css","webpack://ClassicEditor/../ckeditor5-ui/theme/components/list/list.css?022f","webpack://ClassicEditor/../ckeditor5-ui/theme/components/list/list.css","webpack://ClassicEditor/../ckeditor5-ui/theme/components/button/switchbutton.css?0c2d","webpack://ClassicEditor/../ckeditor5-ui/theme/components/button/switchbutton.css","webpack://ClassicEditor/../ckeditor5-ui/theme/components/dropdown/toolbardropdown.css?8b86","webpack://ClassicEditor/../ckeditor5-ui/theme/components/dropdown/toolbardropdown.css","webpack://ClassicEditor/../ckeditor5-ui/theme/components/dropdown/listdropdown.css?df0b","webpack://ClassicEditor/../ckeditor5-ui/theme/components/dropdown/listdropdown.css","webpack://ClassicEditor/../ckeditor5-ui/theme/components/toolbar/toolbar.css?25c7","webpack://ClassicEditor/../ckeditor5-ui/theme/components/toolbar/toolbar.css","webpack://ClassicEditor/../ckeditor5-editor-classic/theme/classiceditor.css?78b5","webpack://ClassicEditor/../ckeditor5-editor-classic/theme/classiceditor.css","webpack://ClassicEditor/../ckeditor5-block-quote/theme/blockquote.css?446e","webpack://ClassicEditor/../ckeditor5-block-quote/theme/blockquote.css","webpack://ClassicEditor/../ckeditor5-ui/theme/components/panel/balloonpanel.css?d9a5","webpack://ClassicEditor/../ckeditor5-ui/theme/components/panel/balloonpanel.css","webpack://ClassicEditor/../ckeditor5-link/theme/link.css?fff3","webpack://ClassicEditor/../ckeditor5-link/theme/link.css","webpack://ClassicEditor/../ckeditor5-widget/theme/widgettypearound.css?4755","webpack://ClassicEditor/../ckeditor5-widget/theme/widgettypearound.css","webpack://ClassicEditor/../ckeditor5-widget/theme/widget.css?4a91","webpack://ClassicEditor/../ckeditor5-widget/theme/widget.css","webpack://ClassicEditor/../ckeditor5-ui/theme/components/labeledfield/labeledfieldview.css?18da","webpack://ClassicEditor/../ckeditor5-ui/theme/components/labeledfield/labeledfieldview.css","webpack://ClassicEditor/../ckeditor5-ui/theme/components/inputtext/inputtext.css?62e4","webpack://ClassicEditor/../ckeditor5-ui/theme/components/inputtext/inputtext.css","webpack://ClassicEditor/../ckeditor5-image/theme/textalternativeform.css?387b","webpack://ClassicEditor/../ckeditor5-image/theme/textalternativeform.css","webpack://ClassicEditor/../ckeditor5-ui/theme/components/responsive-form/responsiveform.css","webpack://ClassicEditor/../ckeditor5-ui/theme/components/panel/balloonrotator.css?67c7","webpack://ClassicEditor/../ckeditor5-ui/theme/components/panel/balloonrotator.css","webpack://ClassicEditor/../ckeditor5-ui/theme/components/panel/fakepanel.css?a8d1","webpack://ClassicEditor/../ckeditor5-ui/theme/components/panel/fakepanel.css","webpack://ClassicEditor/../ckeditor5-image/theme/image.css?5712","webpack://ClassicEditor/../ckeditor5-image/theme/image.css","webpack://ClassicEditor/../ckeditor5-image/theme/imageuploadprogress.css?e96b","webpack://ClassicEditor/../ckeditor5-image/theme/imageuploadprogress.css","webpack://ClassicEditor/../ckeditor5-image/theme/imageuploadicon.css?f4ac","webpack://ClassicEditor/../ckeditor5-image/theme/imageuploadicon.css","webpack://ClassicEditor/../ckeditor5-image/theme/imageuploadloader.css?82d9","webpack://ClassicEditor/../ckeditor5-image/theme/imageuploadloader.css","webpack://ClassicEditor/../ckeditor5-heading/theme/heading.css","webpack://ClassicEditor/../ckeditor5-image/theme/imagecaption.css?0273","webpack://ClassicEditor/../ckeditor5-image/theme/imagecaption.css","webpack://ClassicEditor/../ckeditor5-image/theme/imagestyle.css?f76f","webpack://ClassicEditor/../ckeditor5-image/theme/imagestyle.css","webpack://ClassicEditor/../ckeditor5-link/theme/linkform.css?4f98","webpack://ClassicEditor/../ckeditor5-link/theme/linkform.css","webpack://ClassicEditor/../ckeditor5-link/theme/linkactions.css?b826","webpack://ClassicEditor/../ckeditor5-link/theme/linkactions.css","webpack://ClassicEditor/../ckeditor5-media-embed/theme/mediaembedediting.css?5710","webpack://ClassicEditor/../ckeditor5-media-embed/theme/mediaembedediting.css","webpack://ClassicEditor/../ckeditor5-media-embed/theme/mediaform.css?6b39","webpack://ClassicEditor/../ckeditor5-media-embed/theme/mediaform.css","webpack://ClassicEditor/../ckeditor5-media-embed/theme/mediaembed.css?159a","webpack://ClassicEditor/../ckeditor5-media-embed/theme/mediaembed.css","webpack://ClassicEditor/../ckeditor5-table/theme/tableediting.css?41d4","webpack://ClassicEditor/../ckeditor5-table/theme/tableediting.css","webpack://ClassicEditor/../ckeditor5-ui/theme/components/dropdown/splitbutton.css?0160","webpack://ClassicEditor/../ckeditor5-ui/theme/components/dropdown/splitbutton.css","webpack://ClassicEditor/../ckeditor5-table/theme/inserttable.css?3ff7","webpack://ClassicEditor/../ckeditor5-table/theme/inserttable.css","webpack://ClassicEditor/../ckeditor5-table/theme/tableselection.css?4eee","webpack://ClassicEditor/../ckeditor5-table/theme/tableselection.css","webpack://ClassicEditor/../ckeditor5-table/theme/table.css?02bc","webpack://ClassicEditor/../ckeditor5-table/theme/table.css","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_Symbol.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_getRawTag.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_objectToString.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseGetTag.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_overArg.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_getPrototype.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/isObjectLike.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/isPlainObject.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_listCacheClear.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/eq.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_assocIndexOf.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_listCacheDelete.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_listCacheGet.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_listCacheHas.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_listCacheSet.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_ListCache.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_stackClear.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_stackDelete.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_stackGet.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_stackHas.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/isObject.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/isFunction.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_isMasked.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_coreJsData.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_toSource.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseIsNative.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_getValue.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_getNative.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_Map.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_nativeCreate.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_hashClear.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_hashDelete.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_hashGet.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_hashHas.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_hashSet.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_Hash.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_mapCacheClear.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_isKeyable.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_getMapData.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_mapCacheDelete.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_mapCacheGet.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_mapCacheHas.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_mapCacheSet.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_MapCache.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_stackSet.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_Stack.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_arrayEach.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_defineProperty.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseAssignValue.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_assignValue.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_copyObject.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseTimes.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseIsArguments.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/isArguments.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/isArray.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_isIndex.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/isLength.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseIsTypedArray.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseUnary.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/isTypedArray.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_arrayLikeKeys.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_isPrototype.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_nativeKeys.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseKeys.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/isArrayLike.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/keys.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseAssign.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_nativeKeysIn.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseKeysIn.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/keysIn.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseAssignIn.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_copyArray.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_arrayFilter.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/stubArray.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_getSymbols.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_copySymbols.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_arrayPush.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_getSymbolsIn.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_copySymbolsIn.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseGetAllKeys.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_getAllKeys.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_getAllKeysIn.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_DataView.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_Promise.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_Set.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_WeakMap.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_getTag.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_initCloneArray.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_Uint8Array.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_cloneArrayBuffer.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_cloneDataView.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_cloneRegExp.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_cloneSymbol.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_cloneTypedArray.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_initCloneByTag.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseCreate.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_initCloneObject.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseIsMap.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/isMap.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseIsSet.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/isSet.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseClone.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/cloneDeepWith.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/isElement.js","webpack://ClassicEditor/../ckeditor5-utils/src/config.js","webpack://ClassicEditor/../ckeditor5-utils/src/spy.js","webpack://ClassicEditor/../ckeditor5-utils/src/eventinfo.js","webpack://ClassicEditor/../ckeditor5-utils/src/uid.js","webpack://ClassicEditor/../ckeditor5-utils/src/priorities.js","webpack://ClassicEditor/../ckeditor5-utils/src/emittermixin.js","webpack://ClassicEditor/../ckeditor5-utils/src/isiterable.js","webpack://ClassicEditor/../ckeditor5-utils/src/mix.js","webpack://ClassicEditor/../ckeditor5-utils/src/collection.js","webpack://ClassicEditor/../ckeditor5-core/src/plugincollection.js","webpack://ClassicEditor/../ckeditor5-utils/src/toarray.js","webpack://ClassicEditor/../ckeditor5-utils/src/translation-service.js","webpack://ClassicEditor/../ckeditor5-utils/src/locale.js","webpack://ClassicEditor/../ckeditor5-core/src/context.js","webpack://ClassicEditor/../ckeditor5-utils/src/comparearrays.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/clone.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/node.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/text.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/textproxy.js","webpack://ClassicEditor/../ckeditor5-utils/src/tomap.js","webpack://ClassicEditor/../ckeditor5-utils/src/objecttomap.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/matcher.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/isSymbol.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_isKey.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/memoize.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_memoizeCapped.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_stringToPath.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_arrayMap.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseToString.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/toString.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_castPath.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/last.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_toKey.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseGet.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseSlice.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_parent.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseUnset.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/unset.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/get.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_assignMergeValue.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_createBaseFor.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseFor.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/isArrayLikeObject.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_safeGet.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/toPlainObject.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseMergeDeep.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseMerge.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/identity.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_apply.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_overRest.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/constant.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseSetToString.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_shortOut.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_setToString.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseRest.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_isIterateeCall.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_createAssigner.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/merge.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseSet.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/set.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/stylesmap.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/element.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/containerelement.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/assignIn.js","webpack://ClassicEditor/../ckeditor5-utils/src/observablemixin.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/editableelement.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/rooteditableelement.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/treewalker.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/position.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/range.js","webpack://ClassicEditor/../ckeditor5-utils/src/count.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/selection.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/documentselection.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/document.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/attributeelement.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/emptyelement.js","webpack://ClassicEditor/../ckeditor5-utils/src/env.js","webpack://ClassicEditor/../ckeditor5-utils/src/keyboard.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/uielement.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/rawelement.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/documentfragment.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/downcastwriter.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/istext.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/filler.js","webpack://ClassicEditor/../ckeditor5-utils/src/fastdiff.js","webpack://ClassicEditor/../ckeditor5-utils/src/diff.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/insertat.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/remove.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/isnode.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/renderer.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/global.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/indexof.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/getancestors.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/domconverter.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/getcommonancestor.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/iswindow.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/emittermixin.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/observer/observer.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_setCacheAdd.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_setCacheHas.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_SetCache.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_arraySome.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_cacheHas.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_equalArrays.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_mapToArray.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_setToArray.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_equalByTag.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_equalObjects.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseIsEqualDeep.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_baseIsEqual.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/isEqualWith.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/observer/mutationobserver.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/observer/domeventdata.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/observer/domeventobserver.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/observer/keyobserver.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/now.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/toNumber.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/debounce.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/observer/fakeselectionobserver.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/observer/selectionobserver.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/observer/focusobserver.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/observer/compositionobserver.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/observer/inputobserver.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/isrange.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/getborderwidths.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/rect.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/scroll.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/view.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/node.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/text.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/textproxy.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/nodelist.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/element.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/treewalker.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/position.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/range.js","webpack://ClassicEditor/../ckeditor5-engine/src/conversion/mapper.js","webpack://ClassicEditor/../ckeditor5-engine/src/conversion/modelconsumable.js","webpack://ClassicEditor/../ckeditor5-engine/src/conversion/downcastdispatcher.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/selection.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/liverange.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/documentselection.js","webpack://ClassicEditor/../ckeditor5-engine/src/conversion/conversionhelpers.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/cloneDeep.js","webpack://ClassicEditor/../ckeditor5-engine/src/conversion/downcasthelpers.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/utils/autoparagraphing.js","webpack://ClassicEditor/../ckeditor5-engine/src/conversion/upcasthelpers.js","webpack://ClassicEditor/../ckeditor5-engine/src/controller/editingcontroller.js","webpack://ClassicEditor/../ckeditor5-core/src/commandcollection.js","webpack://ClassicEditor/../ckeditor5-engine/src/conversion/viewconsumable.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/schema.js","webpack://ClassicEditor/../ckeditor5-engine/src/conversion/upcastdispatcher.js","webpack://ClassicEditor/../ckeditor5-engine/src/controller/datacontroller.js","webpack://ClassicEditor/../ckeditor5-engine/src/conversion/conversion.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/batch.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/operation/operation.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/documentfragment.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/operation/utils.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/isEqual.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/operation/attributeoperation.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/operation/detachoperation.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/operation/moveoperation.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/operation/insertoperation.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/operation/markeroperation.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/operation/renameoperation.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/operation/rootattributeoperation.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/operation/mergeoperation.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/operation/splitoperation.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/rootelement.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/writer.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/differ.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/history.js","webpack://ClassicEditor/../ckeditor5-utils/src/unicode.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/document.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/markercollection.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/operation/nooperation.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/operation/operationfactory.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/liveposition.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/utils/insertcontent.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/utils/deletecontent.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/utils/modifyselection.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/utils/getselectedcontent.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/utils/selection-post-fixer.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/model.js","webpack://ClassicEditor/../ckeditor5-utils/src/keystrokehandler.js","webpack://ClassicEditor/../ckeditor5-core/src/editingkeystrokehandler.js","webpack://ClassicEditor/../ckeditor5-core/src/editor/editor.js","webpack://ClassicEditor/../ckeditor5-core/src/editor/utils/dataapimixin.js","webpack://ClassicEditor/../ckeditor5-core/src/editor/utils/elementapimixin.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/setdatainelement.js","webpack://ClassicEditor/../ckeditor5-engine/src/dataprocessor/basichtmlwriter.js","webpack://ClassicEditor/../ckeditor5-engine/src/dataprocessor/htmldataprocessor.js","webpack://ClassicEditor/../ckeditor5-ui/src/componentfactory.js","webpack://ClassicEditor/../ckeditor5-utils/src/focustracker.js","webpack://ClassicEditor/../ckeditor5-core/src/editor/editorui.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/placeholder.js","webpack://ClassicEditor/../ckeditor5-utils/src/elementreplacer.js","webpack://ClassicEditor/../ckeditor5-editor-classic/src/classiceditorui.js","webpack://ClassicEditor/../ckeditor5-ui/src/toolbar/normalizetoolbarconfig.js","webpack://ClassicEditor/../ckeditor5-ui/src/toolbar/enabletoolbarkeyboardfocus.js","webpack://ClassicEditor/../ckeditor5-ui/src/viewcollection.js","webpack://ClassicEditor/../ckeditor5-ui/src/template.js","webpack://ClassicEditor/../ckeditor5-ui/src/view.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/isString.js","webpack://ClassicEditor/../ckeditor5-ui/src/editorui/bodycollection.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/createelement.js","webpack://ClassicEditor/../ckeditor5-ui/src/editorui/editoruiview.js","webpack://ClassicEditor/../ckeditor5-ui/src/label/labelview.js","webpack://ClassicEditor/../ckeditor5-ui/src/editorui/boxed/boxededitoruiview.js","webpack://ClassicEditor/../ckeditor5-ui/src/editableui/editableuiview.js","webpack://ClassicEditor/../ckeditor5-ui/src/editableui/inline/inlineeditableuiview.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/tounit.js","webpack://ClassicEditor/../ckeditor5-ui/src/panel/sticky/stickypanelview.js","webpack://ClassicEditor/../ckeditor5-ui/src/focuscycler.js","webpack://ClassicEditor/../ckeditor5-ui/src/toolbar/toolbarseparatorview.js","webpack://ClassicEditor/../ckeditor5-ui/src/toolbar/toolbarlinebreakview.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/resizeobserver.js","webpack://ClassicEditor/../ckeditor5-ui/src/dropdown/dropdownpanelview.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/position.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/getpositionedancestor.js","webpack://ClassicEditor/../ckeditor5-ui/src/dropdown/dropdownview.js","webpack://ClassicEditor/../ckeditor5-ui/src/icon/iconview.js","webpack://ClassicEditor/../ckeditor5-ui/src/tooltip/tooltipview.js","webpack://ClassicEditor/../ckeditor5-ui/src/button/buttonview.js","webpack://ClassicEditor/../ckeditor5-ui/theme/icons/dropdown-arrow.svg","webpack://ClassicEditor/../ckeditor5-ui/src/dropdown/button/dropdownbuttonview.js","webpack://ClassicEditor/../ckeditor5-ui/src/list/listview.js","webpack://ClassicEditor/../ckeditor5-ui/src/list/listitemview.js","webpack://ClassicEditor/../ckeditor5-ui/src/list/listseparatorview.js","webpack://ClassicEditor/../ckeditor5-ui/src/button/switchbuttonview.js","webpack://ClassicEditor/../ckeditor5-ui/src/bindings/clickoutsidehandler.js","webpack://ClassicEditor/../ckeditor5-ui/src/dropdown/utils.js","webpack://ClassicEditor/../ckeditor5-ui/src/toolbar/toolbarview.js","webpack://ClassicEditor/../ckeditor5-ui/src/bindings/preventdefault.js","webpack://ClassicEditor/../ckeditor5-core/theme/icons/three-vertical-dots.svg","webpack://ClassicEditor/../ckeditor5-editor-classic/src/classiceditoruiview.js","webpack://ClassicEditor/../ckeditor5-editor-classic/src/classiceditor.js","webpack://ClassicEditor/../ckeditor5-core/src/editor/utils/attachtoform.js","webpack://ClassicEditor/../ckeditor5-utils/src/dom/getdatafromelement.js","webpack://ClassicEditor/../ckeditor5-core/src/plugin.js","webpack://ClassicEditor/../ckeditor5-clipboard/src/datatransfer.js","webpack://ClassicEditor/../ckeditor5-clipboard/src/clipboardobserver.js","webpack://ClassicEditor/../ckeditor5-clipboard/src/pasteplaintext.js","webpack://ClassicEditor/../ckeditor5-clipboard/src/utils/viewtoplaintext.js","webpack://ClassicEditor/../ckeditor5-clipboard/src/clipboard.js","webpack://ClassicEditor/../ckeditor5-clipboard/src/utils/plaintexttohtml.js","webpack://ClassicEditor/../ckeditor5-clipboard/src/utils/normalizeclipboarddata.js","webpack://ClassicEditor/../ckeditor5-core/src/command.js","webpack://ClassicEditor/../ckeditor5-enter/src/utils.js","webpack://ClassicEditor/../ckeditor5-enter/src/entercommand.js","webpack://ClassicEditor/../ckeditor5-enter/src/enterobserver.js","webpack://ClassicEditor/../ckeditor5-enter/src/enter.js","webpack://ClassicEditor/../ckeditor5-enter/src/shiftentercommand.js","webpack://ClassicEditor/../ckeditor5-enter/src/shiftenter.js","webpack://ClassicEditor/../ckeditor5-select-all/src/selectallcommand.js","webpack://ClassicEditor/../ckeditor5-select-all/src/selectallediting.js","webpack://ClassicEditor/../ckeditor5-select-all/src/selectallui.js","webpack://ClassicEditor/../ckeditor5-select-all/theme/icons/select-all.svg","webpack://ClassicEditor/../ckeditor5-select-all/src/selectall.js","webpack://ClassicEditor/../ckeditor5-typing/src/utils/changebuffer.js","webpack://ClassicEditor/../ckeditor5-typing/src/inputcommand.js","webpack://ClassicEditor/../ckeditor5-typing/src/utils/injectunsafekeystrokeshandling.js","webpack://ClassicEditor/../ckeditor5-typing/src/utils/utils.js","webpack://ClassicEditor/../ckeditor5-utils/src/difftochanges.js","webpack://ClassicEditor/../ckeditor5-typing/src/utils/injecttypingmutationshandling.js","webpack://ClassicEditor/../ckeditor5-typing/src/input.js","webpack://ClassicEditor/../ckeditor5-typing/src/deletecommand.js","webpack://ClassicEditor/../ckeditor5-typing/src/deleteobserver.js","webpack://ClassicEditor/../ckeditor5-typing/src/delete.js","webpack://ClassicEditor/../ckeditor5-typing/src/typing.js","webpack://ClassicEditor/../ckeditor5-engine/src/model/operation/transform.js","webpack://ClassicEditor/../ckeditor5-undo/src/basecommand.js","webpack://ClassicEditor/../ckeditor5-undo/src/undocommand.js","webpack://ClassicEditor/../ckeditor5-undo/src/redocommand.js","webpack://ClassicEditor/../ckeditor5-undo/src/undoediting.js","webpack://ClassicEditor/../ckeditor5-undo/theme/icons/undo.svg","webpack://ClassicEditor/../ckeditor5-undo/theme/icons/redo.svg","webpack://ClassicEditor/../ckeditor5-undo/src/undoui.js","webpack://ClassicEditor/../ckeditor5-undo/src/undo.js","webpack://ClassicEditor/../ckeditor5-core/src/contextplugin.js","webpack://ClassicEditor/../ckeditor5-core/src/pendingactions.js","webpack://ClassicEditor/../ckeditor5-upload/src/filereader.js","webpack://ClassicEditor/../ckeditor5-upload/src/filerepository.js","webpack://ClassicEditor/../ckeditor5-adapter-ckfinder/src/utils.js","webpack://ClassicEditor/../ckeditor5-adapter-ckfinder/src/uploadadapter.js","webpack://ClassicEditor/../ckeditor5-utils/src/first.js","webpack://ClassicEditor/../ckeditor5-autoformat/src/blockautoformatediting.js","webpack://ClassicEditor/../ckeditor5-autoformat/src/inlineautoformatediting.js","webpack://ClassicEditor/../ckeditor5-autoformat/src/autoformat.js","webpack://ClassicEditor/../ckeditor5-basic-styles/src/attributecommand.js","webpack://ClassicEditor/../ckeditor5-basic-styles/src/bold/boldediting.js","webpack://ClassicEditor/../ckeditor5-basic-styles/src/bold/boldui.js","webpack://ClassicEditor/../ckeditor5-basic-styles/theme/icons/bold.svg","webpack://ClassicEditor/../ckeditor5-basic-styles/src/italic/italicediting.js","webpack://ClassicEditor/../ckeditor5-basic-styles/src/italic/italicui.js","webpack://ClassicEditor/../ckeditor5-basic-styles/theme/icons/italic.svg","webpack://ClassicEditor/../ckeditor5-block-quote/src/blockquotecommand.js","webpack://ClassicEditor/../ckeditor5-block-quote/src/blockquoteediting.js","webpack://ClassicEditor/../ckeditor5-block-quote/src/blockquoteui.js","webpack://ClassicEditor/../ckeditor5-core/theme/icons/quote.svg","webpack://ClassicEditor/../ckeditor5-ckfinder/src/ckfinderui.js","webpack://ClassicEditor/../ckeditor5-ckfinder/theme/icons/browse-files.svg","webpack://ClassicEditor/../ckeditor5-image/src/image/imageloadobserver.js","webpack://ClassicEditor/../ckeditor5-widget/src/highlightstack.js","webpack://ClassicEditor/../ckeditor5-ui/src/panel/balloon/balloonpanelview.js","webpack://ClassicEditor/../ckeditor5-widget/src/widgettypearound/utils.js","webpack://ClassicEditor/../ckeditor5-widget/src/utils.js","webpack://ClassicEditor/../ckeditor5-widget/theme/icons/drag-handle.svg","webpack://ClassicEditor/../ckeditor5-image/src/image/utils.js","webpack://ClassicEditor/../ckeditor5-image/src/image/converters.js","webpack://ClassicEditor/../ckeditor5-image/src/image/imageinsertcommand.js","webpack://ClassicEditor/../ckeditor5-image/src/image/imageediting.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/observer/mouseobserver.js","webpack://ClassicEditor/../ckeditor5-typing/src/twostepcaretmovement.js","webpack://ClassicEditor/../ckeditor5-typing/src/utils/findattributerange.js","webpack://ClassicEditor/../ckeditor5-link/src/utils/automaticdecorators.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_castSlice.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_hasUnicode.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_asciiToArray.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_unicodeToArray.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_stringToArray.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/_createCaseFirst.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/upperFirst.js","webpack://ClassicEditor/../ckeditor5-link/src/utils.js","webpack://ClassicEditor/../ckeditor5-link/src/linkcommand.js","webpack://ClassicEditor/../ckeditor5-link/src/unlinkcommand.js","webpack://ClassicEditor/../ckeditor5-link/src/utils/manualdecorator.js","webpack://ClassicEditor/../ckeditor5-link/src/linkediting.js","webpack://ClassicEditor/../ckeditor5-typing/src/utils/inlinehighlight.js","webpack://ClassicEditor/../ckeditor5-ui/src/notification/notification.js","webpack://ClassicEditor/../ckeditor5-ckfinder/src/ckfindercommand.js","webpack://ClassicEditor/../ckeditor5-ckfinder/src/ckfinderediting.js","webpack://ClassicEditor/../ckeditor-cloud-services-core/src/uploadgateway/fileuploader.js","webpack://ClassicEditor/../ckeditor-cloud-services-core/src/token/token.js","webpack://ClassicEditor/../ckeditor5-cloud-services/src/cloudservices.js","webpack://ClassicEditor/../ckeditor5-easy-image/src/cloudservicesuploadadapter.js","webpack://ClassicEditor/../ckeditor-cloud-services-core/src/uploadgateway/uploadgateway.js","webpack://ClassicEditor/../ckeditor5-widget/src/widgettypearound/widgettypearound.js","webpack://ClassicEditor/../ckeditor5-widget/theme/icons/return-arrow.svg","webpack://ClassicEditor/../ckeditor5-widget/src/verticalnavigation.js","webpack://ClassicEditor/../ckeditor5-widget/src/widget.js","webpack://ClassicEditor/../ckeditor5-image/src/imagetextalternative/imagetextalternativecommand.js","webpack://ClassicEditor/../ckeditor5-image/src/imagetextalternative/imagetextalternativeediting.js","webpack://ClassicEditor/../ckeditor5-ui/src/labeledfield/labeledfieldview.js","webpack://ClassicEditor/../ckeditor5-ui/src/inputtext/inputtextview.js","webpack://ClassicEditor/../ckeditor5-ui/src/labeledfield/utils.js","webpack://ClassicEditor/../ckeditor5-ui/src/bindings/injectcsstransitiondisabler.js","webpack://ClassicEditor/../ckeditor5-ui/src/bindings/submithandler.js","webpack://ClassicEditor/../ckeditor5-core/theme/icons/check.svg","webpack://ClassicEditor/../ckeditor5-core/theme/icons/cancel.svg","webpack://ClassicEditor/../ckeditor5-image/src/imagetextalternative/ui/textalternativeformview.js","webpack://ClassicEditor/../ckeditor5-ui/src/panel/balloon/contextualballoon.js","webpack://ClassicEditor/../ckeditor5-ui/theme/icons/previous-arrow.svg","webpack://ClassicEditor/../ckeditor5-ui/theme/icons/next-arrow.svg","webpack://ClassicEditor/../ckeditor5-image/src/image/ui/utils.js","webpack://ClassicEditor/../ckeditor5-image/src/imagetextalternative/imagetextalternativeui.js","webpack://ClassicEditor/../ckeditor5-core/theme/icons/low-vision.svg","webpack://ClassicEditor/../ckeditor5-image/src/imagetextalternative.js","webpack://ClassicEditor/../ckeditor5-image/src/image.js","webpack://ClassicEditor/../ckeditor5-upload/src/ui/filedialogbuttonview.js","webpack://ClassicEditor/../ckeditor5-image/src/imageupload/utils.js","webpack://ClassicEditor/../ckeditor5-image/src/imageupload/imageuploadui.js","webpack://ClassicEditor/../ckeditor5-core/theme/icons/image.svg","webpack://ClassicEditor/../ckeditor5-image/src/imageupload/imageuploadprogress.js","webpack://ClassicEditor/../ckeditor5-image/theme/icons/image_placeholder.svg","webpack://ClassicEditor/../ckeditor5-engine/src/view/upcastwriter.js","webpack://ClassicEditor/../ckeditor5-image/src/imageupload/imageuploadcommand.js","webpack://ClassicEditor/../ckeditor5-image/src/imageupload/imageuploadediting.js","webpack://ClassicEditor/../ckeditor5-image/src/imageupload.js","webpack://ClassicEditor/../ckeditor5-paragraph/src/paragraphcommand.js","webpack://ClassicEditor/../ckeditor5-paragraph/src/insertparagraphcommand.js","webpack://ClassicEditor/../ckeditor5-paragraph/src/paragraph.js","webpack://ClassicEditor/../ckeditor5-heading/src/headingcommand.js","webpack://ClassicEditor/../ckeditor5-heading/src/headingediting.js","webpack://ClassicEditor/../ckeditor5-ui/src/model.js","webpack://ClassicEditor/../ckeditor5-heading/src/headingui.js","webpack://ClassicEditor/../ckeditor5-heading/src/utils.js","webpack://ClassicEditor/../ckeditor5-image/src/imagecaption/utils.js","webpack://ClassicEditor/../ckeditor5-image/src/imagecaption/imagecaptionediting.js","webpack://ClassicEditor/../ckeditor5-image/src/imagestyle/imagestylecommand.js","webpack://ClassicEditor/../ckeditor5-image/src/imagestyle/converters.js","webpack://ClassicEditor/../ckeditor5-core/theme/icons/object-full-width.svg","webpack://ClassicEditor/../ckeditor5-core/theme/icons/object-left.svg","webpack://ClassicEditor/../ckeditor5-core/theme/icons/object-center.svg","webpack://ClassicEditor/../ckeditor5-core/theme/icons/object-right.svg","webpack://ClassicEditor/../ckeditor5-image/src/imagestyle/utils.js","webpack://ClassicEditor/../ckeditor5-image/src/imagestyle/imagestyleediting.js","webpack://ClassicEditor/../ckeditor5-image/src/imagestyle/imagestyleui.js","webpack://ClassicEditor/../ckeditor5-widget/src/widgettoolbarrepository.js","webpack://ClassicEditor/../ckeditor5-core/src/multicommand.js","webpack://ClassicEditor/../ckeditor5-indent/src/indentediting.js","webpack://ClassicEditor/../ckeditor5-indent/theme/icons/indent.svg","webpack://ClassicEditor/../ckeditor5-indent/theme/icons/outdent.svg","webpack://ClassicEditor/../ckeditor5-indent/src/indentui.js","webpack://ClassicEditor/../ckeditor5-engine/src/view/observer/clickobserver.js","webpack://ClassicEditor/../ckeditor5-link/src/ui/linkformview.js","webpack://ClassicEditor/../ckeditor5-link/src/ui/linkactionsview.js","webpack://ClassicEditor/../ckeditor5-link/theme/icons/unlink.svg","webpack://ClassicEditor/../ckeditor5-core/theme/icons/pencil.svg","webpack://ClassicEditor/../ckeditor5-link/src/linkui.js","webpack://ClassicEditor/../ckeditor5-link/theme/icons/link.svg","webpack://ClassicEditor/../ckeditor5-typing/src/utils/getlasttextline.js","webpack://ClassicEditor/../ckeditor5-typing/src/textwatcher.js","webpack://ClassicEditor/../ckeditor5-link/src/autolink.js","webpack://ClassicEditor/../ckeditor5-list/src/listcommand.js","webpack://ClassicEditor/../ckeditor5-list/src/indentcommand.js","webpack://ClassicEditor/../ckeditor5-list/src/utils.js","webpack://ClassicEditor/../ckeditor5-list/src/converters.js","webpack://ClassicEditor/../ckeditor5-list/src/listediting.js","webpack://ClassicEditor/../ckeditor5-list/src/listui.js","webpack://ClassicEditor/../ckeditor5-list/theme/icons/numberedlist.svg","webpack://ClassicEditor/../ckeditor5-list/theme/icons/bulletedlist.svg","webpack://ClassicEditor/../ckeditor5-media-embed/src/converters.js","webpack://ClassicEditor/../ckeditor5-media-embed/src/utils.js","webpack://ClassicEditor/../ckeditor5-media-embed/src/mediaembedcommand.js","webpack://ClassicEditor/../ckeditor5-media-embed/src/mediaregistry.js","webpack://ClassicEditor/../ckeditor5-media-embed/theme/icons/media-placeholder.svg","webpack://ClassicEditor/../ckeditor5-media-embed/src/mediaembedediting.js","webpack://ClassicEditor/../ckeditor5-media-embed/src/automediaembed.js","webpack://ClassicEditor/../ckeditor5-media-embed/src/ui/mediaformview.js","webpack://ClassicEditor/../ckeditor5-media-embed/src/mediaembedui.js","webpack://ClassicEditor/../ckeditor5-media-embed/theme/icons/media.svg","webpack://ClassicEditor/../ckeditor5-paste-from-office/src/filters/list.js","webpack://ClassicEditor/../ckeditor5-paste-from-office/src/normalizers/googledocsnormalizer.js","webpack://ClassicEditor/../ckeditor5-paste-from-office/src/filters/removeboldwrapper.js","webpack://ClassicEditor/../ckeditor5-paste-from-office/src/filters/space.js","webpack://ClassicEditor/../ckeditor5-paste-from-office/src/filters/parse.js","webpack://ClassicEditor/../ckeditor5-paste-from-office/src/filters/image.js","webpack://ClassicEditor/../ckeditor5-paste-from-office/src/normalizers/mswordnormalizer.js","webpack://ClassicEditor/../ckeditor5-table/src/utils/common.js","webpack://ClassicEditor/../ckeditor5-table/src/converters/upcasttable.js","webpack://ClassicEditor/../ckeditor5-table/src/tablewalker.js","webpack://ClassicEditor/../ckeditor5-table/src/converters/downcast.js","webpack://ClassicEditor/../ckeditor5-table/src/commands/inserttablecommand.js","webpack://ClassicEditor/../ckeditor5-table/src/utils/selection.js","webpack://ClassicEditor/../ckeditor5-table/src/commands/insertrowcommand.js","webpack://ClassicEditor/../ckeditor5-table/src/commands/insertcolumncommand.js","webpack://ClassicEditor/../ckeditor5-table/src/commands/splitcellcommand.js","webpack://ClassicEditor/../ckeditor5-table/src/utils/structure.js","webpack://ClassicEditor/../ckeditor5-table/src/commands/mergecellcommand.js","webpack://ClassicEditor/../ckeditor5-table/src/commands/removerowcommand.js","webpack://ClassicEditor/../ckeditor5-table/src/commands/removecolumncommand.js","webpack://ClassicEditor/../ckeditor5-table/src/commands/setheaderrowcommand.js","webpack://ClassicEditor/../ckeditor5-table/src/commands/setheadercolumncommand.js","webpack://ClassicEditor/../ckeditor5-table/src/tableutils.js","webpack://ClassicEditor/../ckeditor5-table/src/commands/mergecellscommand.js","webpack://ClassicEditor/../ckeditor5-table/src/commands/selectrowcommand.js","webpack://ClassicEditor/../ckeditor5-table/src/commands/selectcolumncommand.js","webpack://ClassicEditor/../ckeditor5-table/src/converters/table-layout-post-fixer.js","webpack://ClassicEditor/../ckeditor5-table/src/converters/table-cell-paragraph-post-fixer.js","webpack://ClassicEditor/../ckeditor5-table/src/converters/table-cell-refresh-post-fixer.js","webpack://ClassicEditor/../ckeditor5-table/src/converters/table-heading-rows-refresh-post-fixer.js","webpack://ClassicEditor/../ckeditor5-table/src/tableediting.js","webpack://ClassicEditor/../ckeditor5-ui/src/dropdown/button/splitbuttonview.js","webpack://ClassicEditor/../ckeditor5-table/src/ui/inserttableview.js","webpack://ClassicEditor/../ckeditor5-table/src/tableui.js","webpack://ClassicEditor/../ckeditor5-table/theme/icons/table.svg","webpack://ClassicEditor/../ckeditor5-table/theme/icons/table-column.svg","webpack://ClassicEditor/../ckeditor5-table/theme/icons/table-row.svg","webpack://ClassicEditor/../ckeditor5-table/theme/icons/table-merge-cell.svg","webpack://ClassicEditor/../ckeditor5-table/src/tableselection.js","webpack://ClassicEditor/../ckeditor5-table/src/tableclipboard.js","webpack://ClassicEditor/../ckeditor5-table/src/tablekeyboard.js","webpack://ClassicEditor/../ckeditor5-table/src/tablemouse/mouseeventsobserver.js","webpack://ClassicEditor/../ckeditor5-table/src/tablemouse.js","webpack://ClassicEditor/../ckeditor5-table/src/utils/ui/widget.js","webpack://ClassicEditor//Users/pomek/Projects/ckeditor/ckeditor5/node_modules/lodash-es/escapeRegExp.js","webpack://ClassicEditor/../ckeditor5-typing/src/texttransformation.js","webpack://ClassicEditor/./src/ckeditor.js","webpack://ClassicEditor/../ckeditor5-essentials/src/essentials.js","webpack://ClassicEditor/../ckeditor5-basic-styles/src/bold.js","webpack://ClassicEditor/../ckeditor5-basic-styles/src/italic.js","webpack://ClassicEditor/../ckeditor5-block-quote/src/blockquote.js","webpack://ClassicEditor/../ckeditor5-ckfinder/src/ckfinder.js","webpack://ClassicEditor/../ckeditor5-easy-image/src/easyimage.js","webpack://ClassicEditor/../ckeditor5-heading/src/heading.js","webpack://ClassicEditor/../ckeditor5-image/src/imagecaption.js","webpack://ClassicEditor/../ckeditor5-image/src/imagestyle.js","webpack://ClassicEditor/../ckeditor5-image/src/imagetoolbar.js","webpack://ClassicEditor/../ckeditor5-indent/src/indent.js","webpack://ClassicEditor/../ckeditor5-link/src/link.js","webpack://ClassicEditor/../ckeditor5-list/src/list.js","webpack://ClassicEditor/../ckeditor5-media-embed/src/mediaembed.js","webpack://ClassicEditor/../ckeditor5-paste-from-office/src/pastefromoffice.js","webpack://ClassicEditor/../ckeditor5-table/src/table.js","webpack://ClassicEditor/../ckeditor5-table/src/tabletoolbar.js"],"names":["root","factory","exports","module","define","amd","window","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","CKEditorError","Error","errorName","context","data","super","JSON","stringify","getLinkToDocumentationMessage","this","type","err","is","error","message","stack","logWarning","console","warn","formatConsoleArguments","logError","documentationMessage","memo","isOldIE","Boolean","document","all","atob","getTarget","target","styleTarget","querySelector","HTMLIFrameElement","contentDocument","head","e","stylesInDom","getIndexByIdentifier","identifier","result","length","modulesToDom","list","options","idCountMap","identifiers","item","id","base","count","concat","index","obj","css","media","sourceMap","references","updater","push","addStyle","insertStyleElement","style","createElement","attributes","nonce","keys","forEach","setAttribute","insert","appendChild","textStore","replaceText","replacement","filter","join","applyToSingletonTag","remove","styleSheet","cssText","cssNode","createTextNode","childNodes","removeChild","insertBefore","applyToTag","removeAttribute","btoa","unescape","encodeURIComponent","firstChild","singleton","singletonCounter","update","styleIndex","parentNode","removeStyleElement","newObj","lastIdentifiers","newList","toString","newLastIdentifiers","_i","_index","splice","freeSelf","self","Function","freeExports","nodeType","freeModule","Buffer","undefined","isBuffer","freeProcess","process","nodeUtil","types","require","binding","windowOrGlobal","global","CKEDITOR_VERSION","api","content","default","locals","freeGlobal","allocUnsafe","buffer","isDeep","slice","constructor","copy","originalModule","webpackPolyfill","children","g","objectProto","nativeObjectToString","symToStringTag","isOwn","tag","unmasked","func","transform","arg","getPrototypeOf","funcProto","funcToString","objectCtorString","proto","Ctor","__data__","size","other","array","Array","pop","ListCache","entries","clear","entry","set","has","uid","maskSrcKey","exec","IE_PROTO","reIsHostCtor","reIsNative","RegExp","replace","test","Hash","map","MapCache","pairs","LARGE_ARRAY_SIZE","Stack","iteratee","objValue","source","props","customizer","isNew","newValue","propertyIsEnumerable","arguments","isArray","reIsUint","typedArrayTags","nodeIsTypedArray","isTypedArray","inherited","isArr","isArg","isBuff","isType","skipIndexes","String","isProto","predicate","resIndex","nativeGetSymbols","getOwnPropertySymbols","symbol","values","offset","keysFunc","symbolsFunc","dataViewCtorString","mapCtorString","promiseCtorString","setCtorString","weakMapCtorString","getTag","ArrayBuffer","resolve","ctorString","input","Uint8Array","arrayBuffer","byteLength","dataView","byteOffset","reFlags","regexp","lastIndex","symbolProto","symbolValueOf","valueOf","typedArray","objectCreate","nodeIsMap","isMap","nodeIsSet","isSet","cloneableTags","baseClone","bitmask","isFlat","isFull","isFunc","stacked","subValue","add","keysIn","configurations","defaultConfigurations","_config","cloneConfig","_setObjectToTarget","_setToTarget","_getFromSource","isDefine","parts","split","part","configuration","leaveDOMReferences","spy","called","path","stop","off","HEX_NUMBERS","fill","val","r1","Math","random","r2","r3","r4","priority","normal","highest","high","low","lowest","_listeningTo","_emitterId","event","callback","listenTo","wasFired","args","stopListening","emitter","emitterInfo","eventCallbacks","emitters","_getEmitterId","_setEmitterId","emitterId","callbacks","eventName","events","getEvents","childEventName","newEventNodes","childEvents","substr","lastIndexOf","node","createEventNamespace","lists","getCallbacksListsForNamespace","callbackDefinition","added","removeCallback","indexOf","eventOrInfo","eventInfo","getCallbacksForEvent","_events","callbackArgs","from","apply","_delegations","destinations","passAllDestinations","fireDelegatedEvents","return","rethrowUnexpectedError","to","nameOrFunction","Map","delete","eventNode","callbacksLists","childCallbacksLists","fireArgs","delegatedInfo","fire","isIterable","iterator","mix","baseClass","mixins","mixin","getOwnPropertyNames","sourceDescriptor","getOwnPropertyDescriptor","initialItemsOrOptions","hasInitialItems","_items","_itemMap","_idProperty","idProperty","_bindToExternalToInternalMap","WeakMap","_bindToInternalToExternalMap","_skippedIndexesFromExternal","_getItemIdBeforeAdding","addMany","items","itemId","currentItemIndex","removed","idOrIndex","itemOrId","subject","_remove","ctx","find","_bindToCollection","removedItems","externalCollection","as","Class","_setUpBindToBinding","using","callbackOrProperty","addItem","evt","externalItem","isExternalBoundToThis","externalItemBound","finalIndex","skipped","getIndex","reduce","itemDoesNotExist","availablePlugins","contextPlugins","_context","_plugins","_availablePlugins","PluginConstructor","pluginName","_contextPlugins","pluginInstance","plugin","plugins","removePlugins","that","loading","Set","loaded","pluginConstructors","mapToAvailableConstructors","removePluginConstructors","missingPlugins","pluginNameOrConstructor","getPluginConstructor","getMissingPluginNames","errorId","Promise","reject","loadPlugin","then","initPlugins","includes","requires","RequiredPluginConstructorOrName","RequiredPluginConstructor","isContextPlugin","requiredBy","_add","instantiatePlugin","catch","loadedPlugins","method","promise","PluginConstructorOrName","promises","destroy","plugin1","plugin2","toArray","_translate","language","quantity","numberOfLanguages","CKEDITOR_TRANSLATIONS","messageId","string","dictionary","hasTranslation","plural","getPluralForm","pluralFormIndex","Number","RTL_LANGUAGE_CODES","uiLanguage","contentLanguage","uiLanguageDirection","getLanguageDirection","contentLanguageDirection","_t","match","interpolateString","languageCode","config","defaultConfig","builtinPlugins","languageConfig","locale","ui","editors","_contextOwner","Plugin","init","editor","isContextOwner","names","compareArrays","a","b","minLen","min","parent","pos","getChildIndex","getChild","unshift","includeSelf","parentFirst","ancestors","ancestorsA","getAncestors","ancestorsB","thisPath","getPath","nodePath","isBefore","_removeChildren","_fireChange","json","_textData","otherNode","textNode","offsetInText","substring","toMap","objectToMap","Matcher","pattern","_patterns","classes","element","singleElement","isElementMatching","results","matchName","patterns","hasAttribute","attribute","getAttribute","matchAttributes","getClassNames","hasClass","matchClasses","styles","hasStyle","getStyle","matchStyles","reIsDeepProp","reIsPlainProp","memoize","resolver","TypeError","memoized","cache","Cache","rePropName","reEscapeChar","charCodeAt","number","quote","subString","symbolToString","baseToString","start","end","defaultValue","fromRight","iterable","srcIndex","mergeFunc","srcValue","isCommon","isTyped","baseMerge","thisArg","nativeMax","max","otherArgs","nativeNow","Date","now","lastCalled","stamp","remaining","assigner","sources","guard","nested","styleProcessor","_styles","_styleProcessor","isEmpty","getStyleNames","inlineStyle","parsedStyles","stylesString","quoteType","propertyNameStart","propertyValueStart","propertyName","stylesMap","charAt","char","propertyValue","trim","parseInlineStyles","toNormalizedForm","propertyDescriptor","getReducedForm","nameOrObject","valueOrObject","toPath","_cleanEmptyObjectsOnPath","getNormalized","_getStylesEntries","arr","sort","parsed","pathParts","parentPath","parentObject","_normalizers","_extractors","_reducers","_consumables","appendStyleValue","normalizer","extractor","normalizedValue","reducer","callbackOrPath","shorthandName","styleNames","_mapStyleNames","alsoName","stylesObject","nameOrPath","valueToSet","attrs","_attrs","parseAttributes","_children","_insertChild","_classes","classString","parseClasses","stylesProcessor","setTo","_customProperties","otherElement","className","getAsString","matcher","deep","childrenClone","child","getChildren","_clone","cloned","getFillerOffset","childCount","nodes","normalize","howMany","classesSet","classesString","classArray","lastChild","observablePropertiesSymbol","boundObservablesSymbol","boundPropertiesSymbol","ObservableMixin","initObservable","properties","configurable","oldValue","bindProperties","isStringArray","boundProperties","bindings","bindTo","toMany","bindToMany","_observable","_bindProperties","_to","_bindings","unbindProperties","boundObservables","toObservable","toProperty","toProperties","toPropertyBindings","boundObservable","methodName","originalMethod","on","observable","parsedArgs","lastObservable","parseBindToArgs","bindingsKeys","numberOfBindings","updateBoundObservableProperty","chain","toPropertyName","bindingsToObservable","updateBoundObservables","updateBindToBound","observables","observableAndAttributePairs","getBindingTargets","every","isFocused","selection","editableElement","rootNameSymbol","rootName","getCustomProperty","_setCustomProperty","boundaries","startPosition","direction","position","_createAt","singleCharacters","shallow","ignoreElementEnd","_boundaryStartParent","_boundaryEndParent","skip","done","prevPosition","next","_next","_previous","clone","previousPosition","isAtEnd","_createAfter","_formatReturnValue","charactersCount","textLength","textProxy","isAtStart","_createBefore","startOffset","nextPosition","isEqual","endOffset","editable","shift","shifted","treeWalker","otherPosition","compareWith","otherPath","itemOrPosition","getLastMatchingPosition","enlargeTrimSkip","isAfter","nodeAfterStart","nodeAfter","nodeBeforeEnd","nodeBefore","otherRange","loose","isCollapsed","containsStart","containsPosition","containsEnd","ranges","isIntersecting","commonRangeStart","commonRangeEnd","getCommonAncestor","nextSibling","previousSibling","startElement","endElement","getShiftedBy","_createFromParentsAndOffsets","offsetSize","_createFromPositionAndShift","_","selectable","placeOrOffset","_ranges","_lastRangeBackward","_isFake","_fakeSelectionLabel","range","rangeCount","anchor","first","last","firstRange","getFirstRange","lastRange","getLastRange","otherSelection","isFake","fakeSelectionLabel","focus","thisRange","found","isBackward","numOfRangesA","getRanges","rangeA","getTrimmed","rangeB","getContainedElement","_setRanges","_setFakeOptions","fake","label","backward","_createIn","_createOn","newFocus","_addRange","newRanges","isLastBackward","_pushRange","storedRange","addedRange","intersectingRange","_selection","delegate","getFirstPosition","getLastPosition","getSelectedElement","isSimilar","setFocus","roots","_postFixers","postFixer","writer","wasFixed","_priority","_id","_clonesGroup","nonUiChildrenCount","DEFAULT_PRIORITY","userAgent","navigator","toLowerCase","isMac","isGecko","isSafari","isAndroid","isBlink","features","isRegExpUnicodePropertySupported","isSupported","search","macGlyphsToModifiers","modifiersToMacGlyphs","keyCodes","arrowleft","arrowup","arrowright","arrowdown","backspace","enter","space","esc","tab","ctrl","cmd","alt","code","letter","fromCharCode","generateKnownKeyCodes","getCode","keyCode","altKey","ctrlKey","shiftKey","parseKeystroke","keystroke","splitKeystrokeText","sum","getEnvKeystrokeText","isArrowKeyCode","getLocalizedArrowKeyCodeDirection","isLtrContent","isForwardArrowKeyCode","localizedKeyCodeDirection","domDocument","toDomElement","domElement","getAttributeKeys","injectUiElementHandling","view","domConverter","domSelection","domTarget","ownerDocument","defaultView","getSelection","domSelectionCollapsed","getRangeAt","collapsed","domParent","focusNode","domOffset","focusOffset","viewPosition","domPositionToView","jumpedOverAnyUiElement","nextViewPosition","newDomPosition","viewPositionToDom","collapse","extend","jumpOverUiElement","_cloneGroups","_setTo","_setFocus","attributeElement","_document","renderFunction","uiElement","render","rawElement","_setAttribute","_removeAttribute","_addClass","_removeClass","_setStyle","_removeStyle","_removeCustomProperty","positionOrRange","_breakAttributes","_breakAttributesRange","newElement","sourceRange","targetPosition","move","positionOffset","positionParent","_removeFromClonedElementsGroup","mergeAttributes","mergeTextNodes","_appendChild","prev","newPosition","validateNodesToInsert","errorContext","validNodesToInsert","some","validNode","container","getParentContainer","insertionPosition","_addToClonedElementsGroup","endPosition","rangeOrItem","validateRangeContainer","breakStart","breakEnd","parentContainer","mergePosition","walker","getWalker","current","rangeToRemove","parentElement","ancestor","countBefore","_wrapPosition","viewSelection","setSelection","_wrapRange","newRange","_unwrapChildren","newName","viewElement","getAttributes","groupName","wrapElement","wrapPositions","isText","isAttribute","isUI","isRaw","_wrapAttributeElement","shouldABeOutsideB","newAttribute","_wrapChildren","offsetChange","unwrapElement","unwrapPositions","unwrapped","_unwrapAttributeElement","movePositionToTextNode","breakTextNode","fakePosition","createAttributeElement","POSITIVE_INFINITY","wrapRange","wrap","wrapper","toWrap","canBeJoined","setStyle","addClass","toUnwrap","removeClass","removeStyle","forceSplitText","rangeStart","rangeEnd","isContainerOrFragment","offsetAfter","clonedNode","nodesToMove","group","getIdentity","textToMove","_data","t1","t2","nodeBeforeLength","startContainer","endContainer","NBSP_FILLER","BR_FILLER","fillerBr","dataset","ckeFiller","INLINE_FILLER","inlineFiller","startsWithFiller","domNode","isInlineFiller","domText","getDataWithoutFiller","jumpOverInlineFiller","fastDiff","cmp","atomicChanges","changeIndexes","arr1","arr2","firstIndex","findFirstDifferenceIndex","lastIndexOld","lastIndexNew","oldArrayReversed","cutAndReverse","newArrayReversed","findChangeBoundaryIndexes","newLength","changeIndexesToAtomicChanges","newArray","changeIndexesToChanges","reverse","aLength","bLength","_insert","_delete","tmp","delta","es","fp","snake","k","y1","y2","dir","y","x","nodeToInsert","isNode","Document","Node","domDocuments","markedAttributes","markedChildren","markedTexts","_inlineFiller","_fakeSelectionContainer","mapViewToDom","inlineFillerPosition","_updateChildrenMappings","_isSelectionInInlineFiller","_removeInlineFiller","_getInlineFillerPosition","_needsInlineFillerAtSelection","_updateAttrs","_updateChildren","_updateText","fillerDomPosition","addInlineFiller","_updateSelection","_updateFocus","actualDomChildren","expectedDomChildren","viewChildrenToDom","withChildren","diff","_diffNodeLists","actions","_findReplaceActions","counter","equal","action","insertIndex","deleteIndex","viewChild","_updateElementMappings","unbindDomElement","bindElements","firstPos","selectionPosition","domFillerNode","selectionParent","selectionOffset","findAncestor","isEditable","viewText","findCorrespondingDomText","newDomText","viewToDom","actualText","expectedText","filler","insertData","deleteData","domAttrKeys","attr","viewAttrKeys","nodesToUnbind","_markDescendantTextToSync","domToView","domChildList","fakeSelectionContainer","childList","filterOutFakeSelectionContainer","actualDom","expectedDom","newActions","actualSlice","expectedSlice","areSimilar","viewNode","_removeDomSelection","_removeFakeSelection","domRoot","_updateFakeSelection","_updateDomSelection","assign","top","left","width","textContent","createFakeSelectionContainer","bindFakeSelection","_fakeSelectionNeedsUpdate","domRange","createRange","removeAllRanges","selectNodeContents","addRange","_domSelectionNeedsUpdate","ELEMENT_NODE","childAtOffset","tagName","fixGeckoSelectionAfterBr","isDomSelectionCorrect","oldViewSelection","domSelectionToView","anchorNode","contains","doc","activeDomElement","activeElement","mapDomToView","domParentOrArray","nodeAfterFiller","fillerNode","node1","node2","COMMENT_NODE","actualDomChild","expectedDomChild","isBlockFiller","DOCUMENT_NODE","BR_FILLER_REF","blockFillerMode","preElements","blockElements","_blockFiller","_domToViewMapping","_viewToDomMapping","_fakeSelectionMapping","_rawContentElementMatcher","_encounteredRawContentDomNodes","WeakSet","viewDocumentSelection","domFragment","viewFragment","textData","_processDataFromViewText","createDocumentFragment","bindDocumentFragments","createElementNS","fillerPositionOffset","childView","viewRange","domStart","domEnd","setStart","setEnd","viewParent","domBefore","domAfter","hostElement","getHostViewElement","_processDataFromDomText","isComment","isDocumentFragment","viewName","keepOriginalCase","innerHTML","domChildrenToView","domChild","fakeSelectionToView","isDomSelectionBackward","viewRanges","domRangeToView","viewStart","viewEnd","findCorrespondingViewText","viewBefore","domElementOrDocumentFragment","isElement","documentFragmentOrElement","viewEditable","domEditable","scrollX","scrollY","scrollPositions","forEachDomNodeAncestor","scrollLeft","scrollTop","scrollTo","DOCUMENT_FRAGMENT_NODE","isEqualNode","hasBlockParent","isNbspBlockFiller","anchorOffset","detach","_isDomSelectionPositionCorrect","prevNode","_getTouchingViewTextNode","_nodeEndsWithSpace","nextNode","_hasDomParentOfType","_getTouchingInlineDomNode","shouldLeftTrim","_checkShouldLeftTrimDomText","shouldRightTrim","_checkShouldRightTrimDomText","Text","getNext","topmostParent","createTreeWalker","NodeFilter","SHOW_TEXT","SHOW_ELEMENT","acceptNode","FILTER_ACCEPT","FILTER_SKIP","currentNode","touchingNode","lca","nodeA","nodeB","boundaryParent","parents","isWindow","stringifiedObject","rest","proxy","_getProxyEmitter","attach","listeningEmitter","listenedToEmitterId","getNodeUID","_domNode","_domListeners","listenerOptions","capture","useCapture","passive","usePassive","domListener","_createDomListener","addEventListener","removeListener","domEvt","removeEventListener","Observer","isEnabled","disable","matches","SetCache","equalFunc","isPartial","arrLength","othLength","seen","arrValue","othValue","compared","othIndex","convert","objProps","objLength","skipCtor","objCtor","othCtor","objIsArr","othIsArr","objTag","othTag","objIsObj","othIsObj","isSameTag","objIsWrapped","othIsWrapped","objUnwrapped","othUnwrapped","baseIsEqual","characterData","characterDataOldValue","subtree","renderer","_renderer","_domElements","_mutationObserver","MutationObserver","_onMutations","takeRecords","observe","enable","disconnect","domMutations","mutatedTexts","mutatedElements","mutation","_isBogusBrMutation","text","oldText","newText","viewMutations","mutatedText","markToSync","viewChildren","newViewChildren","sameNodes","oldChildren","newChildren","viewSelectionAnchor","viewSelectionFocus","child1","child2","forceRender","addedNode","removedNodes","addedNodes","domEvent","additionalData","preventDefault","stopPropagation","domEventType","checkShouldIgnoreEventFromTarget","onDomEvent","eventType","metaKey","reTrim","reIsBadHex","reIsBinary","reIsOctal","freeParseInt","parseInt","isBinary","nativeMin","wait","lastArgs","lastThis","maxWait","timerId","lastCallTime","lastInvokeTime","leading","maxing","trailing","invokeFunc","time","leadingEdge","setTimeout","timerExpired","shouldInvoke","timeSinceLastCall","trailingEdge","timeWaiting","remainingWait","debounced","isInvoking","clearTimeout","cancel","flush","_fireSelectionChangeDoneDebounced","_handleSelectionMove","newSelection","oldSelection","mutationObserver","getObserver","_documents","_clearInfiniteLoopInterval","setInterval","_clearInfiniteLoop","_loopbackCounter","_handleSelectionChange","clearInterval","newViewSelection","hasDomSelection","_renderTimeoutId","selectedEditable","isComposing","isRange","getBorderWidths","getComputedStyle","borderTopWidth","right","borderRightWidth","bottom","borderBottomWidth","borderLeftWidth","rectProperties","isSourceRange","_source","writable","rangeRects","getDomRangeRects","copyRectProperties","getBoundingRect","getBoundingClientRect","innerWidth","innerHeight","height","anotherRect","rect","getIntersection","getArea","visibleRect","isBody","commonAncestorContainer","parentRect","intersectionRect","prop","intersectRect","scrollBarWidth","scrollBarHeight","documentElement","clientWidth","clientHeight","borderWidths","offsetWidth","offsetHeight","rects","clientRects","getClientRects","boundingRectData","NEGATIVE_INFINITY","rectangleCount","elementOrRange","body","scrollViewportToShowTarget","viewportOffset","targetWindow","getWindow","currentWindow","currentFrame","firstAncestorToScroll","getParentElement","scrollAncestorsToShowRect","getRectRelativeToWindow","targetRect","scrollWindowToShowRect","frameElement","targetShiftedDownRect","moveBy","targetShiftedUpRect","viewportRect","excludeScrollbarsAndBorders","isAbove","isBelow","isLeftOf","isRightOf","getRect","parentWindow","firstRect","secondRect","relativeWindow","frame","frameRect","scrollAncestorsToShowTarget","domRoots","_initialDomRootAttributes","_observers","_ongoingChange","_postFixersInProgress","_renderingDisabled","_hasChangedSinceTheLastRendering","_writer","addObserver","_render","viewRoot","getRoot","_name","initialDomRootAttributes","updateContenteditableAttribute","isReadOnly","change","observer","viewRangeToDom","isRenderingInProgress","callbackResult","_callPostFixers","flag","disableObservers","enableObservers","getChildStartOffset","toJSON","_nodes","_insertNodes","getNodeIndex","maxOffset","getNodeStartOffset","totalOffset","nodeList","indexStart","getNode","offsetToIndex","relativePath","parentName","_removeNodes","fromJSON","stickiness","_visitedParent","prevVisitedParent","textNodeAtPosition","getTextNodeAtPosition","getNodeAfterPosition","formatReturnValue","offsetInTextNode","getNodeBeforePosition","newOffset","diffAt","leftParent","getParentPath","operation","_getTransformedByInsertOperation","_getTransformedByMoveOperation","_getTransformedBySplitOperation","_getTransformedByMergeOperation","_getTransformedByInsertion","_getTransformedByMove","sourcePosition","movedRange","_getCombined","splitPosition","moveTargetPosition","graveyardPosition","_getTransformedByDeletion","deletionPosition","deletePosition","transformed","insertPosition","combined","graveyard","shouldJoin","isTouching","getCommonPath","posParent","operations","getTransformedByOperation","j","containsRange","spread","newPos","moveRange","differenceSet","getDifference","difference","common","transformedCommon","newStart","newEnd","ref","refIndex","_modelToViewMapping","_viewToModelMapping","_viewToModelLengthCallbacks","_markerNameToElements","_elementToMarkerNames","_unboundMarkerNames","viewContainer","modelPosition","findPositionIn","viewBlock","findMappedViewAncestor","modelParent","modelOffset","_toModelOffset","modelElement","toModelElement","markerName","toViewElement","elements","nameToElements","elementToNames","markerNames","toModelPosition","modelRange","toViewPosition","mapper","isPhantom","boundElements","getElementsWithSameId","viewElementName","lengthCallback","viewOffset","getModelLength","len","expectedOffset","lastLength","_moveViewPositionToTextNode","_consumable","_textProxyRegistry","_normalizeConsumableType","_getSymbolForTextProxy","itemConsumables","startMap","endMap","_addSymbolForTextProxy","conversionApi","dispatcher","_reconversionEventsMapping","differ","markers","getMarkersToRemove","convertMarkerRemove","changes","_mapChangesWithAutomaticReconversion","convertInsert","convertRemove","reconvertElement","convertAttribute","attributeKey","attributeOldValue","attributeNewValue","flushUnboundMarkerNames","markerRange","getRange","convertMarkerAdd","getMarkersToAdd","consumable","_createInsertConsumable","walkerValueToEventData","_convertInsertWithAttributes","_clearConversionApi","_createConsumableForRange","_testAndFire","elementRange","currentView","convertedViewElement","elementOrTextProxyToView","createRangeOn","unbindViewElement","markersAtSelection","getMarkersAtPosition","_createSelectionConsumable","marker","shouldMarkerChangeBeConverted","getItems","modelName","getEventName","itemsToReconvert","updated","getChanges","_isReconvertTriggerEvent","elementName","containsItem","anyNewRange","oldRange","_removeAllRanges","directChange","_popRange","attributeKeys","visited","startBlock","getParentBlock","isTopBlockInRange","block","isUnvisitedTopBlock","endBlock","limitStartPosition","limitEndPosition","_checkRange","isUnvisitedBlock","model","schema","isBlock","hasParentLimit","isLimit","parentBlock","findAncestorBlock","bindWithDocument","isDocumentOperation","_createFromRanges","boundariesChanged","contentChanged","doesOperationChangeRangeContent","toRange","hasOwnRange","isGravityOverridden","getSelectedBlocks","containsEntireContent","_updateMarkers","_updateAttributes","prefixOrName","observeMarkers","_getStoredAttributes","overrideGravity","restoreGravity","startsWith","_model","_attributePriority","_selectionRestorePosition","_hasChangedRange","_overriddenGravityRegister","_observedMarkers","_fixGraveyardSelection","_validateSelectionRange","_updateMarker","batch","changeParent","enqueueChange","storedAttributes","clearAttributesStoredInElement","_getDefaultRange","optionsOrPlaceOrOffset","overrideUid","liveRange","_prepareRange","fromRange","changed","markerGroup","selectionRange","oldMarkers","hasMarker","contained","clearAll","newAttributes","_getSurroundingAttributes","oldAttributes","_setAttributesTo","newKey","oldKey","realKey","getAttrsIfCharacter","isInline","isObject","getNearestSelectionRange","ConversionHelpers","dispatchers","_dispatchers","conversionHelper","normalizeToElementConfig","elementCreator","consume","converterPriority","triggerBy","_mapReconversionTriggerEvent","childName","downcastElementToElement","modelValue","getFromAttributeCreator","oldViewElement","newViewElement","viewWriter","toViewRange","unwrap","downcastAttributeToElement","normalizeToAttributeConfig","attributeCreator","oldAttribute","downcastAttributeToAttribute","isOpening","viewStartElement","viewEndElement","bindElementToMarker","markerNameToElements","unbindElementFromMarkerName","clearClonedElementsGroup","downcastMarkerToElement","highlightDescriptor","descriptor","prepareDescriptor","createViewElementFromHighlightDescriptor","rangeAfterWrap","highlightElement","viewHighlightElement","removeHighlight","downcastMarkerToHighlight","viewCreator","viewMarkerData","handleMarkerBoundary","viewData","removeMarkerFromAttribute","attributeName","removeMarkerData","downcastMarkerToData","isStart","checkChild","createUIElement","insertMarkerAsElement","insertMarkerAsAttribute","viewElementType","modelData","viewElementDefinition","createContainerElement","createViewElementFromDefinition","modelAttributeValue","autoParagraphEmptyRoots","getRootNames","insertElement","isParagraphable","nodeOrType","createContext","wrapInParagraph","paragraph","createPositionAt","upcastElementToElement","normalizeModelAttributeConfig","converter","prepareToAttributeConverter","getViewElementNameFromConfig","upcastElementToAttribute","viewKey","normalized","normalizeViewAttributeKeyValueConfig","upcastAttributeToAttribute","oldModel","normalizeElementToMarkerConfig","upcastElementToMarker","converterStart","prepareToElementConverter","normalizeDataToMarkerConfig","converterEnd","basePriority","maxPriority","priorityFactor","attrName","addMarkerElements","markerViewNames","markerViewName","modelCursor","convertChildren","viewItem","upcastAttributeToMarker","upcastDataToMarker","viewConfig","matcherResult","getModelElement","safeInsert","updateConversionResult","viewAttributeKeyToCopy","defaultModelValue","modelKey","configToTest","onlyViewNameIsDefined","modelAttribute","checkAttribute","setAttributeOn","configForElements","downcastDispatcher","_disableRendering","convertChanges","convertSelection","toModelRange","modelSelection","createSelection","convertSelectionChange","createText","modelEnd","createRangeIn","isAttached","brokenPosition","breakAttributes","_commands","commandName","command","execute","commands","ViewConsumable","consumables","elementConsumables","revert","instance","consumablesFromElement","createFrom","_canConsumeName","_test","_consume","_revert","getRelatedStyles","consumableName","toConsume","_sourceDefinitions","_attributeProperties","decorate","SchemaContext","getDefinition","itemName","definition","_clearCache","_compiledDefinitions","_compile","getDefinitions","def","isSelectable","isContent","_checkContextMatch","allowAttributes","positionOrBaseElement","elementToMerge","checkMerge","childDef","retValue","getAttributeProperties","selectionOrRangeOrPosition","rangeCommonAncestor","getMinimalFlatRanges","convertToMinimalFlatRanges","_getValidRangesForRange","backwardWalker","forwardWalker","limitElement","forward","step","combineWalkers","removeDisallowedAttributeFromNode","positionsInRange","getPositions","compiledDefinitions","sourceRules","itemNames","compileBaseItemRule","compileAllowContentOf","compileAllowWhere","compileAllowAttributesOf","compileInheritPropertiesFrom","cleanUpAllowIn","cleanUpAllowAttributes","contextItemIndex","contextItem","getItem","allowIn","parentRule","mapContextItem","query","getNames","endsWith","sourceItemRules","itemRule","allowContentOf","allowWhere","allowAttributesOf","inheritTypesFrom","sourceItemRule","typeNames","copyTypes","copyProperty","inheritFrom","inheritAllFrom","makeInheritAllWork","allowContentOfItemName","getAllowedChildren","allowedItem","allowWhereItemName","allowedIn","allowAttributeOfItem","inheritAttributes","inheritPropertiesOfItem","existingItems","itemToCheck","ctxItem","_splitParts","_cursorParents","_modelCursor","convertItem","_convertItem","_convertChildren","_safeInsert","_updateConversionResult","splitToAllowedParent","_splitToAllowedParent","getSplitParts","_getSplitParts","contextDefinition","append","createContextTree","store","documentFragment","_removeEmptyElements","modelItem","markerElements","markerElement","currentPosition","createPositionBefore","extractMarkersFromModelFragment","elementOrModelCursor","nextModelCursor","splitResult","createPositionAfter","savedCursorParent","allowedParent","findAllowedParent","treeWalkerValue","originalPart","splitPart","_registerSplitPair","cursorParent","anyRemoved","processor","upcastDispatcher","viewDocument","_viewWriter","_checkIfRootsExists","hasContent","ignoreWhitespaces","modelElementOrFragment","viewDocumentFragment","toView","toData","clearBindings","intersection","_getMarkersRelativeToElement","version","initialData","main","modelRoot","parse","newData","removeSelectionAttribute","toModel","viewElementOrFragment","rootNames","downcastDispatchers","upcastDispatchers","_helpers","_downcast","_createConversionHelpers","isDowncast","_upcast","alias","for","elementToElement","_getAllUpcastDefinitions","attributeToElement","elementToAttribute","attributeToAttribute","helpers","upcastAlso","_getUpcastDefinition","upcastAlsoItem","Batch","op","baseVersion","Operation","__className","_normalizeNodes","_splitNodeAtPosition","_mergeNodesAtIndex","_move","_haveSameAttributes","mergedNode","offsetDiff","firstPart","secondPart","iteratorA","iteratorB","newTargetPosition","getMovedRangeStart","sourceElement","targetElement","sourceOffset","targetOffset","shouldReceiveAttributes","gyPosition","originalNodes","affectsData","_markers","oldName","mergedElement","getInsertionPosition","splitElement","_assertWriterUsedCorrectly","isSameTree","addOperation","applyOperation","rangeRootPosition","usingOperation","updateMarker","addMarker","itemOrRange","setAttributeOnRange","setAttributeOnItem","removeAttributesFromItem","_addOperationForAffectedMarkers","flat","applyRemoveOperation","_merge","_mergeDetached","createPositionFromPath","merge","renameOperation","firstSplitElement","firstCopyElement","elementOrString","shiftedRange","applyMarkerOperation","_set","markerOrName","currentMarker","_refresh","hasUsingOperationDefined","affectsDataDefined","currentRange","updatedRange","managedUsingOperations","keyOrObjectOrIterable","_setSelectionAttribute","keyOrIterableOfKeys","_removeSelectionAttribute","_overrideGravity","_restoreGravity","storeKey","_getStoreAttributeKey","_currentWriter","isAffected","elementBefore","elementAfter","affectedInLeftElement","affectedInRightElement","affectedAfterLeftElement","affectedBeforeRightElement","valueBefore","valueAfter","lastSplitPosition","previousValue","rootA","rootB","markerCollection","_markerCollection","_changesInElement","_elementSnapshots","_changedMarkers","_changeCount","_cachedChanges","_cachedChangesWithGraveyard","_isInInsertedElement","_markRemove","_markInsert","getMarkersIntersectingRange","bufferMarkerChange","_markAttribute","sourceParentInserted","targetParentInserted","graveyardParent","mergedIntoElement","buffered","includeChangesInGraveyard","diffSet","snapshotChildren","elementChildren","_getChildrenSnapshot","_generateActionsFromChanges","_getInsertDiff","_getRemoveDiff","elementAttributes","snapshotAttributes","_getAttributesDiff","changeCount","prevDiff","thisDiff","isConsecutiveTextRemove","isConsecutiveTextAdd","isConsecutiveAttributeChange","_changesInGraveyardFilter","changeItem","_markChange","_removeAllNestedChanges","_makeSnapshot","_getChangesForElement","_handleChange","inc","nodesToHandle","old","incEnd","oldEnd","intersectionLength","howManyAfter","attributePart","diffs","snapshot","oldChildrenLength","oldChildrenHandled","repeat","posInGy","rangeInGy","History","_operations","_undoPairs","_undoneOperations","undoneOperation","undoingOperation","isInsideSurrogatePair","character","isLowSurrogateHalf","isInsideCombinedSymbol","history","_hasSelectionChangedFromTheLastChangeBlock","createRoot","bufferOperation","_hasDocumentChangedFromTheLastChangeBlock","refresh","hasDataChanges","reset","defaultRoot","_getDefaultRoot","validateTextNodePosition","rangeBoundary","oldMarker","hasChanged","_attachLiveRange","_managedUsingOperations","_affectsData","_destroyMarker","prefix","_detachLiveRange","_liveRange","stopDelegating","oldPosition","toPosition","canMergeWith","_filterAttributesOf","_affectedStart","_affectedEnd","parentContext","_handleNode","isFirst","isLast","removeDisallowedAttributes","nodeToSelect","_handleObject","_checkAndSplitToAllowedPosition","_mergeSiblingsOf","_handleDisallowedNode","_tryAutoparagraphing","handleNodes","livePos","fromPosition","_setAffectedBoundaries","mergeLeft","_canMergeLeft","mergeRight","_canMergeRight","mergePosLeft","mergePosRight","livePosition","_getAllowedIn","tempPos","deleteContent","selRange","doNotResetEntireContent","getLimitElement","shouldEntireContentBeReplacedWithParagraph","insertParagraph","replaceEntireContentWithParagraph","ignoreMarkers","modifySelection","getLivePositionsForSelectedBlocks","leaveUnmerged","checkShouldMerge","startAncestor","endAncestor","positionA","positionB","getAncestorsJustBelowCommonAncestor","mergeBranchesRight","commonAncestor","parentToRemove","rename","clearAttributes","setAttributes","fromEntries","mergeBranchesLeft","mergeBranches","collapseSelectionAt","doNotAutoparagraph","isTextAllowed","isParagraphAllowed","shouldAutoparagraph","leftPos","rightPos","rangeToCheck","isCrossingLimitElement","tryExtendingTo","isForward","unit","isAtWordBoundary","isAtNodeBoundary","boundaryChar","getCorrectWordBreakPosition","getCorrectPosition","getSearchRange","searchEnd","offsetToCheck","removeRangeContent","parentsToCheck","itemRange","parentToCheck","removeRange","injectSelectionPostFixer","registerPostFixer","correctedRange","tryFixingRange","nonIntersectingRanges","previousRange","merged","mergeIntersectingRanges","selectionPostFixer","originalPosition","nearestSelectionRange","fixedPosition","tryFixingCollapsedRange","isTextAllowedOnStart","isTextAllowedOnEnd","startLimitElement","endLimitElement","startIsOnBlock","endIsOnBlock","checkSelectionOnNonLimitElements","fixedStart","fixedEnd","isStartInLimit","isEndInLimit","bothInSameParent","expandStart","expandEnd","findOutermostLimitAncestor","tryFixingNonCollapsedRage","startingNode","isLimitNode","_pendingChanges","_validate","register","addChildCheck","childDefinition","_runPendingChanges","batchOrType","_execute","insertion","nodesToInsert","getSelectionRange","affectedRange","getAffectedRange","insertContent","setSelectionFocus","frag","commonPath","commonParent","getNodeByPath","flatSubtreeRange","appendText","cloneElement","leftExcessRange","getSelectedContent","rangeOrElement","intersectingMarker","ret","currentBatch","callbackReturnValue","_handleChangeBlock","_listener","keyEvtData","evtData","_addEditor","_getEditorConfig","once","state","editing","conversion","addAlias","keystrokes","extraPlugins","readyPromise","_removeEditor","el","HTMLTextAreaElement","BasicHtmlWriter","fragment","implementation","createHTMLDocument","_domParser","DOMParser","_domConverter","_htmlWriter","getHtml","_toDom","registerRawContentMatcher","parseFromString","_components","originalName","_elements","_nextEventLoopTimeout","_focus","_blur","focusedElement","componentFactory","focusTracker","_editableElementsMap","ckeditorInstance","editorUI","documentPlaceholders","enablePlaceholder","isDirectHost","updateDocumentPlaceholders","hidePlaceholder","placeholders","wasViewModified","updatePlaceholder","getChildPlaceholderHostSubstitute","isEmptyish","selectionAnchor","needsPlaceholder","showPlaceholder","ElementReplacer","_replacedElements","display","_toolbarConfig","_elementReplacer","replacementElement","editingView","editingRoot","setEditableElement","attachDomRoot","_initPlaceholder","_initToolbar","restore","detachDomRoot","stickyPanel","limiterElement","viewportTopOffset","toolbar","fillFromConfig","origin","originKeystrokeHandler","originFocusTracker","beforeFocus","afterBlur","enableToolbarKeyboardFocus","placeholderText","initialItems","_renderViewIntoCollectionParent","_parentElement","elementOrDocFragment","dest","evtName","isRendered","_isRendered","_revertData","_renderNode","intoFragment","isApplying","revertData","_revertTemplateFromNode","isView","isTemplate","eventNameOrFunctionOrAttribute","TemplateToBinding","eventNameOrFunction","if","valueIfTrue","TemplateIfBinding","template","extendTemplate","extendObjectValueArray","eventListeners","childIndex","isInvalid","_renderText","_renderElement","_renderAttributes","_renderElementChildren","_setUpListeners","hasTemplateBinding","_bindToObservable","getTextUpdater","attrValue","domAttrValue","attrNs","valueToBind","shouldExtend","getAttributeUpdater","_renderStyleAttribute","arrayValueReducer","isFalsy","setAttributeNS","styleName","styleValue","getStyleUpdater","isViewCollection","setParent","childRevertData","revertBindings","schemaItem","domEvtName","domSelector","activateDomEventListener","syncValueSchemaValue","templateBinding","activateAttributeListener","revertBinding","TemplateBinding","getValue","getValueSchemaValue","removeAttributeNS","normalizePlainTextDefinition","normalizeTextDefinition","listeners","arrayify","normalizeListeners","normalizeAttributes","cur","ext","_viewCollections","_unboundChildren","createCollection","collection","_bindTemplate","views","registerChild","getViews","_bodyCollectionContainer","class","namespace","xmlns","childElementCount","attachToDom","detachFromDom","bindTemplate","setTemplate","_voiceLabelView","_createVoiceLabel","role","lang","voiceLabel","_editableElement","_hasExternalElement","_editingView","_updateIsFocusedClasses","updateAfterRender","toUnit","toPx","_contentPanelPlaceholder","isSticky","_panelRect","_contentPanel","_hasViewportTopOffset","_isStickyToTheLimiter","limiterBottomOffset","marginLeft","_checkIfShouldBeSticky","panelRect","limiterRect","_limiterRect","isActive","_marginLeft","FocusCycler","keystrokeHandler","focusables","isFocusable","_getFocusableItem","viewIndex","focused","previous","collectionLength","_observerInstance","_createObserver","_element","_callback","_addElementCallback","_deleteElementCallback","_elementCallbacks","_getElementCallbacks","unobserve","ObserverConstructor","ResizeObserver","_previousRects","_periodicCheckTimeout","_checkElementRectsAndExecuteCallback","_startPeriodicCheck","_stopPeriodicCheck","periodicCheck","_hasRectChanged","contentRect","currentRect","previousRect","selectstart","focusLast","getOptimalPosition","positions","limiter","fitInViewport","positionedElementAncestor","offsetParent","getPositionedAncestor","elementRect","bestPositionRect","bestPositionName","bestPosition","elementRectArea","processedPositions","positionData","getPositionNameAndRect","positionName","positionRect","limiterIntersectArea","viewportIntersectArea","limiterViewportIntersectRect","getIntersectionArea","processedPosition","processPositionsToAreas","bestPositionData","getBestOfProcessedPositions","getBestPositionNameAndRect","getVisible","absoluteRectCoordinates","getAbsoluteRectCoordinates","ancestorPosition","ancestorBorderWidths","shiftRectCoordinatesDueToPositionedAncestor","moveTo","maxFitFactor","fitFactor","buttonView","panelView","isOpen","panelPosition","_getOptimalPosition","_panelPositions","closeDropdown","southEast","southWest","northEast","northWest","defaultPanelPositions","buttonRect","viewBox","_updateXMLContent","_colorFillPaths","svg","fillColor","querySelectorAll","ariaLabelUid","tooltipView","_createTooltipView","labelView","_createLabelView","iconView","keystrokeView","_createKeystrokeView","_getTooltipString","tabindex","isToggleable","mousedown","click","icon","withKeystroke","tooltip","arrowView","_createArrowView","_focusCycler","focusPrevious","focusNext","focusFirst","toggleSwitchView","_createToggleView","clickOutsideHandler","activator","contextElements","composedPath","contextElement","createDropdown","ButtonClass","dropdownView","closeDropdownOnBlur","closeDropdownOnExecute","focusDropdownContentsOnArrows","addDefaultBehavior","addListToDropdown","listView","listItemView","itemsView","shouldGroupWhenFull","isFloating","maxWidth","_behavior","StaticLayout","viewFocusables","viewItemsView","viewFocusTracker","viewLocale","ungroupedItems","groupedItems","groupedItemsDropdown","_createGroupedItemsDropdown","resizeObserver","cachedPadding","shouldUpdateGroupingOnNextResize","_updateFocusCycleableItems","changeData","removedItem","currentIndex","addedItem","_updateGrouping","_enableGroupingOnResize","_enableGroupingOnMaxWidthChange","initialGroupedItemsCount","wereItemsGrouped","_areItemsOverflowing","_groupLastItem","_ungroupFirstItem","lastChildRect","toolbarRect","computedStyle","paddingProperty","previousWidth","dropdown","buttons","toolbarView","addToolbarToDropdown","shouldToolbarGroupWhenFull","sourceElementOrData","updateSourceElement","form","originalSubmit","onSubmit","submit","attachToForm","getInitialData","_disableStack","forceDisable","DataTransfer","nativeDataTransfer","files","kind","getAsFile","getFiles","_native","getData","setData","handleInput","targetRanges","dropRange","dataTransfer","clipboardData","domDoc","clientX","clientY","caretRangeFromPoint","rangeParent","rangeOffset","getDropViewRange","shiftPressed","asPlainText","smallPaddingElements","modelDocument","onCopyCut","_htmlDataProcessor","fullMatch","spaces","scrollToTheSelection","dataController","modelFragment","isPlainTextFragment","textAttributes","isFormatting","viewToPlainText","childText","Command","forceDisabled","clearForceDisabled","getCopyOnEnterAttributes","allAttributes","copyOnEnter","isSelectionEmpty","attributesToCopy","splitBlock","setSelectionAttribute","isContainedWithinOneElement","enterBlock","splitPos","isSoft","insertBreak","softBreakAction","anchorPos","isInsideLimitElement","breakLineElement","createEmptyElement","scopeElement","isSelectAllScope","SELECT_ALL_KEYSTROKE","domEventData","ChangeBuffer","limit","isLocked","_changeCallback","_batch","_reset","_selectionChangeCallback","createBatch","ignoreLock","undoStepSize","_buffer","_batches","textInsertions","resultRange","lock","unlock","safeKeycodes","isNonTypingKeystroke","keyData","getSingleTextNodeChange","output","lastOperation","pushLast","isContinuationOf","expected","diffToChanges","compareChildNodes","oldChild","newChild","mutations","containerChildrenMutated","_handleContainerChildrenMutations","_handleTextMutation","_handleTextNodeInsertion","mutationsCommonAncestor","getMutationsContainer","domMutationCommonAncestor","freshDomConverter","modelFromCurrentDom","currentModel","modelFromDomChildren","currentModelChildren","lastDomChild","lastCurrentChild","isLastDomChildSoftBreak","isLastCurrentChildSoftBreak","isSafeForTextMutation","diffResult","firstChangeAt","insertions","deletions","calculateChanges","modelSelectionRange","insertText","viewPos","modelPos","insertedText","lastChangeAt","inputCommand","latestCompositionSelection","handleUnsafeKeystroke","isSelectionUnchanged","deleteSelectionContent","isFlatSelection","injectUnsafeKeystrokesHandling","handle","injectTypingMutationsHandling","_shouldEntireContentBeReplacedWithParagraph","sequence","_replaceEntireContentWithParagraph","limitElementFirstChild","fireViewDeleteEvent","originalEvent","hasWordModifier","inputType","selectionToRemove","deleteCommandParams","domSelectionAfterDeletion","transformations","setTransformation","OperationA","OperationB","transformationFunction","aGroup","noUpdateTransformation","getTransformation","transformSets","operationsA","operationsB","contextFactory","useRelations","forceWeakRemove","setOriginalOperations","originalOperations","nextTransformIndex","nextBaseVersionA","nextBaseVersionB","originalOperationsACount","originalOperationsBCount","opA","indexB","opB","newOpsA","getContext","newOpsB","updateRelation","newOpA","padWithNoOps","brokenOperationsACount","brokenOperationsBCount","updateBaseVersions","_history","_useRelations","_forceWeakRemove","_relations","takeFrom","originalOperation","_setRelation","affectedLeft","affectedRight","side","wasInLeftElement","wasStartBeforeMergedElement","wasEndBeforeMergedElement","wasInRightElement","aIsStrong","aWasUndone","_wasUndone","bWasUndone","abRelation","_getRelation","baRelation","originalOp","wasUndone","isUndoneOperation","origB","undoneB","getUndoneOperation","origA","relationsA","relation","_getComplementaryAttributeOperations","insertOperation","insertValue","_moveTargetIntoMovedRange","_makeMoveOperationsFromRanges","hasSameParentAs","moveOp","_breakRangeByMoveOperation","aNewRange","aToGraveyard","bToGraveyard","aIsWeak","removedRange","mergeInside","mergeSplittingElement","getReversed","aCompB","shouldSpread","rightRange","movesGraveyardElement","gyMoveSource","splitNodesMoveSource","gyMoveTarget","gyMove","splitNodesMoveTargetPath","splitNodesMoveTarget","splitNodesMove","extraRename","splitPath","additionalSplit","rangeToMove","gyElementMoved","newParentPosition","newTargetPath","howManyRemoved","aInGraveyard","bInGraveyard","newPositionPath","_stack","_createdBatches","clearStack","docSelection","selectionRanges","transformedRangeGroups","getTransformedByOperations","allRanges","rangeGroup","isRangeContainedByAnyOtherRange","normalizeRanges","batchToUndo","undoingBatch","operationsToUndo","operationToUndo","nextBaseVersion","historyOperations","getOperations","reversedOperations","setOperationAsUndone","joinedRange","getJoined","batchIndex","findIndex","_undo","_restoreSelection","redoingBatch","_batchRegistry","_undoCommand","_redoCommand","isRedoBatch","isUndoBatch","addBatch","undoneBatch","localizedUndoIcon","undo","redo","localizedRedoIcon","_addButton","Icon","ContextPlugin","_actions","hasAny","FileReader","reader","_reader","onprogress","file","total","onload","onerror","onabort","readAsDataURL","abort","loaders","_updatePendingAction","_loadersMap","_pendingAction","uploaded","fileOrPromise","createUploadAdapter","loader","aggregatedUploaded","aggregatedTotal","uploadTotal","fileOrPromiseOrLoader","getLoader","_destroy","pendingActions","getMessage","uploadedPercent","filePromise","uploadAdapterCreator","_filePromiseWrapper","_createFilePromiseWrapper","_adapter","status","read","upload","uploadResponse","isFulfilled","rejecter","getCsrfToken","token","cookie","pair","decodeURIComponent","getCookie","randValues","crypto","getRandomValues","toUpperCase","generateToken","url","_initRequest","_initListeners","_sendRequest","xhr","XMLHttpRequest","open","responseType","genericError","response","lengthComputable","FormData","send","iteratorItem","blockAutoformatEditing","callbackOrCommand","blockToFormat","firstNode","firstNodeRange","inlineAutoformatEditing","testRegexpOrCallback","formatCallback","regExp","testCallback","format","leftDel","rightDel","delStart","delEnd","rangeText","getTextAfterCode","testOutput","rangesToFormat","testOutputToRanges","rangesToRemove","arrays","getCallbackFunctionForInlineAutoformat","validRanges","getValidRanges","_getValueFromFirstAllowedNode","checkAttributeInSelection","forceValue","setAttributeProperties","fontWeight","_getValue","_checkEnabled","blocks","blocksToQuote","findQuote","checkCanBeQuoted","_applyQuote","_removeQuote","firstBlock","getRangesOfBlockGroups","groupRange","positionBefore","positionAfter","quotesToMerge","currentQuote","nextQuote","elementOrPosition","nextBlock","isBQAllowed","isBlockAllowedInBQ","button","_fireEvents","HighlightStack","oldTop","_insertDescriptor","newTop","compareDescriptors","oldDescriptor","newDescriptor","_removeDescriptor","shouldABeBeforeB","classesToString","defaultLimiterElement","isVisible","show","defaultPositions","positionOptions","southArrowNorth","southArrowNorthMiddleWest","southArrowNorthMiddleEast","southArrowNorthWest","southArrowNorthEast","northArrowSouth","northArrowSouthMiddleWest","northArrowSouthMiddleEast","northArrowSouthWest","northArrowSouthEast","optimalPosition","unpin","_pinWhenIsVisibleCallback","_startPinning","_stopPinning","hide","attachTo","getDomElement","scrollTarget","isWithinScrollTarget","isLimiterWithinScrollTarget","getNorthTop","balloonRect","arrowVerticalOffset","getSouthTop","arrowHorizontalOffset","northWestArrowSouthWest","northWestArrowSouthMiddleWest","northWestArrowSouth","northWestArrowSouthMiddleEast","northWestArrowSouthEast","northEastArrowSouthWest","northEastArrowSouthMiddleWest","northEastArrowSouth","northEastArrowSouthMiddleEast","northEastArrowSouthEast","southWestArrowNorthWest","southWestArrowNorthMiddleWest","southWestArrowNorth","southWestArrowNorthMiddleEast","southWestArrowNorthEast","southEastArrowNorthWest","southEastArrowNorthMiddleWest","southEastArrowNorth","southEastArrowNorthMiddleEast","southEastArrowNorthEast","isTypeAroundWidget","isWidget","getTypeAroundFakeCaretPosition","toWidget","setCustomProperty","labelOrCreator","setLabel","hasSelectionHandle","widgetElement","selectionHandle","addSelectionHandle","setHighlightHandling","getLabel","labelCreator","toWidgetEditable","findOptimalInsertionPosition","selectedElement","typeAroundFakeCaretPosition","centeredBalloonPositionForLongWidgets","widgetRect","viewportWidgetInsersectionRect","balloonTotalHeight","getSelectedImageWidget","isImageWidget","insertImage","imageElement","insertAtSelection","isImageAllowed","getInsertImageParent","isImageAllowedInParent","checkSelectionOnObject","isInOtherImage","getViewImgFromWidget","figureView","figureChildren","figureChild","modelToViewAttributeConverter","img","src","createImageViewElement","altText","toImageWidget","srcset","srcsetAttributeConverter","viewImage","modelImage","viewFigureToModel","emptyElement","figure","_overrideUid","arrowRightPressed","arrowLeftPressed","contentDirection","isMovementHandled","_handleForwardMovement","_handleBackwardMovement","_isNextGravityRestorationSkipped","_isGravityOverridden","isBetweenDifferentAttributes","hasAnyAttribute","preventCaretMovement","setSelectionAttributesFromTheNodeBefore","isStepAfterAnyAttributeBoundary","overrideSelectionGravity","restoreSelectionGravity","observedAttribute","attrBefore","findAttributeRange","_findBound","lookBack","lastNode","_definitions","viewFigure","linkInImage","reHasUnicode","rsAstral","rsCombo","rsFitz","rsNonAstral","rsRegional","rsSurrPair","reOptMod","rsSeq","rsSymbol","reUnicode","strSymbols","chr","ATTRIBUTE_WHITESPACES","SAFE_URL","EMAIL_REG_EXP","PROTOCOL_REG_EXP","createLinkElement","href","linkElement","ensureSafeUrl","isSafeUrl","addLinkProtocolIfApplicable","link","defaultProtocol","protocol","isProtocolNeeded","manualDecorators","automaticDecorators","manualDecorator","_getDecoratorStateFromModel","manualDecoratorIds","truthyManualDecorators","falsyManualDecorators","linkRange","allowedRanges","rangesToUpdate","_isRangeToUpdate","decoratorName","allowedRange","linkCommand","rangesToUnlink","ManualDecorator","EXTERNAL_LINKS_REGEXP","addTargetToExternalLinks","linkDecorators","decorators","localizedDecoratorsLabels","decorator","getLocalizedDecorators","retArray","normalizeDecorators","_enableAutomaticDecorators","_enableManualDecorators","registerAttribute","highlightedElements","inlineHighlight","_enableInsertContentSelectionAttributesFixer","_enableClickingAfterLink","_enableTypingOverLink","_handleDeleteContentAfterLink","automaticDecoratorDefinitions","rel","getDispatcher","manualDecoratorDefinitions","manualDecoratorName","removeLinkAttributesFromSelection","clicked","selectionAttributes","deletedContent","isTyping","firstPosition","lastPosition","nodeAtFirstPosition","nodeAtLastPosition","shouldCopyAttributes","shouldPreserveAttributes","hasBackspacePressed","linkHref","isInput","alert","_showNotification","title","imageCommand","openerMethod","chooseFiles","originalOnInit","onInit","finder","links","isImage","images","linkFile","getUrl","imagesUrls","image","request","insertImages","resizedUrl","notification","showWarning","CKFinder","urls","BASE64_HEADER_REG_EXP","fileOrData","apiAddress","_isBase64","base64","sliceSize","contentType","base64Data","byteArrays","byteNumbers","Blob","_base64ToBlob","_token","_apiAddress","_prepareRequest","_attachXHRListeners","setRequestHeader","onError","statusCode","xhrResponse","formData","DEFAULT_OPTIONS","autoRefresh","tokenUrlOrRefreshToken","initValue","_validateTokenValue","defaultRefreshToken","tokenUrl","_options","_registerRefreshTokenTimeout","refreshToken","_tokenRefreshTimeout","tokenValue","isString","isPlainString","isJWTFormat","tokenRefreshTimeoutTime","_getTokenRefreshTimeoutTime","binaryTokenPayload","exp","tokenExpireTime","floor","optionName","_tokens","Token","getTokenFor","cloudServices","uploadUrl","_uploadGateway","_UploadGateway","Adapter","uploadGateway","fileUploader","POSSIBLE_INSERTION_POSITIONS","RETURN_ARROW_ICON_ELEMENT","_currentFakeCaretModelElement","_enableTypeAroundUIInjection","_enableInsertingParagraphsOnButtonClick","_enableInsertingParagraphsOnEnterKeypress","_enableInsertingParagraphsOnTypingKeystroke","_enableTypeAroundFakeCaretActivationUsingKeyboardArrows","_enableDeleteIntegration","_enableInsertContentIntegration","widgetModelElement","selectedModelElement","_insertParagraph","buttonTitles","before","after","widgetViewElement","typeAroundWrapper","wrapperDomElement","buttonTemplate","importNode","injectButtons","caretTemplate","injectFakeCaret","injectUIIntoWidget","positionToWidgetCssClass","_listenToIfEnabled","_handleArrowKeyPress","selectedViewElement","shouldStopAndPreventDefault","_handleArrowKeyPressOnSelectedWidget","_handleArrowKeyPressWhenSelectionNextToAWidget","widgetPlugin","modelElementNextToSelection","_getObjectElementNextToSelection","_setSelectionOverElement","closest","buttonPosition","classList","getTypeAroundButtonPosition","widgetDomElement","getClosestWidgetViewElement","wasHandled","_insertParagraphAccordingToFakeCaretPosition","keyCodesHandledSomewhereElse","selectedModelWidget","isForwardDelete","probe","deepestEmptyRangeAncestor","deepestEmptyAncestor","getDeepestEmptyElementAncestor","documentSelection","verticalNavigationHandler","arrowUpPressed","arrowDownPressed","expandSelection","selectionWillShrink","getNearestNonInlineLimit","lastRangePosition","getNearestTextPosition","firstRangePosition","findTextRangeFromSelection","boundaryVerticalPosition","round","isSingleLineRange","walkerValueType","_previouslySelected","_clearPreviouslySelectedWidgets","lastMarked","isChild","_onMousedown","_handleSelectionChangeOnArrowKeyPress","_preventDefaultOnArrowKeyPress","_handleDelete","isInsideNestedEditable","detail","objectElement","objectElementNextToSelection","previousNode","nodeToRemove","widget","viewUid","statusUid","fieldView","statusView","_createStatusView","errorText","infoText","placeholder","readonly","_updateIsEmpty","_setDomElementValue","select","createLabeledInputText","labeledFieldView","inputView","ariaDescribedById","injectCssTransitionDisabler","disableCssTransitions","_isCssTransitionsDisabled","enableCssTransitions","submitHandler","labeledInput","_createLabeledInputView","saveButtonView","_createButton","check","cancelButtonView","_focusables","v","positionLimiter","_viewToStack","_idToStack","_rotatorView","_createRotatorView","_fakePanelsView","_createFakePanelsView","hasView","stackId","_numberOfStacks","_visibleStack","singleViewMode","showStack","_showView","_singleViewMode","visibleView","_showNextStack","hideView","_getStackId","pin","_getBalloonPosition","updatePosition","visibleStack","stacks","nextIndex","isSingleViewMode","numberOfStacks","buttonNextView","buttonPrevView","_showPrevStack","balloonClassName","withArrow","showView","_createButtonView","balloonPanelView","_balloonPanelView","_addPanels","_removePanels","deregisterChild","numberOfPanels","getBalloonPositionData","_createForm","_form","_showForm","_balloon","_hideForm","_isVisible","balloon","repositionContextualBalloon","_isInBalloon","focusEditable","_fileInputView","accept","multiple","createImageTypeRegExp","regExpSafeNames","imageTypes","imageTypesRegExp","acceptedType","allowMultipleFiles","imagesToUpload","uploadStatusChange","uploadId","fileRepository","_startAppearEffect","_showPlaceholder","_hidePlaceholder","progressBar","_createProgressBar","_showProgressBar","viewImg","_displayLocalImage","completeIcon","_showCompleteIcon","_removeUIElement","_hideProgressBar","_stopAppearEffect","_getUIElement","_createPlaceholder","imageFigure","uniqueProperty","removeChildren","oldElement","insertChild","uploadImage","createLoader","fetchableImages","isLocalImage","imageSrc","fetch","resource","blob","mimeType","getImageMimeType","File","fetchableImage","isInGraveyard","getImagesFromChangeItem","_readAndUpload","domFigure","originalDisplay","_ckHack","uploadStatus","_parseAndSetSrcsetAttributeOnImage","clean","destroyLoader","srcsetAttribute","isNaN","checkCanBecomeParagraph","paragraphLikeElements","modelElements","heading","checkCanBecomeHeading","option","_addDefaultH1Conversion","enterCommand","localizedTitles","Paragraph","getLocalizedOptions","defaultTitle","dropdownTooltip","titles","itemDefinitions","headingCommand","paragraphCommand","withText","commandValue","isOn","areEnabled","para","whichModel","getCaptionFromImage","imageModelElement","matchImageCaption","_insertMissingModelCaptionElement","captionModelToView","createCaptionForEditing","createEditableElement","captionElementCreator","_fixCaptionVisibility","_updateCaptionVisibility","lastCaption","_lastSelectedCaption","viewCaption","modelCaption","getParentCaption","hideCaptionIfEmpty","showCaption","viewModified","nodeFinder","imagesWithoutCaption","nestedItem","appendElement","captionElement","insertViewCaptionAndBind","caption","defaultStyle","isDefault","attributeValue","getStyleByName","defaultStyles","full","alignLeft","alignCenter","alignRight","defaultIcons","center","normalizeImageStyles","configuredStyles","_normalizeStyle","extendedStyle","modelToViewConverter","newStyle","oldStyle","modelToViewStyleAttribute","filteredStyles","viewFigureElement","modelImageElement","viewToModelStyleAttribute","translatedStyles","translateStyles","localizedDefaultStylesTitles","componentName","balloonToolbar","isWidgetSelected","_toolbarDefinitions","_updateToolbarsVisibility","toolbarConfig","toolbarId","ariaLabel","getRelatedElement","maxRelatedElementDepth","deepestRelatedElement","deepestToolbarDefinition","relatedElement","relatedElementDepth","_isToolbarVisible","_hideToolbar","_isToolbarInBalloon","_showToolbar","toolbarDefinition","_childCommands","_getFirstEnabledCommand","localizedIndentIcon","indent","outdent","localizedOutdentIcon","_defineButton","urlInputView","_createUrlInput","_manualDecoratorSwitches","_createManualDecoratorSwitches","_createFormChildren","accumulator","switchButton","switches","decoratorValue","additionalButtonsView","previewButtonView","_createPreviewButton","unlinkButtonView","editButtonView","actionsView","_createActionsView","formView","_createFormView","_createToolbarLinkButton","_enableUserBalloonInteractions","markerToHighlight","markerToElement","unlinkCommand","_addFormView","_hideUI","parsedUrl","getDecoratorSwitchesState","_closeFormView","_showUI","_getSelectedLinkElement","_areActionsVisible","_isUIVisible","_isUIInPanel","_areActionsInPanel","_getBalloonPositionData","_isFormInPanel","restoreManualDecoratorStates","_removeFormView","_hideFakeVisualSelection","forceVisible","_addActionsView","_showFakeVisualSelection","_startUpdatingUI","prevSelectedLink","prevSelectionParent","getSelectionParent","selectedLink","markerViewElements","targetLink","findLinkElementAncestor","startLink","endLink","nextValidRange","getNextValidRange","nextStartPath","nextStartPosition","nextRange","removeMarker","isLinkElement","getLastTextLine","hasMatch","_startListening","_evaluateTextBeforeSelection","suffix","rangeBeforeSelection","testResult","eventData","URL_REG_EXP","_enableTypingHandling","_enableEnterHandling","_enableShiftEnterHandling","watcher","isSingleSpaceAtTheEnd","getUrlAtTextEnd","linkEnd","linkStart","_applyAutoLink","_checkAndApplyAutoLinkOnRange","shiftEnterCommand","isLinkAllowedOnRange","checkCanBecomeListItem","turnOff","currentIndent","newIndent","listIndent","lowestIndent","_fixType","listType","listItem","startingItem","indentDirection","_indentBy","itemsToChange","lastItem","generateLiInUl","getListItemFillerOffset","createViewListItemElement","viewList","injectViewList","injectedItem","injectedList","refItem","getSiblingListItem","sameIndent","smallerIndent","prevItem","breakContainer","mappedViewAncestor","nestedList","findNestedList","positionAfterUiElements","prevView","breakPosition","mergeViewLists","nextViewList","lastSubChild","modelChild","firstList","secondList","mergeContainers","itemIndent","createUIComponent","hasOnlyLists","modelViewInsertion","modelViewChangeType","listName","modelViewMergeAfterChangeType","modelViewSplitOnInsert","removeStart","removeEnd","previousList","mergePos","modelViewMergeAfter","viewItemPrev","viewItemNext","viewModelConverter","getIndent","listItemModel","convertedChild","findNextListItem","viewToModelListItemChildrenConverter","cleanList","isList","cleanListItem","foundList","modelToViewPosition","topmostViewList","modelIndentPasteFixer","indentChange","hoistNestedLists","nextIndent","modelRemoveStartPosition","viewRemoveStartPosition","viewRemovedItem","prevModelItem","foo","prevIndent","prevViewList","itemToListHead","applied","_addListToFix","innerItem","listHead","_fixListIndents","_fixListTypes","maxIndent","fixBy","typesStack","modelChangePostFixer","registerViewToModelLength","getViewListItemLength","modelNode","modelLength","viewListPrev","modelViewChangeIndent","modelViewRemove","getCommandExecuter","registerChildCommand","modelToViewUrlAttributeConverter","registry","mediaContentElement","mediaViewElement","getMediaViewElement","createMediaFigureElement","getSelectedMediaModelWidget","insertMedia","mediaElement","selectedMedia","providers","extraProviders","removedProviders","removeProviders","providerDefinitions","provider","_getMedia","getViewElement","previewRenderer","html","subPattern","_getUrlMatches","rawUrl","_getValidUrl","_match","_previewRenderer","renderForEditingView","renderMediaPreview","mediaHtml","_getPreviewHtml","createRawElement","_getPlaceholderHtml","outerHTML","toMediaWidget","viewMedia","hasMedia","URL_REGEXP","_timeoutId","_positionToInsert","leftLivePosition","rightLivePosition","_embedMediaBetweenPositions","leftPosition","rightPosition","mediaRegistry","urlRange","validators","_validators","resetFormStatus","validator","_urlInputViewInfoDefault","inputField","_urlInputViewInfoTip","mediaURLInputValue","mediaForm","getFormValidators","_setUpDropdown","_setUpForm","closeUI","isValid","transformListItemLikeElementsIntoLists","itemLikeElements","itemLikeElementsMatcher","itemData","getListItemData","order","findAllItemLikeElements","currentList","currentIndentation","itemLikeElement","isDifferentList","previousItem","currentItem","isNewListNeeded","previousItemLikeElement","indentationDifference","listStyle","listLikeItem","listStyleRegexp","listStyleTypeRegex","listStyleMatch","listStyleType","listStyleTypeMatch","bulletedStyle","listMarkerElement","textNodeOrElement","findListMarkerNode","listMarker","findBulletedListStyle","mapListStyleDefinition","detectListStyle","lastListItem","lastListItemChild","insertNewEmptyList","differentIndentation","listElement","parentList","levelChange","findParentListAtLevel","bulletMatcher","removeBulletElement","transformElementIntoListItem","idMatch","orderMatch","indentMatch","googleDocsMatch","htmlString","removeBoldWrapper","unwrapParagraphInListItem","normalizeSafariSpaceSpans","parseHtml","domParser","normalizedHtml","normalizeSpacing","cleanContentAfterBody","htmlDocument","innerTextLength","innerText","normalizeSpacerunSpans","bodyString","bodyView","documentToView","styleTags","getElementsByTagName","sheet","cssRules","extractStyles","replaceImagesSourceWithBase64","rtfData","upcastWriter","shapesIds","imageElementsMatcher","imgs","shapes","shape","removeAllImgElementsRepresentingShapes","shapeElementsMatcher","prevSiblingName","findAllShapesIds","removeAllShapeElements","findAllImageElementsWithLocalSource","imageElements","imagesHexSources","newSrc","hexString","hex","replaceImagesFileSourceWithInlineRepresentation","regexPictureHeader","regexPicture","imageType","extractImageDataFromRtf","msWordMatch1","msWordMatch2","updateNumericAttribute","createEmptyTableCell","tableCell","isHeadingColumnCell","tableUtils","table","headingColumns","column","getCellLocation","upcastTable","viewTable","rows","headingRows","tableMeta","headRows","bodyRows","firstTheadElement","tableChild","trs","tr","headingCols","scanRowForHeadingColumns","scanTable","row","th","TableWalker","_table","_startRow","startRow","_endRow","endRow","_startColumn","startColumn","_endColumn","endColumn","_includeAllSlots","includeAllSlots","_skipRows","_row","_column","_cellIndex","_spannedCells","_nextCellAtColumn","_isOverEndRow","_isOverEndColumn","_advanceToNextRow","outValue","spanData","_getSpanned","_shouldSkipSlot","_formatOutValue","cell","colspan","rowspan","_recordSpans","anchorRow","anchorColumn","TableSlot","rowIsMarkedAsSkipped","rowIsBeforeStartRow","columnIsBeforeStartColumn","columnIsAfterEndColumn","rowMap","rowToUpdate","columnToUpdate","_markSpannedCell","tableWalker","cellAnchorRow","cellAnchorColumn","downcastInsertTable","asWidget","figureElement","tableElement","tableWidget","tableAttributes","viewRows","tableSlot","tableRow","trElement","createTr","createViewTableCellElement","rowIndex","convertParagraphInTableCell","isSingleParagraphWithoutAttributes","renameViewTableCellIfRequired","desiredCellElementName","getCellElementName","viewCell","renamedCell","renameViewTableCell","cellElementName","cellElement","isSingleParagraph","innerParagraph","tableSection","sectionName","viewTableSection","getExistingTableSectionElement","tableChildElement","createTableSection","getOrCreateTableSection","getSectionName","removeTableSectionIfEmpty","validParent","getInsertTableParent","createTable","getSelectedTableCells","cells","sortRanges","getTableCellsContainingSelection","cellWithSelection","getSelectionAffectedTableCells","selectedCells","getRowIndexes","tableCells","getFirstLastIndexesObject","getColumnIndexes","isSelectionRectangular","selectedTableCells","rowIndexes","areIndexesInSameSection","areCellInTheSameTableSection","columns","areaOfSelectedCells","rowsIndexes","columnIndexes","lastRow","firstRow","lastColumn","firstColumn","getBiggestRectangleArea","compareRangeOrder","indexes","allIndexesSorted","indexA","posA","posB","headingSectionSize","tableParent","insertAbove","affectedTableCells","insertRows","at","copyStructureFromAbove","insertColumns","isHorizontal","splitCellHorizontally","splitCellVertically","cropTableToDimensions","sourceTable","cropDimensions","croppedTable","cropHeight","tableMap","sourceRow","sourceColumn","isAnchor","rowInCroppedTable","tableCellCopy","trimTableCellIfNeeded","addHeadingsToCroppedTable","getVerticallyOverlappingCells","overlapRow","slotInfo","cellHeight","cellEndRow","splitHorizontally","splitRow","newRowspan","newCellAttributes","newCellRowSpan","columnIndex","newCell","getPositionBefore","getHorizontallyOverlappingCells","overlapColumn","cellsToSplit","cellWidth","cellEndColumn","splitVertically","splitColumn","newColspan","newCellColSpan","cellRow","cellColumn","limitRow","limitColumn","removeEmptyColumns","getColumns","columnsMap","emptyColumns","cellsCount","emptyColumn","removeColumns","removeEmptyRows","emptyRows","emptyRow","removeRows","removeEmptyRowsColumns","adjustLastRowIndex","dimensions","lastRowMap","rowspanAdjustment","adjustLastColumnIndex","lastColumnMap","colspanAdjustment","cellToMerge","_getMergeableCell","isMergeNext","cellToExpand","cellToRemove","removedTableCellRow","mergeTableCells","spanAttribute","cellSpan","cellToMergeSpan","horizontalCell","hasHeadingColumns","cellOnLeft","cellOnRight","leftCellColumn","rightCellColumn","leftCellSpan","isCellOnLeftInHeadingColumn","isCellOnRightInHeadingColumn","getHorizontalCell","isMergeWithBodyCell","isMergeWithHeadCell","currentCellRowSpan","rowOfCellToMerge","mergeColumn","cellToMergeData","getVerticalCell","span","firstCell","lastRowIndex","getRows","selectedRowIndexes","areAllRowsSelected","referenceCells","removedRowIndexes","columnIndexToFocus","rowsToRemove","cellToFocus","removedRowIndex","columnToFocus","getCellToFocus","tableColumnCount","lastCell","returnValue","getBoundaryCells","removedColumnIndexes","columnsToRemove","isInTable","_isInHeading","headingRowsToSet","currentHeadingRows","overlappingCells","headingColumnsToSet","createEmptyRows","insertAt","rowsToInsert","isCopyStructure","copyStructureFrom","walkerEndRow","tableIterator","rowColSpansMap","lastCellRow","isReferenceRow","cellIndex","abs","columnsToInsert","tableColumns","createCells","skipRow","cellsToMove","cellsToTrim","lastRowOfCell","rowSpanToSet","getCellsToMoveAndTrimOnRemoveRow","targetRowIndex","tableRowMap","previousCell","cellToMove","moveCellsToRow","updateHeadingRows","headingsRemoved","adjustHeadingColumns","removedColumnIndex","numberOfCells","newCellsSpan","updatedSpan","breakSpanEvenly","newCellsAttributes","cellsToInsert","splitCellColumn","cellsToUpdate","splitCellRow","isOnSameColumn","isInEvenlySplitRow","rowspanToSet","tableCellToInsert","firstTableCell","mergeWidth","mergeHeight","maxWidthOffset","maxHeightOffset","getMaxOffset","firstCellRow","firstCellColumn","getMergeDimensions","cellBeingMerged","targetCell","currentMaxOffset","which","dimensionValue","rangesToSelect","startLocation","endLocation","cellInfo","injectTableLayoutPostFixer","analyzedTables","isTableAttributeEntry","fixTableCellsRowspan","fixTableRowsSizes","tableLayoutPostFixer","maxRows","rowLimit","findCellsToTrim","rowsLengths","lengths","getRowsLengths","tableSize","maxColumns","isAttributeType","injectTableCellParagraphPostFixer","fixTable","fixTableRow","fixTableCellContent","checkTableCellChange","tableCellContentsPostFixer","textNodes","injectTableCellRefreshPostFixer","cellsToCheck","shouldRefresh","refreshItem","tableCellRefreshPostFixer","injectTableHeadingRowsRefreshPostFixer","tablesToRefresh","tableHeadingRowsRefreshPostFixer","getViewTable","oldColumns","newColumns","lastColumnToCheck","actionView","_createActionView","_createGridCollection","_highlightGridBoxes","boxView","boxes","isContentLtr","insertTableView","bindIsOn","_prepareDropdown","_prepareMergeSplitButtonDropdown","_fillDropdownWithListOptions","addListOption","_handleDeleteContent","_defineSelectionConverter","_enablePluginDisabling","adjustedLastRow","adjustedLastColumn","anchorCell","cellsToSelect","_getCellsToSelect","highlighted","previouslyHighlighted","clearHighlightedTableCells","lastViewCell","tableCellToSelect","rangeToSelect","selectionMap","walkerOptions","flipVertically","flipHorizontally","_onCopyCut","_onInsertContent","tableSelection","getSelectionAsFragment","pastedTable","contentRange","rangeBefore","rangeAfter","getTableIfOnlyTableInContent","pastedDimensions","selectedTable","shouldExpandSelection","expectedHeight","expectedWidth","tableWidth","tableHeight","expandTableSize","doVerticalSplit","doHorizontalSplit","splitCellsToRectangularSelection","prepareTableForPasting","selectionHeight","selectionWidth","_replaceSelectedCellsWithPasted","pastedWidth","pastedHeight","pastedTableLocationMap","createLocationMap","selectedTableMap","pastedRow","pastedColumn","pastedCell","cellToInsert","newTableCell","_replaceTableSlotCell","areHeadingRowsIntersectingSelection","areHeadingColumnsIntersectingSelection","newCells","limitColumns","isAffectedBySelection","limitRows","endIndex","_handleTabOnSelectedTable","_getTabHandler","_onKeydown","getFocusCell","currentRowIndex","currentCellIndex","isFirstCellInRow","isLastCellInRow","isLastRow","nextRow","previousRow","_handleArrowKeys","focusCell","_navigateFromCellInDirection","_isSelectionAtCellEdge","currentCellInfo","cellToSelect","getAnchorCell","setCellSelection","positionToSelect","_enableShiftClickSelection","_enableMouseDragSelection","blockSelectionChange","_getModelTableCellFromDomEvent","haveSameTableParent","beganCellSelection","newTargetCell","viewTargetElement","cellA","cellB","getSelectedTableWidget","isTableWidget","getTableWidgetAncestor","parentTable","positionOrElement","reHasRegExpChar","TRANSFORMATIONS","copyright","registeredTrademark","trademark","oneHalf","oneThird","twoThirds","oneForth","threeQuarters","lessThanOrEqual","greaterThanOrEqual","notEqual","arrowLeft","arrowRight","horizontalEllipsis","enDash","emDash","quotesPrimary","buildQuotesRegExp","quotesSecondary","quotesPrimaryEnGb","quotesSecondaryEnGb","quotesPrimaryPl","quotesSecondaryPl","TRANSFORMATION_GROUPS","symbols","mathematical","typography","quotes","DEFAULT_TRANSFORMATIONS","normalizeFrom","normalizeTo","getTextAttributesAfterPosition","quoteCharacter","_addListAutoformats","_addBasicStylesAutoformats","_addHeadingAutoformats","_addBlockQuoteAutoformats","_addCodeBlockAutoformats","boldCallback","italicCallback","codeCallback","strikethroughCallback","level","normalizers","isTransformedWithPasteFromOffice","activeNormalizer","widgetToolbarRepository","tableContentToolbarItems","tableToolbarItems","include","_enableTransformationWatchers","normalizedTransformations","extra","isNotRemoved","transformation","definitions","definedTransformations","transformationOrGroup","expandGroupsAndRemoveDuplicates","normalizeTransformations","normalizedTransformation","replaces","matchedRange","changeIndex","replaceWith","replacePosition","replaceRange","contentToolbar"],"mappings":";;;;wqGAAA,SAA2CA,EAAMC,GAC1B,iBAAZC,SAA0C,iBAAXC,OACxCA,OAAOD,QAAUD,IACQ,mBAAXG,QAAyBA,OAAOC,IAC9CD,OAAO,GAAIH,GACe,iBAAZC,QACdA,QAAuB,cAAID,IAE3BD,EAAoB,cAAIC,IAR1B,CASGK,QAAQ,WACX,O,YCTE,IAAIC,EAAmB,GAGvB,SAASC,EAAoBC,GAG5B,GAAGF,EAAiBE,GACnB,OAAOF,EAAiBE,GAAUP,QAGnC,IAAIC,EAASI,EAAiBE,GAAY,CACzCC,EAAGD,EACHE,GAAG,EACHT,QAAS,IAUV,OANAU,EAAQH,GAAUI,KAAKV,EAAOD,QAASC,EAAQA,EAAOD,QAASM,GAG/DL,EAAOQ,GAAI,EAGJR,EAAOD,QA0Df,OArDAM,EAAoBM,EAAIF,EAGxBJ,EAAoBO,EAAIR,EAGxBC,EAAoBQ,EAAI,SAASd,EAASe,EAAMC,GAC3CV,EAAoBW,EAAEjB,EAASe,IAClCG,OAAOC,eAAenB,EAASe,EAAM,CAAEK,YAAY,EAAMC,IAAKL,KAKhEV,EAAoBgB,EAAI,SAAStB,GACX,oBAAXuB,QAA0BA,OAAOC,aAC1CN,OAAOC,eAAenB,EAASuB,OAAOC,YAAa,CAAEC,MAAO,WAE7DP,OAAOC,eAAenB,EAAS,aAAc,CAAEyB,OAAO,KAQvDnB,EAAoBoB,EAAI,SAASD,EAAOE,GAEvC,GADU,EAAPA,IAAUF,EAAQnB,EAAoBmB,IAC/B,EAAPE,EAAU,OAAOF,EACpB,GAAW,EAAPE,GAA8B,iBAAVF,GAAsBA,GAASA,EAAMG,WAAY,OAAOH,EAChF,IAAII,EAAKX,OAAOY,OAAO,MAGvB,GAFAxB,EAAoBgB,EAAEO,GACtBX,OAAOC,eAAeU,EAAI,UAAW,CAAET,YAAY,EAAMK,MAAOA,IACtD,EAAPE,GAA4B,iBAATF,EAAmB,IAAI,IAAIM,KAAON,EAAOnB,EAAoBQ,EAAEe,EAAIE,EAAK,SAASA,GAAO,OAAON,EAAMM,IAAQC,KAAK,KAAMD,IAC9I,OAAOF,GAIRvB,EAAoB2B,EAAI,SAAShC,GAChC,IAAIe,EAASf,GAAUA,EAAO2B,WAC7B,WAAwB,OAAO3B,EAAgB,SAC/C,WAA8B,OAAOA,GAEtC,OADAK,EAAoBQ,EAAEE,EAAQ,IAAKA,GAC5BA,GAIRV,EAAoBW,EAAI,SAASiB,EAAQC,GAAY,OAAOjB,OAAOkB,UAAUC,eAAe1B,KAAKuB,EAAQC,IAGzG7B,EAAoBgC,EAAI,GAIjBhC,EAAoBA,EAAoBiC,EAAI,I,+BClFrD,sGA6Ce,MAAMC,UAAsBC,MAe1C,YAAaC,EAAWC,EAASC,GAGhCC,MAFgB,GAAIH,IAAgBE,EAAO,IAAKE,KAAKC,UAAWH,GAAY,KAASI,EAA+BN,MAOpHO,KAAKlC,KAAO,gBAOZkC,KAAKN,QAAUA,EAOfM,KAAKL,KAAOA,EAMb,GAAIM,GACH,MAAgB,kBAATA,EAaR,8BAA+BC,EAAKR,GACnC,GAAKQ,EAAIC,IAAMD,EAAIC,GAAI,iBACtB,MAAMD,EAYP,MAAME,EAAQ,IAAIb,EAAeW,EAAIG,QAASX,GAM9C,MAFAU,EAAME,MAAQJ,EAAII,MAEZF,GAwBD,SAASG,EAAYd,EAAWE,GACtCa,QAAQC,QAASC,EAAwBjB,EAAWE,IAwB9C,SAASgB,EAAUlB,EAAWE,GACpCa,QAAQJ,SAAUM,EAAwBjB,EAAWE,IAGtD,SAASI,EAA+BN,GACvC,MAAO,2GAA8CA,EAGtD,SAASiB,EAAwBjB,EAAWE,GAC3C,MAAMiB,EAAuBb,EAA+BN,GAE5D,OAAOE,EAAO,CAAEF,EAAWE,EAAMiB,GAAyB,CAAEnB,EAAWmB,K,6BCpLxE,IACMC,EADFC,EAEK,WAUL,YAToB,IAATD,IAMTA,EAAOE,QAAQ5D,QAAU6D,UAAYA,SAASC,MAAQ9D,OAAO+D,OAGxDL,GAIPM,EAAY,WACd,IAAIN,EAAO,GACX,OAAO,SAAkBO,GACvB,QAA4B,IAAjBP,EAAKO,GAAyB,CACvC,IAAIC,EAAcL,SAASM,cAAcF,GAEzC,GAAIjE,OAAOoE,mBAAqBF,aAAuBlE,OAAOoE,kBAC5D,IAGEF,EAAcA,EAAYG,gBAAgBC,KAC1C,MAAOC,GAEPL,EAAc,KAIlBR,EAAKO,GAAUC,EAGjB,OAAOR,EAAKO,IApBA,GAwBZO,EAAc,GAElB,SAASC,EAAqBC,GAG5B,IAFA,IAAIC,GAAU,EAELvE,EAAI,EAAGA,EAAIoE,EAAYI,OAAQxE,IACtC,GAAIoE,EAAYpE,GAAGsE,aAAeA,EAAY,CAC5CC,EAASvE,EACT,MAIJ,OAAOuE,EAGT,SAASE,EAAaC,EAAMC,GAI1B,IAHA,IAAIC,EAAa,GACbC,EAAc,GAET7E,EAAI,EAAGA,EAAI0E,EAAKF,OAAQxE,IAAK,CACpC,IAAI8E,EAAOJ,EAAK1E,GACZ+E,EAAKJ,EAAQK,KAAOF,EAAK,GAAKH,EAAQK,KAAOF,EAAK,GAClDG,EAAQL,EAAWG,IAAO,EAC1BT,EAAa,GAAGY,OAAOH,EAAI,KAAKG,OAAOD,GAC3CL,EAAWG,GAAME,EAAQ,EACzB,IAAIE,EAAQd,EAAqBC,GAC7Bc,EAAM,CACRC,IAAKP,EAAK,GACVQ,MAAOR,EAAK,GACZS,UAAWT,EAAK,KAGH,IAAXK,GACFf,EAAYe,GAAOK,aACnBpB,EAAYe,GAAOM,QAAQL,IAE3BhB,EAAYsB,KAAK,CACfpB,WAAYA,EACZmB,QAASE,EAASP,EAAKT,GACvBa,WAAY,IAIhBX,EAAYa,KAAKpB,GAGnB,OAAOO,EAGT,SAASe,EAAmBjB,GAC1B,IAAIkB,EAAQpC,SAASqC,cAAc,SAC/BC,EAAapB,EAAQoB,YAAc,GAEvC,QAAgC,IAArBA,EAAWC,MAAuB,CAC3C,IAAIA,EAAmD,KAEnDA,IACFD,EAAWC,MAAQA,GAQvB,GAJAtF,OAAOuF,KAAKF,GAAYG,SAAQ,SAAU3E,GACxCsE,EAAMM,aAAa5E,EAAKwE,EAAWxE,OAGP,mBAAnBoD,EAAQyB,OACjBzB,EAAQyB,OAAOP,OACV,CACL,IAAIhC,EAASD,EAAUe,EAAQyB,QAAU,QAEzC,IAAKvC,EACH,MAAM,IAAI5B,MAAM,2GAGlB4B,EAAOwC,YAAYR,GAGrB,OAAOA,EAcT,IACMS,EADFC,GACED,EAAY,GACT,SAAiBnB,EAAOqB,GAE7B,OADAF,EAAUnB,GAASqB,EACZF,EAAUG,OAAOjD,SAASkD,KAAK,QAI1C,SAASC,EAAoBd,EAAOV,EAAOyB,EAAQxB,GACjD,IAAIC,EAAMuB,EAAS,GAAKxB,EAAIE,MAAQ,UAAUJ,OAAOE,EAAIE,MAAO,MAAMJ,OAAOE,EAAIC,IAAK,KAAOD,EAAIC,IAIjG,GAAIQ,EAAMgB,WACRhB,EAAMgB,WAAWC,QAAUP,EAAYpB,EAAOE,OACzC,CACL,IAAI0B,EAAUtD,SAASuD,eAAe3B,GAClC4B,EAAapB,EAAMoB,WAEnBA,EAAW9B,IACbU,EAAMqB,YAAYD,EAAW9B,IAG3B8B,EAAWzC,OACbqB,EAAMsB,aAAaJ,EAASE,EAAW9B,IAEvCU,EAAMQ,YAAYU,IAKxB,SAASK,EAAWvB,EAAOlB,EAASS,GAClC,IAAIC,EAAMD,EAAIC,IACVC,EAAQF,EAAIE,MACZC,EAAYH,EAAIG,UAepB,GAbID,EACFO,EAAMM,aAAa,QAASb,GAE5BO,EAAMwB,gBAAgB,SAGpB9B,GAA6B,oBAAT+B,OACtBjC,GAAO,uDAAuDH,OAAOoC,KAAKC,SAASC,mBAAmBlF,KAAKC,UAAUgD,MAAe,QAMlIM,EAAMgB,WACRhB,EAAMgB,WAAWC,QAAUzB,MACtB,CACL,KAAOQ,EAAM4B,YACX5B,EAAMqB,YAAYrB,EAAM4B,YAG1B5B,EAAMQ,YAAY5C,SAASuD,eAAe3B,KAI9C,IAAIqC,EAAY,KACZC,EAAmB,EAEvB,SAAShC,EAASP,EAAKT,GACrB,IAAIkB,EACA+B,EACAhB,EAEJ,GAAIjC,EAAQ+C,UAAW,CACrB,IAAIG,EAAaF,IACjB9B,EAAQ6B,IAAcA,EAAY9B,EAAmBjB,IACrDiD,EAASjB,EAAoBnF,KAAK,KAAMqE,EAAOgC,GAAY,GAC3DjB,EAASD,EAAoBnF,KAAK,KAAMqE,EAAOgC,GAAY,QAE3DhC,EAAQD,EAAmBjB,GAC3BiD,EAASR,EAAW5F,KAAK,KAAMqE,EAAOlB,GAEtCiC,EAAS,YAxFb,SAA4Bf,GAE1B,GAAyB,OAArBA,EAAMiC,WACR,OAAO,EAGTjC,EAAMiC,WAAWZ,YAAYrB,GAmFzBkC,CAAmBlC,IAKvB,OADA+B,EAAOxC,GACA,SAAqB4C,GAC1B,GAAIA,EAAQ,CACV,GAAIA,EAAO3C,MAAQD,EAAIC,KAAO2C,EAAO1C,QAAUF,EAAIE,OAAS0C,EAAOzC,YAAcH,EAAIG,UACnF,OAGFqC,EAAOxC,EAAM4C,QAEbpB,KAKNnH,EAAOD,QAAU,SAAUkF,EAAMC,IAC/BA,EAAUA,GAAW,IAGR+C,WAA0C,kBAAtB/C,EAAQ+C,YACvC/C,EAAQ+C,UAAYnE,KAItB,IAAI0E,EAAkBxD,EADtBC,EAAOA,GAAQ,GAC0BC,GACzC,OAAO,SAAgBuD,GAGrB,GAFAA,EAAUA,GAAW,GAE2B,mBAA5CxH,OAAOkB,UAAUuG,SAAShI,KAAK+H,GAAnC,CAIA,IAAK,IAAIlI,EAAI,EAAGA,EAAIiI,EAAgBzD,OAAQxE,IAAK,CAC/C,IACImF,EAAQd,EADK4D,EAAgBjI,IAEjCoE,EAAYe,GAAOK,aAKrB,IAFA,IAAI4C,EAAqB3D,EAAayD,EAASvD,GAEtC0D,EAAK,EAAGA,EAAKJ,EAAgBzD,OAAQ6D,IAAM,CAClD,IAEIC,EAASjE,EAFK4D,EAAgBI,IAIK,IAAnCjE,EAAYkE,GAAQ9C,aACtBpB,EAAYkE,GAAQ7C,UAEpBrB,EAAYmE,OAAOD,EAAQ,IAI/BL,EAAkBG,M,8BC1QtB,WAGII,EAA0B,iBAARC,MAAoBA,MAAQA,KAAK/H,SAAWA,QAAU+H,KAGxEnJ,EAAO,KAAckJ,GAAYE,SAAS,cAATA,GAEtB,O,8BCRf,+BAIIC,EAAgC,iBAAXnJ,SAAuBA,UAAYA,QAAQoJ,UAAYpJ,QAG5EqJ,EAAaF,GAAgC,iBAAVlJ,GAAsBA,IAAWA,EAAOmJ,UAAYnJ,EAMvFqJ,EAHgBD,GAAcA,EAAWrJ,UAAYmJ,EAG5B,IAAKG,YAASC,EAsBvCC,GAnBiBF,EAASA,EAAOE,cAAWD,IAmBf,IAElB,Q,mDCrCf,uBAGIJ,EAAgC,iBAAXnJ,SAAuBA,UAAYA,QAAQoJ,UAAYpJ,QAG5EqJ,EAAaF,GAAgC,iBAAVlJ,GAAsBA,IAAWA,EAAOmJ,UAAYnJ,EAMvFwJ,EAHgBJ,GAAcA,EAAWrJ,UAAYmJ,GAGtB,IAAWO,QAG1CC,EAAY,WACd,IAEE,IAAIC,EAAQP,GAAcA,EAAWQ,SAAWR,EAAWQ,QAAQ,QAAQD,MAE3E,OAAIA,GAKGH,GAAeA,EAAYK,SAAWL,EAAYK,QAAQ,QACjE,MAAOnF,KAXI,GAcA,Q,mDC7Bf,uBAaA,MAGMoF,EAAmC,iBAAX3J,OAAsBA,OAAS4J,EAG7D,GAAKD,EAAeE,iBAiInB,MAAM,IAAI,IACT,8BACA,MAGDF,EAAeE,iBA5IA,W,kCCbhB,IAAIC,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,8BClBnC,YACA,IAAIC,EAA8B,iBAAVN,GAAsBA,GAAUA,EAAO9I,SAAWA,QAAU8I,EAErE,Q,gDCHf,uBAGIb,EAAgC,iBAAXnJ,SAAuBA,UAAYA,QAAQoJ,UAAYpJ,QAG5EqJ,EAAaF,GAAgC,iBAAVlJ,GAAsBA,IAAWA,EAAOmJ,UAAYnJ,EAMvFqJ,EAHgBD,GAAcA,EAAWrJ,UAAYmJ,EAG5B,IAAKG,YAASC,EACvCgB,EAAcjB,EAASA,EAAOiB,iBAAchB,EAqBjC,IAXf,SAAqBiB,EAAQC,GAC3B,GAAIA,EACF,OAAOD,EAAOE,QAEhB,IAAI1F,EAASwF,EAAOxF,OAChBD,EAASwF,EAAcA,EAAYvF,GAAU,IAAIwF,EAAOG,YAAY3F,GAGxE,OADAwF,EAAOI,KAAK7F,GACLA,K,mCC/BT9E,EAAOD,QAAU,SAAS6K,GACzB,IAAKA,EAAeC,gBAAiB,CACpC,IAAI7K,EAASiB,OAAOY,OAAO+I,GAEtB5K,EAAO8K,WAAU9K,EAAO8K,SAAW,IACxC7J,OAAOC,eAAelB,EAAQ,SAAU,CACvCmB,YAAY,EACZC,IAAK,WACJ,OAAOpB,EAAOQ,KAGhBS,OAAOC,eAAelB,EAAQ,KAAM,CACnCmB,YAAY,EACZC,IAAK,WACJ,OAAOpB,EAAOO,KAGhBU,OAAOC,eAAelB,EAAQ,UAAW,CACxCmB,YAAY,IAEbnB,EAAO6K,gBAAkB,EAE1B,OAAO7K,I,cCtBR,IAAI+K,EAGJA,EAAI,WACH,OAAO/H,KADJ,GAIJ,IAEC+H,EAAIA,GAAK,IAAI9B,SAAS,cAAb,GACR,MAAOvE,GAEc,iBAAXvE,SAAqB4K,EAAI5K,QAOrCH,EAAOD,QAAUgL,G,gBCnBjB,IAAId,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,6BCDpB,IAJf,WACE,OAAO,I,gBCdT,IAAIH,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,gR,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,svL,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,8pC,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,4F,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,yW,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,y0F,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,wU,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,0xH,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,mtL,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,4uD,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,kuF,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,4S,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,+iC,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,mvI,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,svC,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,sO,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,o+J,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,mT,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,+uP,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,kqM,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,k3H,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,2sC,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,2Z,cCAjBC,EAAOD,QAAU,qyD,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,0rB,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,8qC,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,mK,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,wX,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,k5C,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,swB,cCAjBC,EAAOD,QAAU,mV,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,uL,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,yY,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,y7C,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,k2D,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,svY,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,gX,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,4E,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,qe,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,q0E,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,68B,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,2kC,gBCAjB,IAAIkK,EAAM,EAAQ,GACFC,EAAU,EAAQ,IAIC,iBAFvBA,EAAUA,EAAQvI,WAAauI,EAAQC,QAAUD,KAG/CA,EAAU,CAAC,CAAClK,EAAOO,EAAI2J,EAAS,MAG9C,IAAIhF,EAAU,CAAC,WAAa,oBAAoB,WAAa,CAAC,YAAW,GAEzE,OAAiB,OACjB,WAAoB,GAEP+E,EAAIC,EAAShF,GAI1BlF,EAAOD,QAAUmK,EAAQE,QAAU,I,cClBnCpK,EAAOD,QAAU,4b,wFCKF,EAFF,IAAKuB,OCAd0J,EAAc/J,OAAOkB,UAGrB,EAAiB6I,EAAY5I,eAO7B6I,EAAuBD,EAAYtC,SAGnCwC,EAAiB,EAAS,EAAO3J,iBAAc+H,EA6BpC,MApBf,SAAmB9H,GACjB,IAAI2J,EAAQ,EAAezK,KAAKc,EAAO0J,GACnCE,EAAM5J,EAAM0J,GAEhB,IACE1J,EAAM0J,QAAkB5B,EACxB,IAAI+B,GAAW,EACf,MAAO3G,IAET,IAAII,EAASmG,EAAqBvK,KAAKc,GAQvC,OAPI6J,IACEF,EACF3J,EAAM0J,GAAkBE,SAEjB5J,EAAM0J,IAGVpG,GClCL,EAPc7D,OAAOkB,UAOcuG,SAaxB,MAJf,SAAwBlH,GACtB,OAAO,EAAqBd,KAAKc,ICT/B,EAAiB,EAAS,EAAOD,iBAAc+H,EAkBpC,MATf,SAAoB9H,GAClB,OAAa,MAATA,OACe8H,IAAV9H,EAdQ,qBADL,gBAiBJ,GAAkB,KAAkBP,OAAOO,GAC/C,EAAUA,GACV,EAAeA,ICVN,MANf,SAAiB8J,EAAMC,GACrB,OAAO,SAASC,GACd,OAAOF,EAAKC,EAAUC,MCLX,EAFI,EAAQvK,OAAOwK,eAAgBxK,QCyBnC,MAJf,SAAsBO,GACpB,OAAgB,MAATA,GAAiC,iBAATA,GCjB7BkK,EAAYzC,SAAS9G,UACrB,EAAclB,OAAOkB,UAGrBwJ,EAAeD,EAAUhD,SAGzB,EAAiB,EAAYtG,eAG7BwJ,EAAmBD,EAAajL,KAAKO,QA2C1B,MAbf,SAAuBO,GACrB,IAAK,EAAaA,IA5CJ,mBA4Cc,EAAWA,GACrC,OAAO,EAET,IAAIqK,EAAQ,EAAarK,GACzB,GAAc,OAAVqK,EACF,OAAO,EAET,IAAIC,EAAO,EAAepL,KAAKmL,EAAO,gBAAkBA,EAAMnB,YAC9D,MAAsB,mBAARoB,GAAsBA,aAAgBA,GAClDH,EAAajL,KAAKoL,IAASF,GC9ChB,MALf,WACE5I,KAAK+I,SAAW,GAChB/I,KAAKgJ,KAAO,GC2BC,MAJf,SAAYxK,EAAOyK,GACjB,OAAOzK,IAAUyK,GAAUzK,GAAUA,GAASyK,GAAUA,GCb3C,MAVf,SAAsBC,EAAOpK,GAE3B,IADA,IAAIiD,EAASmH,EAAMnH,OACZA,KACL,GAAI,EAAGmH,EAAMnH,GAAQ,GAAIjD,GACvB,OAAOiD,EAGX,OAAQ,GCXN+D,EAHaqD,MAAMhK,UAGC2G,OA4BT,MAjBf,SAAyBhH,GACvB,IAAIa,EAAOK,KAAK+I,SACZrG,EAAQ,EAAa/C,EAAMb,GAE/B,QAAI4D,EAAQ,KAIRA,GADY/C,EAAKoC,OAAS,EAE5BpC,EAAKyJ,MAELtD,EAAOpI,KAAKiC,EAAM+C,EAAO,KAEzB1C,KAAKgJ,MACA,ICbM,MAPf,SAAsBlK,GACpB,IAAIa,EAAOK,KAAK+I,SACZrG,EAAQ,EAAa/C,EAAMb,GAE/B,OAAO4D,EAAQ,OAAI4D,EAAY3G,EAAK+C,GAAO,ICA9B,MAJf,SAAsB5D,GACpB,OAAO,EAAakB,KAAK+I,SAAUjK,IAAQ,GCa9B,MAbf,SAAsBA,EAAKN,GACzB,IAAImB,EAAOK,KAAK+I,SACZrG,EAAQ,EAAa/C,EAAMb,GAQ/B,OANI4D,EAAQ,KACR1C,KAAKgJ,KACPrJ,EAAKsD,KAAK,CAACnE,EAAKN,KAEhBmB,EAAK+C,GAAO,GAAKlE,EAEZwB,MCTT,SAASqJ,EAAUC,GACjB,IAAI5G,GAAS,EACTX,EAAoB,MAAXuH,EAAkB,EAAIA,EAAQvH,OAG3C,IADA/B,KAAKuJ,UACI7G,EAAQX,GAAQ,CACvB,IAAIyH,EAAQF,EAAQ5G,GACpB1C,KAAKyJ,IAAID,EAAM,GAAIA,EAAM,KAK7BH,EAAUlK,UAAUoK,MAAQ,EAC5BF,EAAUlK,UAAkB,OAAI,EAChCkK,EAAUlK,UAAUf,IAAM,EAC1BiL,EAAUlK,UAAUuK,IAAM,EAC1BL,EAAUlK,UAAUsK,IAAM,EAEX,QCjBA,MALf,WACEzJ,KAAK+I,SAAW,IAAI,EACpB/I,KAAKgJ,KAAO,GCMC,MARf,SAAqBlK,GACnB,IAAIa,EAAOK,KAAK+I,SACZjH,EAASnC,EAAa,OAAEb,GAG5B,OADAkB,KAAKgJ,KAAOrJ,EAAKqJ,KACVlH,GCDM,MAJf,SAAkBhD,GAChB,OAAOkB,KAAK+I,SAAS3K,IAAIU,ICGZ,MAJf,SAAkBA,GAChB,OAAOkB,KAAK+I,SAASW,IAAI5K,ICoBZ,MALf,SAAkBN,GAChB,IAAIyB,SAAczB,EAClB,OAAgB,MAATA,IAA0B,UAARyB,GAA4B,YAARA,ICShC,IChCT0J,EDgCS,EAVf,SAAoBnL,GAClB,IAAK,EAASA,GACZ,OAAO,EAIT,IAAI4J,EAAM,EAAW5J,GACrB,MA5BY,qBA4BL4J,GA3BI,8BA2BcA,GA7BZ,0BA6B6BA,GA1B7B,kBA0BgDA,GE5BhD,EAFE,IAAK,sBDAlBwB,GACED,EAAM,SAASE,KAAK,GAAc,EAAWrG,MAAQ,EAAWA,KAAKsG,UAAY,KACvE,iBAAmBH,EAAO,GAc3B,MAJf,SAAkBrB,GAChB,QAASsB,GAAeA,KAActB,GEZpC,EAHYrC,SAAS9G,UAGIuG,SAqBd,MAZf,SAAkB4C,GAChB,GAAY,MAARA,EAAc,CAChB,IACE,OAAO,EAAa5K,KAAK4K,GACzB,MAAO5G,IACT,IACE,OAAQ4G,EAAO,GACf,MAAO5G,KAEX,MAAO,ICVLqI,EAAe,8BAGf,EAAY9D,SAAS9G,UACrB,EAAclB,OAAOkB,UAGrB,EAAe,EAAUuG,SAGzB,EAAiB,EAAYtG,eAG7B4K,EAAaC,OAAO,IACtB,EAAavM,KAAK,GAAgBwM,QAjBjB,sBAiBuC,QACvDA,QAAQ,yDAA0D,SAAW,KAmBjE,MARf,SAAsB1L,GACpB,SAAK,EAASA,IAAU,EAASA,MAGnB,EAAWA,GAASwL,EAAaD,GAChCI,KAAK,EAAS3L,KC/BhB,MAJf,SAAkBS,EAAQH,GACxB,OAAiB,MAAVG,OAAiBqH,EAAYrH,EAAOH,ICO9B,MALf,SAAmBG,EAAQH,GACzB,IAAIN,EAAQ,EAASS,EAAQH,GAC7B,OAAO,EAAaN,GAASA,OAAQ8H,GCPxB,GAFL,EAAU,IAAM,OCCX,GAFI,EAAUrI,OAAQ,UCWtB,OALf,WACE+B,KAAK+I,SAAW,GAAe,GAAa,MAAQ,GACpD/I,KAAKgJ,KAAO,GCKC,OANf,SAAoBlK,GAClB,IAAIgD,EAAS9B,KAAK0J,IAAI5K,WAAekB,KAAK+I,SAASjK,GAEnD,OADAkB,KAAKgJ,MAAQlH,EAAS,EAAI,EACnBA,GCJL,GAHc7D,OAAOkB,UAGQC,eAoBlB,OATf,SAAiBN,GACf,IAAIa,EAAOK,KAAK+I,SAChB,GAAI,GAAc,CAChB,IAAIjH,EAASnC,EAAKb,GAClB,MArBiB,8BAqBVgD,OAA4BwE,EAAYxE,EAEjD,OAAO,GAAepE,KAAKiC,EAAMb,GAAOa,EAAKb,QAAOwH,GCpBlD,GAHcrI,OAAOkB,UAGQC,eAgBlB,OALf,SAAiBN,GACf,IAAIa,EAAOK,KAAK+I,SAChB,OAAO,QAA8BzC,IAAd3G,EAAKb,GAAsB,GAAepB,KAAKiC,EAAMb,ICG/D,OAPf,SAAiBA,EAAKN,GACpB,IAAImB,EAAOK,KAAK+I,SAGhB,OAFA/I,KAAKgJ,MAAQhJ,KAAK0J,IAAI5K,GAAO,EAAI,EACjCa,EAAKb,GAAQ,SAA0BwH,IAAV9H,EAfV,4BAekDA,EAC9DwB,MCNT,SAASoK,GAAKd,GACZ,IAAI5G,GAAS,EACTX,EAAoB,MAAXuH,EAAkB,EAAIA,EAAQvH,OAG3C,IADA/B,KAAKuJ,UACI7G,EAAQX,GAAQ,CACvB,IAAIyH,EAAQF,EAAQ5G,GACpB1C,KAAKyJ,IAAID,EAAM,GAAIA,EAAM,KAK7BY,GAAKjL,UAAUoK,MAAQ,GACvBa,GAAKjL,UAAkB,OAAI,GAC3BiL,GAAKjL,UAAUf,IAAM,GACrBgM,GAAKjL,UAAUuK,IAAM,GACrBU,GAAKjL,UAAUsK,IAAM,GAEN,UCXA,OATf,WACEzJ,KAAKgJ,KAAO,EACZhJ,KAAK+I,SAAW,CACd,KAAQ,IAAI,GACZ,IAAO,IAAK,IAAO,GACnB,OAAU,IAAI,KCFH,OAPf,SAAmBvK,GACjB,IAAIyB,SAAczB,EAClB,MAAgB,UAARyB,GAA4B,UAARA,GAA4B,UAARA,GAA4B,WAARA,EACrD,cAAVzB,EACU,OAAVA,GCMQ,OAPf,SAAoB6L,EAAKvL,GACvB,IAAIa,EAAO0K,EAAItB,SACf,OAAO,GAAUjK,GACba,EAAmB,iBAAPb,EAAkB,SAAW,QACzCa,EAAK0K,KCGI,OANf,SAAwBvL,GACtB,IAAIgD,EAAS,GAAW9B,KAAMlB,GAAa,OAAEA,GAE7C,OADAkB,KAAKgJ,MAAQlH,EAAS,EAAI,EACnBA,GCCM,OAJf,SAAqBhD,GACnB,OAAO,GAAWkB,KAAMlB,GAAKV,IAAIU,ICGpB,OAJf,SAAqBA,GACnB,OAAO,GAAWkB,KAAMlB,GAAK4K,IAAI5K,ICSpB,OATf,SAAqBA,EAAKN,GACxB,IAAImB,EAAO,GAAWK,KAAMlB,GACxBkK,EAAOrJ,EAAKqJ,KAIhB,OAFArJ,EAAK8J,IAAI3K,EAAKN,GACdwB,KAAKgJ,MAAQrJ,EAAKqJ,MAAQA,EAAO,EAAI,EAC9BhJ,MCLT,SAASsK,GAAShB,GAChB,IAAI5G,GAAS,EACTX,EAAoB,MAAXuH,EAAkB,EAAIA,EAAQvH,OAG3C,IADA/B,KAAKuJ,UACI7G,EAAQX,GAAQ,CACvB,IAAIyH,EAAQF,EAAQ5G,GACpB1C,KAAKyJ,IAAID,EAAM,GAAIA,EAAM,KAK7Bc,GAASnL,UAAUoK,MAAQ,GAC3Be,GAASnL,UAAkB,OAAI,GAC/BmL,GAASnL,UAAUf,IAAM,GACzBkM,GAASnL,UAAUuK,IAAM,GACzBY,GAASnL,UAAUsK,IAAM,GAEV,UCEA,OAhBf,SAAkB3K,EAAKN,GACrB,IAAImB,EAAOK,KAAK+I,SAChB,GAAIpJ,aAAgB,EAAW,CAC7B,IAAI4K,EAAQ5K,EAAKoJ,SACjB,IAAK,IAAQwB,EAAMxI,OAASyI,IAG1B,OAFAD,EAAMtH,KAAK,CAACnE,EAAKN,IACjBwB,KAAKgJ,OAASrJ,EAAKqJ,KACZhJ,KAETL,EAAOK,KAAK+I,SAAW,IAAI,GAASwB,GAItC,OAFA5K,EAAK8J,IAAI3K,EAAKN,GACdwB,KAAKgJ,KAAOrJ,EAAKqJ,KACVhJ,MChBT,SAASyK,GAAMnB,GACb,IAAI3J,EAAOK,KAAK+I,SAAW,IAAI,EAAUO,GACzCtJ,KAAKgJ,KAAOrJ,EAAKqJ,KAInByB,GAAMtL,UAAUoK,MAAQ,EACxBkB,GAAMtL,UAAkB,OAAI,EAC5BsL,GAAMtL,UAAUf,IAAM,EACtBqM,GAAMtL,UAAUuK,IAAM,EACtBe,GAAMtL,UAAUsK,IAAM,GAEP,UCLA,OAZf,SAAmBP,EAAOwB,GAIxB,IAHA,IAAIhI,GAAS,EACTX,EAAkB,MAATmH,EAAgB,EAAIA,EAAMnH,SAE9BW,EAAQX,IAC8B,IAAzC2I,EAASxB,EAAMxG,GAAQA,EAAOwG,KAIpC,OAAOA,GCRM,GARO,WACpB,IACE,IAAIZ,EAAO,EAAUrK,OAAQ,kBAE7B,OADAqK,EAAK,GAAI,GAAI,IACNA,EACP,MAAO5G,KALU,GCsBN,OAbf,SAAyBzC,EAAQH,EAAKN,GACzB,aAAPM,GAAsB,GACxB,GAAeG,EAAQH,EAAK,CAC1B,cAAgB,EAChB,YAAc,EACd,MAASN,EACT,UAAY,IAGdS,EAAOH,GAAON,GCbd,GAHcP,OAAOkB,UAGQC,eAoBlB,OARf,SAAqBH,EAAQH,EAAKN,GAChC,IAAImM,EAAW1L,EAAOH,GAChB,GAAepB,KAAKuB,EAAQH,IAAQ,EAAG6L,EAAUnM,UACxC8H,IAAV9H,GAAyBM,KAAOG,IACnC,GAAgBA,EAAQH,EAAKN,ICgBlB,OA1Bf,SAAoBoM,EAAQC,EAAO5L,EAAQ6L,GACzC,IAAIC,GAAS9L,EACbA,IAAWA,EAAS,IAKpB,IAHA,IAAIyD,GAAS,EACTX,EAAS8I,EAAM9I,SAEVW,EAAQX,GAAQ,CACvB,IAAIjD,EAAM+L,EAAMnI,GAEZsI,EAAWF,EACXA,EAAW7L,EAAOH,GAAM8L,EAAO9L,GAAMA,EAAKG,EAAQ2L,QAClDtE,OAEaA,IAAb0E,IACFA,EAAWJ,EAAO9L,IAEhBiM,EACF,GAAgB9L,EAAQH,EAAKkM,GAE7B,GAAY/L,EAAQH,EAAKkM,GAG7B,OAAO/L,GCjBM,OAVf,SAAmBD,EAAG0L,GAIpB,IAHA,IAAIhI,GAAS,EACTZ,EAASqH,MAAMnK,KAEV0D,EAAQ1D,GACf8C,EAAOY,GAASgI,EAAShI,GAE3B,OAAOZ,GCCM,OAJf,SAAyBtD,GACvB,OAAO,EAAaA,IAVR,sBAUkB,EAAWA,ICVvC,GAAcP,OAAOkB,UAGrB,GAAiB,GAAYC,eAG7B6L,GAAuB,GAAYA,qBAyBxB,GALG,GAAgB,WAAa,OAAOC,UAApB,IAAsC,GAAkB,SAAS1M,GACjG,OAAO,EAAaA,IAAU,GAAed,KAAKc,EAAO,YACtDyM,GAAqBvN,KAAKc,EAAO,WCPvB,GAFD2K,MAAMgC,Q,QCnBhBC,GAAW,mBAoBA,OAVf,SAAiB5M,EAAOuD,GACtB,IAAI9B,SAAczB,EAGlB,SAFAuD,EAAmB,MAAVA,EAfY,iBAewBA,KAGlC,UAAR9B,GACU,UAARA,GAAoBmL,GAASjB,KAAK3L,KAChCA,GAAS,GAAKA,EAAQ,GAAK,GAAKA,EAAQuD,GCalC,OALf,SAAkBvD,GAChB,MAAuB,iBAATA,GACZA,GAAS,GAAKA,EAAQ,GAAK,GAAKA,GA9Bb,kBC+BnB6M,GAAiB,GACrBA,GAZiB,yBAYYA,GAXZ,yBAYjBA,GAXc,sBAWYA,GAVX,uBAWfA,GAVe,uBAUYA,GATZ,uBAUfA,GATsB,8BASYA,GARlB,wBAShBA,GARgB,yBAQY,EAC5BA,GAjCc,sBAiCYA,GAhCX,kBAiCfA,GApBqB,wBAoBYA,GAhCnB,oBAiCdA,GApBkB,qBAoBYA,GAhChB,iBAiCdA,GAhCe,kBAgCYA,GA/Bb,qBAgCdA,GA/Ba,gBA+BYA,GA9BT,mBA+BhBA,GA9BgB,mBA8BYA,GA7BZ,mBA8BhBA,GA7Ba,gBA6BYA,GA5BT,mBA6BhBA,GA5BiB,qBA4BY,EAcd,OALf,SAA0B7M,GACxB,OAAO,EAAaA,IAClB,GAASA,EAAMuD,WAAasJ,GAAe,EAAW7M,KC3C3C,OANf,SAAmB8J,GACjB,OAAO,SAAS9J,GACd,OAAO8J,EAAK9J,K,QCJZ8M,GAAmB,MAAY,KAASC,aAqB7B,GAFID,GAAmB,GAAUA,IAAoB,GCbhE,GAHcrN,OAAOkB,UAGQC,eAqClB,OA3Bf,SAAuBZ,EAAOgN,GAC5B,IAAIC,EAAQ,GAAQjN,GAChBkN,GAASD,GAAS,GAAYjN,GAC9BmN,GAAUF,IAAUC,GAAS,OAAAnF,GAAA,GAAS/H,GACtCoN,GAAUH,IAAUC,IAAUC,GAAU,GAAanN,GACrDqN,EAAcJ,GAASC,GAASC,GAAUC,EAC1C9J,EAAS+J,EAAc,GAAUrN,EAAMuD,OAAQ+J,QAAU,GACzD/J,EAASD,EAAOC,OAEpB,IAAK,IAAIjD,KAAON,GACTgN,IAAa,GAAe9N,KAAKc,EAAOM,IACvC+M,IAEQ,UAAP/M,GAEC6M,IAAkB,UAAP7M,GAA0B,UAAPA,IAE9B8M,IAAkB,UAAP9M,GAA0B,cAAPA,GAA8B,cAAPA,IAEtD,GAAQA,EAAKiD,KAElBD,EAAOmB,KAAKnE,GAGhB,OAAOgD,GC5CL,GAAc7D,OAAOkB,UAgBV,OAPf,SAAqBX,GACnB,IAAIsK,EAAOtK,GAASA,EAAMkJ,YAG1B,OAAOlJ,KAFqB,mBAARsK,GAAsBA,EAAK3J,WAAc,KCPhD,GAFE,EAAQlB,OAAOuF,KAAMvF,QCIlC,GAHcA,OAAOkB,UAGQC,eAsBlB,OAbf,SAAkBH,GAChB,IAAK,GAAYA,GACf,OAAO,GAAWA,GAEpB,IAAI6C,EAAS,GACb,IAAK,IAAIhD,KAAOb,OAAOgB,GACjB,GAAevB,KAAKuB,EAAQH,IAAe,eAAPA,GACtCgD,EAAOmB,KAAKnE,GAGhB,OAAOgD,GCMM,OAJf,SAAqBtD,GACnB,OAAgB,MAATA,GAAiB,GAASA,EAAMuD,UAAY,EAAWvD,ICOjD,OAJf,SAAcS,GACZ,OAAO,GAAYA,GAAU,GAAcA,GAAU,GAASA,ICjBjD,OAJf,SAAoBA,EAAQ2L,GAC1B,OAAO3L,GAAU,GAAW2L,EAAQ,GAAKA,GAAS3L,ICMrC,OAVf,SAAsBA,GACpB,IAAI6C,EAAS,GACb,GAAc,MAAV7C,EACF,IAAK,IAAIH,KAAOb,OAAOgB,GACrB6C,EAAOmB,KAAKnE,GAGhB,OAAOgD,GCRL,GAHc7D,OAAOkB,UAGQC,eAwBlB,OAff,SAAoBH,GAClB,IAAK,EAASA,GACZ,OAAO,GAAaA,GAEtB,IAAI8M,EAAU,GAAY9M,GACtB6C,EAAS,GAEb,IAAK,IAAIhD,KAAOG,GACD,eAAPH,IAAyBiN,GAAY,GAAerO,KAAKuB,EAAQH,KACrEgD,EAAOmB,KAAKnE,GAGhB,OAAOgD,GCEM,OAJf,SAAgB7C,GACd,OAAO,GAAYA,GAAU,GAAcA,GAAQ,GAAQ,GAAWA,ICZzD,OAJf,SAAsBA,EAAQ2L,GAC5B,OAAO3L,GAAU,GAAW2L,EAAQ,GAAOA,GAAS3L,I,QCMvC,OAXf,SAAmB2L,EAAQ1B,GACzB,IAAIxG,GAAS,EACTX,EAAS6I,EAAO7I,OAGpB,IADAmH,IAAUA,EAAQC,MAAMpH,MACfW,EAAQX,GACfmH,EAAMxG,GAASkI,EAAOlI,GAExB,OAAOwG,GCQM,OAff,SAAqBA,EAAO8C,GAM1B,IALA,IAAItJ,GAAS,EACTX,EAAkB,MAATmH,EAAgB,EAAIA,EAAMnH,OACnCkK,EAAW,EACXnK,EAAS,KAEJY,EAAQX,GAAQ,CACvB,IAAIvD,EAAQ0K,EAAMxG,GACdsJ,EAAUxN,EAAOkE,EAAOwG,KAC1BpH,EAAOmK,KAAczN,GAGzB,OAAOsD,GCCM,OAJf,WACE,MAAO,ICZL,GAHc7D,OAAOkB,UAGc8L,qBAGnCiB,GAAmBjO,OAAOkO,sBAmBf,GAVGD,GAA+B,SAASjN,GACxD,OAAc,MAAVA,EACK,IAETA,EAAShB,OAAOgB,GACT,GAAYiN,GAAiBjN,IAAS,SAASmN,GACpD,OAAO,GAAqB1O,KAAKuB,EAAQmN,QANR,GCJtB,OAJf,SAAqBxB,EAAQ3L,GAC3B,OAAO,GAAW2L,EAAQ,GAAWA,GAAS3L,ICOjC,OAXf,SAAmBiK,EAAOmD,GAKxB,IAJA,IAAI3J,GAAS,EACTX,EAASsK,EAAOtK,OAChBuK,EAASpD,EAAMnH,SAEVW,EAAQX,GACfmH,EAAMoD,EAAS5J,GAAS2J,EAAO3J,GAEjC,OAAOwG,GCQM,GAlBQjL,OAAOkO,sBASqB,SAASlN,GAE1D,IADA,IAAI6C,EAAS,GACN7C,GACL,GAAU6C,EAAQ,GAAW7C,IAC7BA,EAAS,EAAaA,GAExB,OAAO6C,GAN8B,GCAxB,OAJf,SAAuB8I,EAAQ3L,GAC7B,OAAO,GAAW2L,EAAQ,GAAaA,GAAS3L,ICOnC,OALf,SAAwBA,EAAQsN,EAAUC,GACxC,IAAI1K,EAASyK,EAAStN,GACtB,OAAO,GAAQA,GAAU6C,EAAS,GAAUA,EAAQ0K,EAAYvN,KCDnD,OAJf,SAAoBA,GAClB,OAAO,GAAeA,EAAQ,GAAM,KCIvB,OAJf,SAAsBA,GACpB,OAAO,GAAeA,EAAQ,GAAQ,KCPzB,GAFA,EAAU,IAAM,YCEhB,GAFD,EAAU,IAAM,WCEf,GAFL,EAAU,IAAM,OCEX,GAFD,EAAU,IAAM,WCc1BwN,GAAqB,EAAS,IAC9BC,GAAgB,EAAS,IACzBC,GAAoB,EAAS,IAC7BC,GAAgB,EAAS,IACzBC,GAAoB,EAAS,IAS7BC,GAAS,GAGR,IAnBa,qBAmBDA,GAAO,IAAI,GAAS,IAAIC,YAAY,MAChD,IA1BQ,gBA0BDD,GAAO,IAAI,KAClB,IAzBY,oBAyBDA,GAAO,GAAQE,YAC1B,IAzBQ,gBAyBDF,GAAO,IAAI,KAClB,IAzBY,oBAyBDA,GAAO,IAAI,OACzBA,GAAS,SAAStO,GAChB,IAAIsD,EAAS,EAAWtD,GACpBsK,EA/BQ,mBA+BDhH,EAAsBtD,EAAMkJ,iBAAcpB,EACjD2G,EAAanE,EAAO,EAASA,GAAQ,GAEzC,GAAImE,EACF,OAAQA,GACN,KAAKR,GAAoB,MA/Bf,oBAgCV,KAAKC,GAAe,MAtCf,eAuCL,KAAKC,GAAmB,MArCf,mBAsCT,KAAKC,GAAe,MArCf,eAsCL,KAAKC,GAAmB,MArCf,mBAwCb,OAAO/K,IAII,UCrDX,GAHc7D,OAAOkB,UAGQC,eAqBlB,OAZf,SAAwB8J,GACtB,IAAInH,EAASmH,EAAMnH,OACfD,EAAS,IAAIoH,EAAMxB,YAAY3F,GAOnC,OAJIA,GAA6B,iBAAZmH,EAAM,IAAkB,GAAexL,KAAKwL,EAAO,WACtEpH,EAAOY,MAAQwG,EAAMxG,MACrBZ,EAAOoL,MAAQhE,EAAMgE,OAEhBpL,GCjBM,GAFE,IAAKqL,WCYP,OANf,SAA0BC,GACxB,IAAItL,EAAS,IAAIsL,EAAY1F,YAAY0F,EAAYC,YAErD,OADA,IAAI,GAAWvL,GAAQ2H,IAAI,IAAI,GAAW2D,IACnCtL,GCGM,OALf,SAAuBwL,EAAU9F,GAC/B,IAAID,EAASC,EAAS,GAAiB8F,EAAS/F,QAAU+F,EAAS/F,OACnE,OAAO,IAAI+F,EAAS5F,YAAYH,EAAQ+F,EAASC,WAAYD,EAASD,aCXpEG,GAAU,OAeC,OANf,SAAqBC,GACnB,IAAI3L,EAAS,IAAI2L,EAAO/F,YAAY+F,EAAO7C,OAAQ4C,GAAQ3D,KAAK4D,IAEhE,OADA3L,EAAO4L,UAAYD,EAAOC,UACnB5L,GCVL6L,GAAc,EAAS,EAAOxO,eAAYmH,EAC1CsH,GAAgBD,GAAcA,GAAYE,aAAUvH,EAazC,OAJf,SAAqB8F,GACnB,OAAOwB,GAAgB3P,OAAO2P,GAAclQ,KAAK0O,IAAW,ICC/C,OALf,SAAyB0B,EAAYtG,GACnC,IAAID,EAASC,EAAS,GAAiBsG,EAAWvG,QAAUuG,EAAWvG,OACvE,OAAO,IAAIuG,EAAWpG,YAAYH,EAAQuG,EAAWP,WAAYO,EAAW/L,SCgE/D,OApCf,SAAwB9C,EAAQmJ,EAAKZ,GACnC,IAAIsB,EAAO7J,EAAOyI,YAClB,OAAQU,GACN,IA3BiB,uBA4Bf,OAAO,GAAiBnJ,GAE1B,IAvCU,mBAwCV,IAvCU,gBAwCR,OAAO,IAAI6J,GAAM7J,GAEnB,IAjCc,oBAkCZ,OAAO,GAAcA,EAAQuI,GAE/B,IAnCa,wBAmCI,IAlCJ,wBAmCb,IAlCU,qBAkCI,IAjCH,sBAiCkB,IAhClB,sBAiCX,IAhCW,sBAgCI,IA/BG,6BA+BmB,IA9BzB,uBA8ByC,IA7BzC,uBA8BV,OAAO,GAAgBvI,EAAQuI,GAEjC,IAjDS,eAkDP,OAAO,IAAIsB,EAEb,IAnDY,kBAoDZ,IAjDY,kBAkDV,OAAO,IAAIA,EAAK7J,GAElB,IAtDY,kBAuDV,OAAO,GAAYA,GAErB,IAxDS,eAyDP,OAAO,IAAI6J,EAEb,IAzDY,kBA0DV,OAAO,GAAY7J,KCrErB8O,GAAe9P,OAAOY,OA0BX,GAhBG,WAChB,SAASI,KACT,OAAO,SAAS4J,GACd,IAAK,EAASA,GACZ,MAAO,GAET,GAAIkF,GACF,OAAOA,GAAalF,GAEtB5J,EAAOE,UAAY0J,EACnB,IAAI/G,EAAS,IAAI7C,EAEjB,OADAA,EAAOE,eAAYmH,EACZxE,GAZM,GCIF,OANf,SAAyB7C,GACvB,MAAqC,mBAAtBA,EAAOyI,aAA8B,GAAYzI,GAE5D,GADA,GAAW,EAAaA,KCIf,OAJf,SAAmBT,GACjB,OAAO,EAAaA,IAVT,gBAUmB,GAAOA,ICTnCwP,GAAY,MAAY,KAASC,MAqBtB,GAFHD,GAAY,GAAUA,IAAa,GCPhC,OAJf,SAAmBxP,GACjB,OAAO,EAAaA,IAVT,gBAUmB,GAAOA,ICTnC0P,GAAY,MAAY,KAASC,MAqBtB,GAFHD,GAAY,GAAUA,IAAa,GCiC3CE,GAAgB,GACpBA,GA9Bc,sBA8BWA,GA7BV,kBA8BfA,GAfqB,wBAeWA,GAdd,qBAelBA,GA9Bc,oBA8BWA,GA7BX,iBA8BdA,GAfiB,yBAeWA,GAdX,yBAejBA,GAdc,sBAcWA,GAbV,uBAcfA,GAbe,uBAaWA,GA5Bb,gBA6BbA,GA5BgB,mBA4BWA,GA3BX,mBA4BhBA,GA3BgB,mBA2BWA,GA1Bd,gBA2BbA,GA1BgB,mBA0BWA,GAzBX,mBA0BhBA,GAhBe,uBAgBWA,GAfJ,8BAgBtBA,GAfgB,wBAeWA,GAdX,yBAcsC,EACtDA,GArCe,kBAqCWA,GApCZ,qBAqCdA,GA5BiB,qBA4BW,EA8Fb,OA5Ef,SAASC,EAAU7P,EAAO8P,EAASxD,EAAYhM,EAAKG,EAAQqB,GAC1D,IAAIwB,EACA0F,EAnEgB,EAmEP8G,EACTC,EAnEgB,EAmEPD,EACTE,EAnEmB,EAmEVF,EAKb,GAHIxD,IACFhJ,EAAS7C,EAAS6L,EAAWtM,EAAOM,EAAKG,EAAQqB,GAASwK,EAAWtM,SAExD8H,IAAXxE,EACF,OAAOA,EAET,IAAK,EAAStD,GACZ,OAAOA,EAET,IAAIiN,EAAQ,GAAQjN,GACpB,GAAIiN,GAEF,GADA3J,EAAS,GAAetD,IACnBgJ,EACH,OAAO,GAAUhJ,EAAOsD,OAErB,CACL,IAAIsG,EAAM,GAAO5J,GACbiQ,EA9EM,qBA8EGrG,GA7EJ,8BA6EsBA,EAE/B,GAAI,OAAA7B,GAAA,GAAS/H,GACX,OAAO,aAAYA,EAAOgJ,GAE5B,GA/EY,mBA+ERY,GAxFM,sBAwFcA,GAAmBqG,IAAWxP,GAEpD,GADA6C,EAAUyM,GAAUE,EAAU,GAAK,GAAgBjQ,IAC9CgJ,EACH,OAAO+G,EACH,GAAc/P,EAAO,GAAasD,EAAQtD,IAC1C,GAAYA,EAAO,GAAWsD,EAAQtD,QAEvC,CACL,IAAK4P,GAAchG,GACjB,OAAOnJ,EAAST,EAAQ,GAE1BsD,EAAS,GAAetD,EAAO4J,EAAKZ,IAIxClH,IAAUA,EAAQ,IAAI,IACtB,IAAIoO,EAAUpO,EAAMlC,IAAII,GACxB,GAAIkQ,EACF,OAAOA,EAETpO,EAAMmJ,IAAIjL,EAAOsD,GAEb,GAAMtD,GACRA,EAAMiF,SAAQ,SAASkL,GACrB7M,EAAO8M,IAAIP,EAAUM,EAAUL,EAASxD,EAAY6D,EAAUnQ,EAAO8B,OAE9D,GAAM9B,IACfA,EAAMiF,SAAQ,SAASkL,EAAU7P,GAC/BgD,EAAO2H,IAAI3K,EAAKuP,EAAUM,EAAUL,EAASxD,EAAYhM,EAAKN,EAAO8B,OAIzE,IAAIiM,EAAWiC,EACVD,EAAS,GAAe,GACxBA,EAASM,OAAS,GAEnBhE,EAAQY,OAAQnF,EAAYiG,EAAS/N,GASzC,OARA,GAAUqM,GAASrM,GAAO,SAASmQ,EAAU7P,GACvC+L,IAEF8D,EAAWnQ,EADXM,EAAM6P,IAIR,GAAY7M,EAAQhD,EAAKuP,EAAUM,EAAUL,EAASxD,EAAYhM,EAAKN,EAAO8B,OAEzEwB,GC1HM,OALf,SAAuBtD,EAAOsM,GAE5B,OAAO,GAAUtM,EAAO,EADxBsM,EAAkC,mBAAdA,EAA2BA,OAAaxE,ICX/C,OAJf,SAAmB9H,GACjB,OAAO,EAAaA,IAA6B,IAAnBA,EAAM2H,WAAmB,EAAc3H,ICPxD,MAAM,GAOpB,YAAasQ,EAAgBC,GAO5B/O,KAAKgP,QAAU,GAGVD,GAGJ/O,KAAK/C,OAAQgS,GAAaF,IAItBD,GACJ9O,KAAKkP,mBAAoBlP,KAAKgP,QAASF,GAyCzC,IAAKhR,EAAMU,GACVwB,KAAKmP,aAAcnP,KAAKgP,QAASlR,EAAMU,GAcxC,OAAQV,EAAMU,GAGbwB,KAAKmP,aAAcnP,KAAKgP,QAASlR,EAAMU,GAFtB,GAiBlB,IAAKV,GACJ,OAAOkC,KAAKoP,eAAgBpP,KAAKgP,QAASlR,GAQ3C,SACC,IAAM,MAAMA,KAAQG,OAAOuF,KAAMxD,KAAKgP,eAC/BlR,EAcR,aAAcsD,EAAQtD,EAAMU,EAAO6Q,GAAW,GAE7C,GAAK,EAAevR,GAGnB,YAFAkC,KAAKkP,mBAAoB9N,EAAQtD,EAAMuR,GAMxC,MAAMC,EAAQxR,EAAKyR,MAAO,KAG1BzR,EAAOwR,EAAMlG,MAGb,IAAM,MAAMoG,KAAQF,EAEb,EAAelO,EAAQoO,MAC5BpO,EAAQoO,GAAS,IAIlBpO,EAASA,EAAQoO,GAIlB,GAAK,EAAehR,GAWnB,OATM,EAAe4C,EAAQtD,MAC5BsD,EAAQtD,GAAS,IAGlBsD,EAASA,EAAQtD,QAGjBkC,KAAKkP,mBAAoB9N,EAAQ5C,EAAO6Q,GAMpCA,QAAqC,IAAlBjO,EAAQtD,KAIhCsD,EAAQtD,GAASU,GAWlB,eAAgBoM,EAAQ9M,GAEvB,MAAMwR,EAAQxR,EAAKyR,MAAO,KAG1BzR,EAAOwR,EAAMlG,MAGb,IAAM,MAAMoG,KAAQF,EAAQ,CAC3B,IAAM,EAAe1E,EAAQ4E,IAAW,CACvC5E,EAAS,KACT,MAIDA,EAASA,EAAQ4E,GAIlB,OAAO5E,EAASqE,GAAarE,EAAQ9M,SAAWwI,EAWjD,mBAAoBlF,EAAQqO,EAAeJ,GAC1CpR,OAAOuF,KAAMiM,GAAgBhM,QAAS3E,IACrCkB,KAAKmP,aAAc/N,EAAQtC,EAAK2Q,EAAe3Q,GAAOuQ,MAQzD,SAASJ,GAAarE,GACrB,OAAO,GAAeA,EAAQ8E,IAQ/B,SAASA,GAAoBlR,GAC5B,OAAO,GAAWA,GAAUA,OAAQ8H,EC5NtB,OANf,WACC,OAAO,SAASqJ,IACfA,EAAIC,QAAS,ICLA,MAAM,GAKpB,YAAahF,EAAQ9M,GAOpBkC,KAAK4K,OAASA,EAQd5K,KAAKlC,KAAOA,EAQZkC,KAAK6P,KAAO,GASZ7P,KAAK8P,KAAO,KAOZ9P,KAAK+P,IAAM,MChDb,MAAMC,GAAc,IAAI7G,MAAO,KAAM8G,OACnC5F,IAAK,CAAE6F,EAAKxN,KAAa,IAAM,EAAUgD,SAAU,KAAO+B,OAAQ,IAYrD,SAAS,KAWvB,MAAM0I,EAAqB,WAAhBC,KAAKC,WAA2B,EACrCC,EAAqB,WAAhBF,KAAKC,WAA2B,EACrCE,EAAqB,WAAhBH,KAAKC,WAA2B,EACrCG,EAAqB,WAAhBJ,KAAKC,WAA2B,EAG3C,MAAO,IACNL,GAAaG,GAAM,EAAI,KACvBH,GAAaG,GAAM,EAAI,KACvBH,GAAaG,GAAM,GAAK,KACxBH,GAAaG,GAAM,GAAK,KACxBH,GAAaM,GAAM,EAAI,KACvBN,GAAaM,GAAM,EAAI,KACvBN,GAAaM,GAAM,GAAK,KACxBN,GAAaM,GAAM,GAAK,KACxBN,GAAaO,GAAM,EAAI,KACvBP,GAAaO,GAAM,EAAI,KACvBP,GAAaO,GAAM,GAAK,KACxBP,GAAaO,GAAM,GAAK,KACxBP,GAAaQ,GAAM,EAAI,KACvBR,GAAaQ,GAAM,EAAI,KACvBR,GAAaQ,GAAM,GAAK,KACxBR,GAAaQ,GAAM,GAAK,KCdX,OAvBI,CAQlB,IAAKC,GACJ,MAAwB,iBAAZA,EACJzQ,KAAMyQ,IAAczQ,KAAK0Q,OAEzBD,GAITE,QAAS,IACTC,KAAM,IACNF,OAAQ,EACRG,KAAM,IACNC,QAAS,K,eCvBV,MAAMC,GAAezS,OAAQ,eACvB0S,GAAa1S,OAAQ,aAgSZ,OAxRM,CAIpB,GAAI2S,EAAOC,EAAUhP,EAAU,IAC9BlC,KAAKmR,SAAUnR,KAAMiR,EAAOC,EAAUhP,IAMvC,KAAM+O,EAAOC,EAAUhP,GACtB,IAAIkP,GAAW,EAiBfpR,KAAKmR,SAAUnR,KAAMiR,GAfA,SAAUA,KAAUI,GAGlCD,IACLA,GAAW,EAGXH,EAAMlB,MAGNmB,EAASxT,KAAMsC,KAAMiR,KAAUI,MAKSnP,IAM3C,IAAK+O,EAAOC,GACXlR,KAAKsR,cAAetR,KAAMiR,EAAOC,IAMlC,SAAUK,EAASN,EAAOC,EAAUhP,EAAU,IAC7C,IAAIsP,EAAaC,EAgBXzR,KAAM+Q,MACX/Q,KAAM+Q,IAAiB,IAGxB,MAAMW,EAAW1R,KAAM+Q,IAEjBY,GAAeJ,IACpBK,GAAeL,GAGhB,MAAMM,EAAYF,GAAeJ,IAEzBC,EAAcE,EAAUG,MAC/BL,EAAcE,EAAUG,GAAc,CACrCN,UACAO,UAAW,MAILL,EAAiBD,EAAYM,UAAWb,MAC/CQ,EAAiBD,EAAYM,UAAWb,GAAU,IAGnDQ,EAAexO,KAAMiO,GAqZvB,SAA+BtG,EAAQmH,GACtC,MAAMC,EAASC,GAAWrH,GAG1B,GAAKoH,EAAQD,GAEZ,OASD,IAAIjU,EAAOiU,EAEPG,EAAiB,KAGrB,MAAMC,EAAgB,GAKtB,KAAiB,KAATrU,IACFkU,EAAQlU,IAQbkU,EAAQlU,GA7CF,CACNgU,UAAW,GACXM,YAAa,IA6CbD,EAAclP,KAAM+O,EAAQlU,IAGvBoU,GACJF,EAAQlU,GAAOsU,YAAYnP,KAAMiP,GAGlCA,EAAiBpU,EAEjBA,EAAOA,EAAKuU,OAAQ,EAAGvU,EAAKwU,YAAa,MAG1C,GAAc,KAATxU,EAAc,CAKlB,IAAM,MAAMyU,KAAQJ,EACnBI,EAAKT,UAAYE,EAAQlU,GAAOgU,UAAUrK,QAI3CuK,EAAQlU,GAAOsU,YAAYnP,KAAMiP,IA5cjCM,CAAsBjB,EAASN,GAC/B,MAAMwB,EAAQC,GAA+BnB,EAASN,GAChDR,EAAW,GAAWrS,IAAK8D,EAAQuO,UAEnCkC,EAAqB,CAC1BzB,WACAT,YAID,IAAM,MAAMqB,KAAaW,EAAQ,CAEhC,IAAIG,GAAQ,EAEZ,IAAM,IAAIrV,EAAI,EAAGA,EAAIuU,EAAU/P,OAAQxE,IACtC,GAAKuU,EAAWvU,GAAIkT,SAAWA,EAAW,CACzCqB,EAAUhM,OAAQvI,EAAG,EAAGoV,GACxBC,GAAQ,EAER,MAKIA,GACLd,EAAU7O,KAAM0P,KAQnB,cAAepB,EAASN,EAAOC,GAC9B,MAAMQ,EAAW1R,KAAM+Q,IACvB,IAAIc,EAAYN,GAAWI,GAAeJ,GAC1C,MAAMC,EAAcE,GAAYG,GAAaH,EAAUG,GACjDJ,EAAiBD,GAAeP,GAASO,EAAYM,UAAWb,GAGtE,MAAMS,GAAcH,IAAYC,GAAmBP,IAAUQ,GAK7D,GAAKP,EAAW,CACf2B,GAAgBtB,EAASN,EAAOC,IAMhB,IAFFO,EAAeqB,QAAS5B,KAGN,IAA1BO,EAAe1P,cACZyP,EAAYM,UAAWb,GAE9B4B,GAAgBtB,EAASN,EAAOC,SAK9B,GAAKO,EAAiB,CAC1B,KAAUP,EAAWO,EAAerI,OACnCyJ,GAAgBtB,EAASN,EAAOC,UAG1BM,EAAYM,UAAWb,QAG1B,GAAKO,EAAc,CACvB,IAAMP,KAASO,EAAYM,UAC1B9R,KAAKsR,cAAeC,EAASN,UAEvBS,EAAUG,OAGb,CACJ,IAAMA,KAAaH,EAClB1R,KAAKsR,cAAeI,EAAUG,GAAYN,gBAEpCvR,KAAM+Q,MAOf,KAAMgC,KAAgB1B,GACrB,IACC,MAAM2B,EAAYD,aAAuB,GAAYA,EAAc,IAAI,GAAW/S,KAAM+S,GAClF9B,EAAQ+B,EAAUlV,KACxB,IAAIgU,EA6YP,SAASmB,EAAsBrI,EAAQmH,GACtC,IAAId,EAEJ,IAAMrG,EAAOsI,WAAcjC,EAAQrG,EAAOsI,QAASnB,MAAkBd,EAAMa,UAAU/P,OAGpF,OAAKgQ,EAAUe,QAAS,MAAS,EAEzBG,EAAsBrI,EAAQmH,EAAUM,OAAQ,EAAGN,EAAUO,YAAa,OAG1E,KAIT,OAAOrB,EAAMa,UA5ZKmB,CAAsBjT,KAAMiR,GAM5C,GAHA+B,EAAUnD,KAAK5M,KAAMjD,MAGhB8R,EAAY,CAEhB,MAAMqB,EAAe,CAAEH,KAAc3B,GAOrCS,EAAY3I,MAAMiK,KAAMtB,GAExB,IAAM,IAAIvU,EAAI,EAAGA,EAAIuU,EAAU/P,SAC9B+P,EAAWvU,GAAI2T,SAASmC,MAAOrT,KAAMmT,GAGhCH,EAAUjD,IAAIH,gBAEXoD,EAAUjD,IAAIH,OAErBiD,GAAgB7S,KAAMiR,EAAOa,EAAWvU,GAAI2T,YAIxC8B,EAAUlD,KAAKF,QAZkBrS,MAmBxC,GAAKyC,KAAKsT,aAAe,CACxB,MAAMC,EAAevT,KAAKsT,aAAalV,IAAK6S,GACtCuC,EAAsBxT,KAAKsT,aAAalV,IAAK,KAE9CmV,GACJE,GAAqBF,EAAcP,EAAW3B,GAG1CmC,GACJC,GAAqBD,EAAqBR,EAAW3B,GAIvD,OAAO2B,EAAUU,OAChB,MAAQxT,GAGT,KAAcyT,uBAAwBzT,EAAKF,QAO7C,YAAagS,GACZ,MAAO,CACN4B,GAAI,CAAErC,EAASsC,KACR7T,KAAKsT,eACVtT,KAAKsT,aAAe,IAAIQ,KAKzB9B,EAAOvO,QAASsO,IACf,MAAMwB,EAAevT,KAAKsT,aAAalV,IAAK2T,GAEtCwB,EAGLA,EAAa9J,IAAK8H,EAASsC,GAF3B7T,KAAKsT,aAAa7J,IAAKsI,EAAW,IAAI+B,IAAK,CAAE,CAAEvC,EAASsC,WAY7D,eAAgB5C,EAAOM,GACtB,GAAMvR,KAAKsT,aAIX,GAAMrC,EAEC,GAAMM,EAEN,CACN,MAAMgC,EAAevT,KAAKsT,aAAalV,IAAK6S,GAEvCsC,GACJA,EAAaQ,OAAQxC,QALtBvR,KAAKsT,aAAaS,OAAQ9C,QAF1BjR,KAAKsT,aAAa/J,UAkLd,SAASqI,GAAeL,EAASjP,GACjCiP,EAASP,MACdO,EAASP,IAAe1O,GAAM,MAUzB,SAASqP,GAAeJ,GAC9B,OAAOA,EAASP,IAMjB,SAASiB,GAAWrH,GAOnB,OANMA,EAAOsI,SACZjV,OAAOC,eAAgB0M,EAAQ,UAAW,CACzCpM,MAAO,KAIFoM,EAAOsI,QAiFf,SAASR,GAA+B9H,EAAQmH,GAC/C,MAAMiC,EAAY/B,GAAWrH,GAAUmH,GAEvC,IAAMiC,EACL,MAAO,GAGR,IAAIC,EAAiB,CAAED,EAAUlC,WAEjC,IAAM,IAAIvU,EAAI,EAAGA,EAAIyW,EAAU5B,YAAYrQ,OAAQxE,IAAM,CACxD,MAAM2W,EAAsBxB,GAA+B9H,EAAQoJ,EAAU5B,YAAa7U,IAE1F0W,EAAiBA,EAAexR,OAAQyR,GAGzC,OAAOD,EA+BR,SAASR,GAAqBF,EAAcP,EAAWmB,GACtD,IAAM,IAAM5C,EAASzT,KAAUyV,EAAe,CACvCzV,EAEqB,mBAARA,IAClBA,EAAOA,EAAMkV,EAAUlV,OAFvBA,EAAOkV,EAAUlV,KAKlB,MAAMsW,EAAgB,IAAI,GAAWpB,EAAUpI,OAAQ9M,GAEvDsW,EAAcvE,KAAO,IAAKmD,EAAUnD,MAEpC0B,EAAQ8C,KAAMD,KAAkBD,IASlC,SAAStB,GAAgBtB,EAASN,EAAOC,GACxC,MAAMuB,EAAQC,GAA+BnB,EAASN,GAEtD,IAAM,MAAMa,KAAaW,EACxB,IAAM,IAAIlV,EAAI,EAAGA,EAAIuU,EAAU/P,OAAQxE,IACjCuU,EAAWvU,GAAI2T,UAAYA,IAE/BY,EAAUhM,OAAQvI,EAAG,GACrBA,KC9nBW,SAAS+W,GAAY9V,GACnC,SAAWA,IAASA,EAAOF,OAAOiW,WCgBpB,SAASC,GAAKC,KAAcC,GAC1CA,EAAOjR,QAASkR,IACf1W,OAAO2W,oBAAqBD,GAAQlS,OAAQxE,OAAOkO,sBAAuBwI,IACxElR,QAAS3E,IACT,GAAKA,KAAO2V,EAAUtV,UACrB,OAGD,MAAM0V,EAAmB5W,OAAO6W,yBAA0BH,EAAO7V,GACjE+V,EAAiB1W,YAAa,EAE9BF,OAAOC,eAAgBuW,EAAUtV,UAAWL,EAAK+V,OChBtC,MAAM,GAqCpB,YAAaE,EAAwB,GAAI7S,EAAU,IAClD,MAAM8S,EAAkBV,GAAYS,GA+DpC,GA7DMC,IACL9S,EAAU6S,GASX/U,KAAKiV,OAAS,GAQdjV,KAAKkV,SAAW,IAAIpB,IAQpB9T,KAAKmV,YAAcjT,EAAQkT,YAAc,KAYzCpV,KAAKqV,6BAA+B,IAAIC,QAYxCtV,KAAKuV,6BAA+B,IAAID,QAQxCtV,KAAKwV,4BAA8B,GAG9BR,EACJ,IAAM,MAAM3S,KAAQ0S,EACnB/U,KAAKiV,OAAOhS,KAAMZ,GAClBrC,KAAKkV,SAASzL,IAAKzJ,KAAKyV,uBAAwBpT,GAAQA,GAkB3D,aACC,OAAOrC,KAAKiV,OAAOlT,OAQpB,YACC,OAAO/B,KAAKiV,OAAQ,IAAO,KAQ5B,WACC,OAAOjV,KAAKiV,OAAQjV,KAAK+B,OAAS,IAAO,KAe1C,IAAKM,EAAMK,GACV,OAAO1C,KAAK0V,QAAS,CAAErT,GAAQK,GAchC,QAASiT,EAAOjT,GACf,QAAe4D,IAAV5D,EACJA,EAAQ1C,KAAKiV,OAAOlT,YACd,GAAKW,EAAQ1C,KAAKiV,OAAOlT,QAAUW,EAAQ,EAOjD,MAAM,IAAI,KAAe,oCAAqC1C,MAG/D,IAAM,IAAIsM,EAAS,EAAGA,EAASqJ,EAAM5T,OAAQuK,IAAW,CACvD,MAAMjK,EAAOsT,EAAOrJ,GACdsJ,EAAS5V,KAAKyV,uBAAwBpT,GACtCwT,EAAmBnT,EAAQ4J,EAEjCtM,KAAKiV,OAAOnP,OAAQ+P,EAAkB,EAAGxT,GACzCrC,KAAKkV,SAASzL,IAAKmM,EAAQvT,GAE3BrC,KAAKqU,KAAM,MAAOhS,EAAMwT,GASzB,OANA7V,KAAKqU,KAAM,SAAU,CACpBzB,MAAO+C,EACPG,QAAS,GACTpT,UAGM1C,KASR,IAAK+V,GACJ,IAAI1T,EAEJ,GAAyB,iBAAb0T,EACX1T,EAAOrC,KAAKkV,SAAS9W,IAAK2X,OACpB,IAAyB,iBAAbA,EAQlB,MAAM,IAAI,KAAe,6BAA8B/V,MAPvDqC,EAAOrC,KAAKiV,OAAQc,GAUrB,OAAO1T,GAAQ,KAShB,IAAK2T,GACJ,GAAwB,iBAAZA,EACX,OAAOhW,KAAKkV,SAASxL,IAAKsM,GACpB,CACN,MACM1T,EAAK0T,EADQhW,KAAKmV,aAGxB,OAAOnV,KAAKkV,SAASxL,IAAKpH,IAW5B,SAAU0T,GACT,IAAI3T,EAQJ,OALCA,EADuB,iBAAZ2T,EACJhW,KAAKkV,SAAS9W,IAAK4X,GAEnBA,EAGDhW,KAAKiV,OAAOnC,QAASzQ,GAW7B,OAAQ4T,GACP,MAAQ5T,EAAMK,GAAU1C,KAAKkW,QAASD,GAQtC,OANAjW,KAAKqU,KAAM,SAAU,CACpBzB,MAAO,GACPkD,QAAS,CAAEzT,GACXK,UAGML,EAYR,IAAK6O,EAAUiF,GACd,OAAOnW,KAAKiV,OAAO5K,IAAK6G,EAAUiF,GAYnC,KAAMjF,EAAUiF,GACf,OAAOnW,KAAKiV,OAAOmB,KAAMlF,EAAUiF,GAYpC,OAAQjF,EAAUiF,GACjB,OAAOnW,KAAKiV,OAAOjR,OAAQkN,EAAUiF,GAUtC,QACMnW,KAAKqW,oBACTrW,KAAKsR,cAAetR,KAAKqW,mBACzBrW,KAAKqW,kBAAoB,MAG1B,MAAMC,EAAenN,MAAMiK,KAAMpT,KAAKiV,QAEtC,KAAQjV,KAAK+B,QACZ/B,KAAKkW,QAAS,GAGflW,KAAKqU,KAAM,SAAU,CACpBzB,MAAO,GACPkD,QAASQ,EACT5T,MAAO,IAqGT,OAAQ6T,GACP,GAAKvW,KAAKqW,kBAMT,MAAM,IAAI,KAAe,4BAA6BrW,MAKvD,OAFAA,KAAKqW,kBAAoBE,EAElB,CACNC,GAAIC,IACHzW,KAAK0W,oBAAqBrU,GAAQ,IAAIoU,EAAOpU,KAG9CsU,MAAOC,IAC4B,mBAAtBA,EACX5W,KAAK0W,oBAAqBrU,GAAQuU,EAAoBvU,IAEtDrC,KAAK0W,oBAAqBrU,GAAQA,EAAMuU,MAY5C,oBAAqB9Z,GACpB,MAAMyZ,EAAqBvW,KAAKqW,kBAK1BQ,EAAU,CAAEC,EAAKC,EAAcrU,KACpC,MAAMsU,EAAwBT,EAAmBF,mBAAqBrW,KAChEiX,EAAoBV,EAAmBhB,6BAA6BnX,IAAK2Y,GAM/E,GAAKC,GAAyBC,EAC7BjX,KAAKqV,6BAA6B5L,IAAKsN,EAAcE,GACrDjX,KAAKuV,6BAA6B9L,IAAKwN,EAAmBF,OACpD,CACN,MAAM1U,EAAOvF,EAASia,GAGtB,IAAM1U,EAGL,YAFArC,KAAKwV,4BAA4BvS,KAAMP,GAOxC,IAAIwU,EAAaxU,EAmBjB,IAAM,MAAMyU,KAAWnX,KAAKwV,4BACtB9S,EAAQyU,GACZD,IAiBF,IAAM,MAAMC,KAAWZ,EAAmBf,4BACpC0B,GAAcC,GAClBD,IAIFlX,KAAKqV,6BAA6B5L,IAAKsN,EAAc1U,GACrDrC,KAAKuV,6BAA6B9L,IAAKpH,EAAM0U,GAC7C/W,KAAK4O,IAAKvM,EAAM6U,GAIhB,IAAM,IAAI3Z,EAAI,EAAGA,EAAIgZ,EAAmBf,4BAA4BzT,OAAQxE,IACtE2Z,GAAcX,EAAmBf,4BAA6BjY,IAClEgZ,EAAmBf,4BAA6BjY,OAOpD,IAAM,MAAMwZ,KAAgBR,EAC3BM,EAAS,EAAME,EAAcR,EAAmBa,SAAUL,IAI3D/W,KAAKmR,SAAUoF,EAAoB,MAAOM,GAG1C7W,KAAKmR,SAAUoF,EAAoB,SAAU,CAAEO,EAAKC,EAAcrU,KACjE,MAAML,EAAOrC,KAAKqV,6BAA6BjX,IAAK2Y,GAE/C1U,GACJrC,KAAKmE,OAAQ9B,GAKdrC,KAAKwV,4BAA8BxV,KAAKwV,4BAA4B6B,OAAQ,CAAEvV,EAAQqV,KAChFzU,EAAQyU,GACZrV,EAAOmB,KAAMkU,EAAU,GAGnBzU,EAAQyU,GACZrV,EAAOmB,KAAMkU,GAGPrV,GACL,MAaL,uBAAwBO,GACvB,MAAM+S,EAAapV,KAAKmV,YACxB,IAAIS,EAEJ,GAAOR,KAAc/S,EAAS,CAG7B,GAFAuT,EAASvT,EAAM+S,GAEO,iBAAVQ,EAMX,MAAM,IAAI,KAAe,4BAA6B5V,MAGvD,GAAKA,KAAK5B,IAAKwX,GAMd,MAAM,IAAI,KAAe,qCAAsC5V,WAGhEqC,EAAM+S,GAAeQ,EAAS,KAG/B,OAAOA,EAaR,QAASK,GACR,IAAIvT,EAAOJ,EAAID,EACXiV,GAAmB,EACvB,MAAMlC,EAAapV,KAAKmV,YAyBxB,GAvBuB,iBAAXc,GACX3T,EAAK2T,EACL5T,EAAOrC,KAAKkV,SAAS9W,IAAKkE,GAC1BgV,GAAoBjV,EAEfA,IACJK,EAAQ1C,KAAKiV,OAAOnC,QAASzQ,KAED,iBAAX4T,GAClBvT,EAAQuT,EACR5T,EAAOrC,KAAKiV,OAAQvS,GACpB4U,GAAoBjV,EAEfA,IACJC,EAAKD,EAAM+S,MAGZ/S,EAAO4T,EACP3T,EAAKD,EAAM+S,GACX1S,EAAQ1C,KAAKiV,OAAOnC,QAASzQ,GAC7BiV,GAA+B,GAAV5U,IAAgB1C,KAAKkV,SAAS9W,IAAKkE,IAGpDgV,EAMJ,MAAM,IAAI,KAAe,wBAAyBtX,MAGnDA,KAAKiV,OAAOnP,OAAQpD,EAAO,GAC3B1C,KAAKkV,SAASnB,OAAQzR,GAEtB,MAAMyU,EAAe/W,KAAKuV,6BAA6BnX,IAAKiE,GAM5D,OALArC,KAAKuV,6BAA6BxB,OAAQ1R,GAC1CrC,KAAKqV,6BAA6BtB,OAAQgD,GAE1C/W,KAAKqU,KAAM,SAAUhS,EAAMK,GAEpB,CAAEL,EAAMK,GAQhB,CAAEpE,OAAOiW,YACR,OAAOvU,KAAKiV,OAAQ3W,OAAOiW,aA4B7BC,GAAK,GAAY,ICpuBF,MAAM,GAcpB,YAAa9U,EAAS6X,EAAmB,GAAIC,EAAiB,IAK7DxX,KAAKyX,SAAW/X,EAMhBM,KAAK0X,SAAW,IAAI5D,IAQpB9T,KAAK2X,kBAAoB,IAAI7D,IAE7B,IAAM,MAAM8D,KAAqBL,EAC3BK,EAAkBC,YACtB7X,KAAK2X,kBAAkBlO,IAAKmO,EAAkBC,WAAYD,GAU5D5X,KAAK8X,gBAAkB,IAAIhE,IAE3B,IAAM,MAAQ8D,EAAmBG,KAAoBP,EACpDxX,KAAK8X,gBAAgBrO,IAAKmO,EAAmBG,GAC7C/X,KAAK8X,gBAAgBrO,IAAKsO,EAAgBH,GAGrCA,EAAkBC,YACtB7X,KAAK2X,kBAAkBlO,IAAKmO,EAAkBC,WAAYD,GAY7D,EAAItZ,OAAOiW,YACV,IAAM,MAAM/K,KAASxJ,KAAK0X,SACC,mBAAdlO,EAAO,WACZA,GAwBT,IAAK1K,GACJ,MAAMkZ,EAAShY,KAAK0X,SAAStZ,IAAKU,GAElC,IAAMkZ,EAAS,CACd,IAAIH,EAAa/Y,EAoBjB,KAlBmB,mBAAPA,IACX+Y,EAAa/Y,EAAI+Y,YAAc/Y,EAAIhB,MAiB9B,IAAI,KAAe,qCAAsCkC,KAAKyX,SAAU,CAAEO,OAAQH,IAGzF,OAAOG,EAiBR,IAAKlZ,GACJ,OAAOkB,KAAK0X,SAAShO,IAAK5K,GAc3B,KAAMmZ,EAASC,EAAgB,IAC9B,MAAMC,EAAOnY,KACPN,EAAUM,KAAKyX,SACfW,EAAU,IAAIC,IACdC,EAAS,GAETC,EAAqBC,EAA4BP,GACjDQ,EAA2BD,EAA4BN,GACvDQ,EAwJN,SAAgCT,GAC/B,MAAMS,EAAiB,GAEvB,IAAM,MAAMC,KAA2BV,EAChCW,EAAsBD,IAC3BD,EAAezV,KAAM0V,GAIvB,OAAOD,EAAe3W,OAAS2W,EAAiB,KAjK1BG,CAAuBZ,GAE9C,GAAKS,EAAiB,CAsBrB,MAAMI,EAAU,oCAKhB,OAFA,aAAUA,EAAS,CAAEb,QAASS,IAEvBK,QAAQC,OAAQ,IAAI,KAAeF,EAASpZ,EAAS,CAAEuY,QAASS,KAGxE,OAAOK,QAAQ9X,IAAKsX,EAAmBlO,IAAK4O,IAC1CC,KAAM,IAAMC,EAAab,EAAQ,SACjCY,KAAM,IAAMC,EAAab,EAAQ,cACjCY,KAAM,IAAMZ,GAEd,SAASW,EAAYrB,GACpB,IAAKa,EAAyBW,SAAUxB,KAKnCO,EAAKT,SAAShO,IAAKkO,KAAuBQ,EAAQ1O,IAAKkO,GAI5D,OA0CD,SAA4BA,GAC3B,OAAO,IAAImB,QAAS/L,IACnBoL,EAAQxJ,IAAKgJ,GAERA,EAAkByB,UACtBzB,EAAkByB,SAAS5V,QAAS6V,IACnC,MAAMC,EAA4BX,EAAsBU,GAExD,GAAK1B,EAAkB4B,kBAAoBD,EAA0BC,gBAapE,MAAM,IAAI,KACT,oCACA,KACA,CAAExB,OAAQuB,EAA0Bzb,KAAM2b,WAAY7B,EAAkB9Z,OAI1E,GAAKoa,EAAckB,SAAUG,GAQ5B,MAAM,IAAI,KACT,4BACA7Z,EACA,CAAEsY,OAAQuB,EAA0Bzb,KAAM2b,WAAY7B,EAAkB9Z,OAI1Emb,EAAYM,KAId,MAAMvB,EAASG,EAAKL,gBAAgB1Z,IAAKwZ,IAAuB,IAAIA,EAAmBlY,GACvFyY,EAAKuB,KAAM9B,EAAmBI,GAC9BM,EAAOrV,KAAM+U,GAEbhL,MA7FM2M,CAAmB/B,GACxBgC,MAAO1Z,IAuBP,MAFA,aAAU,wBAAyB,CAAE8X,OAAQJ,IAEvC1X,IAIT,SAASiZ,EAAaU,EAAeC,GACpC,OAAOD,EAAcxC,OAAQ,CAAE0C,EAAS/B,IACjCA,EAAQ8B,GAIT3B,EAAKL,gBAAgBpO,IAAKsO,GACvB+B,EAGDA,EAAQb,KAAMlB,EAAQ8B,GAAS/a,KAAMiZ,IAPpC+B,EAQNhB,QAAQ/L,WA0DZ,SAAS4L,EAAsBoB,GAC9B,MAAuC,mBAA3BA,EACJA,EAGD7B,EAAKR,kBAAkBvZ,IAAK4b,GAepC,SAASxB,EAA4BP,GACpC,OAAOA,EACL5N,IAAKsO,GAA2BC,EAAsBD,IACtD3U,OAAQ4T,KAAuBA,IASnC,UACC,MAAMqC,EAAW,GAEjB,IAAM,MAAQ,CAAElC,KAAoB/X,KACG,mBAA1B+X,EAAemC,SAA0Bla,KAAK8X,gBAAgBpO,IAAKqO,IAC9EkC,EAAShX,KAAM8U,EAAemC,WAIhC,OAAOnB,QAAQ9X,IAAKgZ,GAUrB,KAAMrC,EAAmBI,GACxBhY,KAAK0X,SAASjO,IAAKmO,EAAmBI,GAEtC,MAAMH,EAAaD,EAAkBC,WAErC,GAAMA,EAAN,CAIA,GAAK7X,KAAK0X,SAAShO,IAAKmO,GA+BvB,MAAM,IAAI,KACT,wCACA,KACA,CAAEA,aAAYsC,QAASna,KAAK0X,SAAStZ,IAAKyZ,GAAanQ,YAAa0S,QAASxC,IAI/E5X,KAAK0X,SAASjO,IAAKoO,EAAYG,KCvZlB,SAASqC,GAAS1a,GAChC,OAAOwJ,MAAMgC,QAASxL,GAASA,EAAO,CAAEA,GCyHlC,SAAS2a,GAAYC,EAAUla,EAASma,EAAW,GACzD,GAAyB,iBAAbA,EAQX,MAAM,IAAI,KAAe,4CAA6C,KAAM,CAAEA,aAG/E,MAAMC,EAkDCxc,OAAOuF,KAAMrG,OAAOud,uBAAwB3Y,OAhDxB,IAAtB0Y,IAGJF,EAAWtc,OAAOuF,KAAMrG,OAAOud,uBAAyB,IAGzD,MAAMC,EAAYta,EAAQiC,IAAMjC,EAAQua,OAExC,GAA2B,IAAtBH,IAgCN,SAAyBF,EAAUI,GAClC,QACGxd,OAAOud,sBAAuBH,MAC9Bpd,OAAOud,sBAAuBH,GAAWM,WAAYF,GAnCvBG,CAAgBP,EAAUI,GAC1D,OAAkB,IAAbH,EAEGna,EAAQ0a,OAGT1a,EAAQua,OAGhB,MAAMC,EAAa1d,OAAOud,sBAAuBH,GAAWM,WACtDG,EAAgB7d,OAAOud,sBAAuBH,GAAWS,eAAiB,CAAEhc,GAAW,IAANA,EAAU,EAAI,GAErG,GAAwC,iBAA5B6b,EAAYF,GACvB,OAAOE,EAAYF,GAGpB,MAAMM,EAAkBC,OAAQF,EAAeR,IAG/C,OAAOK,EAAYF,GAAaM,GFwPjCzG,GAAK,GAAkB,IE5ZjBrX,OAAOud,wBACZvd,OAAOud,sBAAwB,ICDhC,MAAMS,GAAqB,CAAE,KAAM,KAAM,KAAM,KAAM,MAKtC,MAAM,GAYpB,YAAajZ,EAAU,IAUtBlC,KAAKob,WAAalZ,EAAQkZ,YAAc,KAWxCpb,KAAKqb,gBAAkBnZ,EAAQmZ,iBAAmBrb,KAAKob,WAQvDpb,KAAKsb,oBAAsBC,GAAsBvb,KAAKob,YAgBtDpb,KAAKwb,yBAA2BD,GAAsBvb,KAAKqb,iBA4C3Drb,KAAKvB,EAAI,CAAE4B,EAASgM,IAAYrM,KAAKyb,GAAIpb,EAASgM,GAYnD,eAYC,OALA7L,QAAQC,KACP,iMAIMT,KAAKob,WAWb,GAAI/a,EAASgM,EAAS,IACrBA,EAASgO,GAAShO,GAEM,iBAAZhM,IACXA,EAAU,CAAEua,OAAQva,IAGrB,MACMma,IADkBna,EAAQ0a,OACC1O,EAAQ,GAAM,EAI/C,OAKF,SAA4BuO,EAAQvO,GACnC,OAAOuO,EAAO1Q,QAAS,UAAW,CAAEwR,EAAOhZ,IACjCA,EAAQ2J,EAAOtK,OAAWsK,EAAQ3J,GAAUgZ,GAP9CC,CAFkBrB,GAAYta,KAAKob,WAAY/a,EAASma,GAEnBnO,IAe9C,SAASkP,GAAsBK,GAC9B,OAAOT,GAAmB/B,SAAUwC,GAAiB,MAAQ,MC7I/C,MAAM,GAQpB,YAAaC,GAOZ7b,KAAK6b,OAAS,IAAI,GAAQA,EAAQ7b,KAAK0H,YAAYoU,eAEnD,MAAMvE,EAAmBvX,KAAK0H,YAAYqU,eAE1C/b,KAAK6b,OAAO5e,OAAQ,UAAWsa,GAQ/BvX,KAAKiY,QAAU,IAAI,GAAkBjY,KAAMuX,GAE3C,MAAMyE,EAAiBhc,KAAK6b,OAAOzd,IAAK,aAAgB,GAMxD4B,KAAKic,OAAS,IAAI,GAAQ,CACzBb,WAAsC,iBAAnBY,EAA8BA,EAAiBA,EAAeE,GACjFb,gBAAiBrb,KAAK6b,OAAOzd,IAAK,sBASnC4B,KAAKvB,EAAIuB,KAAKic,OAAOxd,EAQrBuB,KAAKmc,QAAU,IAAI,GAWnBnc,KAAKoc,cAAgB,KAStB,cACC,MAAMnE,EAAUjY,KAAK6b,OAAOzd,IAAK,YAAe,GAEhD,IAAM,MAAMie,KAAUpE,EAAU,CAC/B,GAAsB,mBAAVoE,EAMX,MAAM,IAAI,KACT,uCACA,KACA,CAAEA,WAIJ,IAAgC,IAA3BA,EAAO7C,gBAOX,MAAM,IAAI,KACT,qCACA,KACA,CAAE6C,WAKL,OAAOrc,KAAKiY,QAAQqE,KAAMrE,GAS3B,UACC,OAAOc,QAAQ9X,IAAKkI,MAAMiK,KAAMpT,KAAKmc,QAASI,GAAUA,EAAOrC,YAC7DhB,KAAM,IAAMlZ,KAAKiY,QAAQiC,WAe5B,WAAYqC,EAAQC,GACnB,GAAKxc,KAAKoc,cAMT,MAAM,IAAI,KAAe,qCAG1Bpc,KAAKmc,QAAQvN,IAAK2N,GAEbC,IACJxc,KAAKoc,cAAgBG,GAcvB,cAAeA,GAKd,OAJKvc,KAAKmc,QAAQzS,IAAK6S,IACtBvc,KAAKmc,QAAQhY,OAAQoY,GAGjBvc,KAAKoc,gBAAkBG,EACpBvc,KAAKka,UAGNnB,QAAQ/L,UAchB,mBACC,MAAMlL,EAAS,GAEf,IAAM,MAAMhE,KAAQkC,KAAK6b,OAAOY,QACzB,CAAE,UAAW,gBAAiB,gBAAiBrD,SAAUtb,KAC9DgE,EAAQhE,GAASkC,KAAK6b,OAAOzd,IAAKN,IAIpC,OAAOgE,EAoDR,cAAe+Z,GACd,OAAO,IAAI9C,QAAS/L,IACnB,MAAMtN,EAAU,IAAIM,KAAM6b,GAE1B7O,EAAStN,EAAQyZ,cAAcD,KAAM,IAAMxZ,OCxQ/B,SAASgd,GAAeC,EAAGC,GACzC,MAAMC,EAASzM,KAAK0M,IAAKH,EAAE5a,OAAQ6a,EAAE7a,QAErC,IAAM,IAAIxE,EAAI,EAAGA,EAAIsf,EAAQtf,IAC5B,GAAKof,EAAGpf,IAAOqf,EAAGrf,GAEjB,OAAOA,EAKT,OAAKof,EAAE5a,QAAU6a,EAAE7a,OAEX,OACI4a,EAAE5a,OAAS6a,EAAE7a,OAEjB,SAGA,YCTM,OAJf,SAAevD,GACb,OAAO,GAAUA,EA7BM,ICwBV,MAAM,GAOpB,YAAawC,GAOZhB,KAAKgB,SAAWA,EAQhBhB,KAAK+c,OAAS,KAYf,YACC,IAAIC,EAEJ,IAAMhd,KAAK+c,OACV,OAAO,KAIR,IAAqD,IAA9CC,EAAMhd,KAAK+c,OAAOE,cAAejd,OAMvC,MAAM,IAAI,KAAe,gCAAiCA,MAG3D,OAAOgd,EASR,kBACC,MAAMta,EAAQ1C,KAAK0C,MAEnB,OAAmB,OAAVA,GAAkB1C,KAAK+c,OAAOG,SAAUxa,EAAQ,IAAS,KASnE,sBACC,MAAMA,EAAQ1C,KAAK0C,MAEnB,OAAmB,OAAVA,GAAkB1C,KAAK+c,OAAOG,SAAUxa,EAAQ,IAAS,KASnE,WACC,IAAI7F,EAAOmD,KAEX,KAAQnD,EAAKkgB,QACZlgB,EAAOA,EAAKkgB,OAGb,OAAOlgB,EAQR,aACC,OAAOmD,KAAKnD,KAAKsD,GAAI,eAkBtB,UACC,MAAM0P,EAAO,GACb,IAAI0C,EAAOvS,KAEX,KAAQuS,EAAKwK,QACZlN,EAAKsN,QAAS5K,EAAK7P,OACnB6P,EAAOA,EAAKwK,OAGb,OAAOlN,EAYR,aAAc3N,EAAU,CAAEkb,aAAa,EAAOC,aAAa,IAC1D,MAAMC,EAAY,GAClB,IAAIP,EAAS7a,EAAQkb,YAAcpd,KAAOA,KAAK+c,OAE/C,KAAQA,GACPO,EAAWpb,EAAQmb,YAAc,OAAS,WAAaN,GACvDA,EAASA,EAAOA,OAGjB,OAAOO,EAaR,kBAAmB/K,EAAMrQ,EAAU,IAClC,MAAMqb,EAAavd,KAAKwd,aAActb,GAChCub,EAAalL,EAAKiL,aAActb,GAEtC,IAAI3E,EAAI,EAER,KAAQggB,EAAYhgB,IAAOkgB,EAAYlgB,IAAOggB,EAAYhgB,IACzDA,IAGD,OAAa,IAANA,EAAU,KAAOggB,EAAYhgB,EAAI,GAUzC,SAAUgV,GAET,GAAKvS,MAAQuS,EACZ,OAAO,EAIR,GAAKvS,KAAKnD,OAAS0V,EAAK1V,KACvB,OAAO,EAGR,MAAM6gB,EAAW1d,KAAK2d,UAChBC,EAAWrL,EAAKoL,UAEhB7b,EAAS4a,GAAegB,EAAUE,GAExC,OAAS9b,GACR,IAAK,SACJ,OAAO,EAER,IAAK,YACJ,OAAO,EAER,QACC,OAAO4b,EAAU5b,GAAW8b,EAAU9b,IAWzC,QAASyQ,GAER,OAAKvS,MAAQuS,IAKRvS,KAAKnD,OAAS0V,EAAK1V,OAKhBmD,KAAK6d,SAAUtL,IAQxB,UACCvS,KAAK+c,OAAOe,gBAAiB9d,KAAK0C,OASnC,YAAazC,EAAMsS,GAClBvS,KAAKqU,KAAM,UAAYpU,EAAMsS,GAExBvS,KAAK+c,QACT/c,KAAK+c,OAAOgB,YAAa9d,EAAMsS,GASjC,SACC,MAAMyL,EAAO,GAAOhe,MAKpB,cAFOge,EAAKjB,OAELiB,EA+CR,GAAI/d,GACH,MAAgB,SAATA,GAA4B,cAATA,GAkD5BuU,GAAK,GAAM,IChXI,MAAM,WAAa,GAQjC,YAAaxT,EAAUrB,GACtBC,MAAOoB,GAUPhB,KAAKie,UAAYte,EAuBlB,GAAIM,GACH,MAAgB,UAATA,GAA6B,eAATA,GAEjB,SAATA,GAA4B,cAATA,GAEV,SAATA,GAA4B,cAATA,EASrB,WACC,OAAOD,KAAKie,UAqBb,YACC,OAAOje,KAAKL,KAGb,UAAWA,GACVK,KAAK+d,YAAa,OAAQ/d,MAE1BA,KAAKie,UAAYte,EAUlB,UAAWue,GACV,OAAQA,aAAqB,KAItBle,OAASke,GAAale,KAAKL,OAASue,EAAUve,MAStD,SACC,OAAO,IAAI,GAAMK,KAAKgB,SAAUhB,KAAKL,OCrGxB,MAAM,GAWpB,YAAawe,EAAUC,EAAcrc,GASpC,GAFA/B,KAAKme,SAAWA,EAEXC,EAAe,GAAKA,EAAeD,EAASxe,KAAKoC,OAMrD,MAAM,IAAI,KAAe,oCAAqC/B,MAG/D,GAAK+B,EAAS,GAAKqc,EAAerc,EAASoc,EAASxe,KAAKoC,OAMxD,MAAM,IAAI,KAAe,8BAA+B/B,MASzDA,KAAKL,KAAOwe,EAASxe,KAAK0e,UAAWD,EAAcA,EAAerc,GAQlE/B,KAAKoe,aAAeA,EASrB,iBACC,OAAOpe,KAAKL,KAAKoC,OAclB,gBACC,OAAO/B,KAAKL,KAAKoC,SAAW/B,KAAKme,SAASxe,KAAKoC,OAShD,aACC,OAAO/B,KAAKme,SAASpB,OAStB,WACC,OAAO/c,KAAKme,SAASthB,KAUtB,eACC,OAAOmD,KAAKme,SAASnd,SAqBtB,GAAIf,GACH,MAAgB,eAATA,GAAkC,oBAATA,GAEtB,cAATA,GAAiC,mBAATA,EAY1B,aAAciC,EAAU,CAAEkb,aAAa,EAAOC,aAAa,IAC1D,MAAMC,EAAY,GAClB,IAAIP,EAAS7a,EAAQkb,YAAcpd,KAAKme,SAAWne,KAAK+c,OAExD,KAAmB,OAAXA,GACPO,EAAWpb,EAAQmb,YAAc,OAAS,WAAaN,GACvDA,EAASA,EAAOA,OAGjB,OAAOO,GClKM,SAASgB,GAAO3e,GAC9B,OAAK2U,GAAY3U,GACT,IAAImU,IAAKnU,GCJH,SAAsBgD,GACpC,MAAM0H,EAAM,IAAIyJ,IAEhB,IAAM,MAAMhV,KAAO6D,EAClB0H,EAAIZ,IAAK3K,EAAK6D,EAAK7D,IAGpB,OAAOuL,EDDCkU,CAAa5e,GEbP,MAAM6e,GAOpB,eAAgBC,GAKfze,KAAK0e,UAAY,GAEjB1e,KAAK4O,OAAQ6P,GAwCd,OAAQA,GACP,IAAM,IAAIpc,KAAQoc,GAEG,iBAARpc,GAAoBA,aAAgB4H,UAC/C5H,EAAO,CAAEvE,KAAMuE,IAIXA,EAAKsc,UAAoC,iBAAhBtc,EAAKsc,SAAuBtc,EAAKsc,mBAAmB1U,UACjF5H,EAAKsc,QAAU,CAAEtc,EAAKsc,UAGvB3e,KAAK0e,UAAUzb,KAAMZ,GAiCvB,SAAUuc,GACT,IAAM,MAAMC,KAAiBD,EAC5B,IAAM,MAAMH,KAAWze,KAAK0e,UAAY,CACvC,MAAMhD,EAAQoD,GAAmBD,EAAeJ,GAEhD,GAAK/C,EACJ,MAAO,CACNkD,QAASC,EACTJ,UACA/C,SAMJ,OAAO,KAaR,YAAakD,GACZ,MAAMG,EAAU,GAEhB,IAAM,MAAMF,KAAiBD,EAC5B,IAAM,MAAMH,KAAWze,KAAK0e,UAAY,CACvC,MAAMhD,EAAQoD,GAAmBD,EAAeJ,GAE3C/C,GACJqD,EAAQ9b,KAAM,CACb2b,QAASC,EACTJ,UACA/C,UAMJ,OAAOqD,EAAQhd,OAAS,EAAIgd,EAAU,KASvC,iBACC,GAA+B,IAA1B/e,KAAK0e,UAAU3c,OACnB,OAAO,KAGR,MAAM0c,EAAUze,KAAK0e,UAAW,GAC1B5gB,EAAO2gB,EAAQ3gB,KAErB,MAA2B,mBAAX2gB,IAAyB3gB,GAAWA,aAAgBmM,OAAoB,KAAPnM,GAUnF,SAASghB,GAAmBF,EAASH,GAEpC,GAAuB,mBAAXA,EACX,OAAOA,EAASG,GAGjB,MAAMlD,EAAQ,GAEd,OAAK+C,EAAQ3gB,OACZ4d,EAAM5d,KA0CR,SAAoB2gB,EAAS3gB,GAE5B,GAAK2gB,aAAmBxU,OACvB,OAAOwU,EAAQtU,KAAMrM,GAGtB,OAAO2gB,IAAY3gB,EAhDLkhB,CAAWP,EAAQ3gB,KAAM8gB,EAAQ9gB,OAExC4d,EAAM5d,OAMR2gB,EAAQnb,aACZoY,EAAMpY,WAgDR,SAA0B2b,EAAUL,GACnC,MAAMlD,EAAQ,GAEd,IAAM,MAAM5d,KAAQmhB,EAAW,CAC9B,MAAMR,EAAUQ,EAAUnhB,GAE1B,IAAK8gB,EAAQM,aAAcphB,GAiB1B,OAAO,KAjB4B,CACnC,MAAMqhB,EAAYP,EAAQQ,aAActhB,GAExC,IAAiB,IAAZ2gB,EACJ/C,EAAMzY,KAAMnF,QACN,GAAK2gB,aAAmBxU,OAAS,CACvC,IAAKwU,EAAQtU,KAAMgV,GAGlB,OAAO,KAFPzD,EAAMzY,KAAMnF,OAIP,IAAKqhB,IAAcV,EAGzB,OAAO,KAFP/C,EAAMzY,KAAMnF,KASf,OAAO4d,EA3Ea2D,CAAiBZ,EAAQnb,WAAYsb,IAElDlD,EAAMpY,YARJ,OAcJmb,EAAQE,UACZjD,EAAMiD,QA0ER,SAAuBM,EAAUL,GAChC,MAAMlD,EAAQ,GAEd,IAAM,MAAM+C,KAAWQ,EACtB,GAAKR,aAAmBxU,OAAS,CAChC,MAAM0U,EAAUC,EAAQU,gBAExB,IAAM,MAAMxhB,KAAQ6gB,EACdF,EAAQtU,KAAMrM,IAClB4d,EAAMzY,KAAMnF,GAId,GAAsB,IAAjB4d,EAAM3Z,OACV,OAAO,SAEF,KAAK6c,EAAQW,SAAUd,GAG7B,OAAO,KAFP/C,EAAMzY,KAAMwb,GAMd,OAAO/C,EAjGU8D,CAAcf,EAAQE,QAASC,IAEzClD,EAAMiD,cAMRF,EAAQgB,SACZ/D,EAAM+D,OAiGR,SAAsBR,EAAUL,GAC/B,MAAMlD,EAAQ,GAEd,IAAM,MAAM5d,KAAQmhB,EAAW,CAC9B,MAAMR,EAAUQ,EAAUnhB,GAE1B,IAAK8gB,EAAQc,SAAU5hB,GAetB,OAAO,KAfwB,CAC/B,MAAMsF,EAAQwb,EAAQe,SAAU7hB,GAEhC,GAAK2gB,aAAmBxU,OAAS,CAChC,IAAKwU,EAAQtU,KAAM/G,GAGlB,OAAO,KAFPsY,EAAMzY,KAAMnF,OAIP,IAAKsF,IAAUqb,EAGrB,OAAO,KAFP/C,EAAMzY,KAAMnF,KASf,OAAO4d,EA1HSkE,CAAanB,EAAQgB,OAAQb,IAEtClD,EAAM+D,UAKN/D,GCvMO,OALf,SAAkBld,GAChB,MAAuB,iBAATA,GACX,EAAaA,IArBF,mBAqBY,EAAWA,ICrBnCqhB,GAAe,mDACfC,GAAgB,QAuBL,OAbf,SAAethB,EAAOS,GACpB,GAAI,GAAQT,GACV,OAAO,EAET,IAAIyB,SAAczB,EAClB,QAAY,UAARyB,GAA4B,UAARA,GAA4B,WAARA,GAC/B,MAATzB,IAAiB,GAASA,MAGvBshB,GAAc3V,KAAK3L,KAAWqhB,GAAa1V,KAAK3L,IAC1C,MAAVS,GAAkBT,KAASP,OAAOgB,KCwBvC,SAAS8gB,GAAQzX,EAAM0X,GACrB,GAAmB,mBAAR1X,GAAmC,MAAZ0X,GAAuC,mBAAZA,EAC3D,MAAM,IAAIC,UAhDQ,uBAkDpB,IAAIC,EAAW,WACb,IAAI7O,EAAOnG,UACPpM,EAAMkhB,EAAWA,EAAS3M,MAAMrT,KAAMqR,GAAQA,EAAK,GACnD8O,EAAQD,EAASC,MAErB,GAAIA,EAAMzW,IAAI5K,GACZ,OAAOqhB,EAAM/hB,IAAIU,GAEnB,IAAIgD,EAASwG,EAAK+K,MAAMrT,KAAMqR,GAE9B,OADA6O,EAASC,MAAQA,EAAM1W,IAAI3K,EAAKgD,IAAWqe,EACpCre,GAGT,OADAoe,EAASC,MAAQ,IAAKJ,GAAQK,OAAS,IAChCF,EAITH,GAAQK,MAAQ,GAED,UC/CA,ICtBXC,GAAa,mGAGbC,GAAe,WAoBJ,GDbf,SAAuBhY,GACrB,IAAIxG,EAAS,GAAQwG,GAAM,SAASxJ,GAIlC,OAfmB,MAYfqhB,EAAMnX,MACRmX,EAAM5W,QAEDzK,KAGLqhB,EAAQre,EAAOqe,MACnB,OAAOre,ECPU,EAAc,SAAS8Y,GACxC,IAAI9Y,EAAS,GAOb,OAN6B,KAAzB8Y,EAAO2F,WAAW,IACpBze,EAAOmB,KAAK,IAEd2X,EAAO1Q,QAAQmW,IAAY,SAAS3E,EAAO8E,EAAQC,EAAOC,GACxD5e,EAAOmB,KAAKwd,EAAQC,EAAUxW,QAAQoW,GAAc,MAASE,GAAU9E,MAElE5Z,KCHM,OAXf,SAAkBoH,EAAOwB,GAKvB,IAJA,IAAIhI,GAAS,EACTX,EAAkB,MAATmH,EAAgB,EAAIA,EAAMnH,OACnCD,EAASqH,MAAMpH,KAEVW,EAAQX,GACfD,EAAOY,GAASgI,EAASxB,EAAMxG,GAAQA,EAAOwG,GAEhD,OAAOpH,GCRL,GAAc,EAAS,EAAO3C,eAAYmH,EAC1Cqa,GAAiB,GAAc,GAAYjb,cAAWY,EA0B3C,OAhBf,SAASsa,EAAapiB,GAEpB,GAAoB,iBAATA,EACT,OAAOA,EAET,GAAI,GAAQA,GAEV,OAAO,GAASA,EAAOoiB,GAAgB,GAEzC,GAAI,GAASpiB,GACX,OAAOmiB,GAAiBA,GAAejjB,KAAKc,GAAS,GAEvD,IAAIsD,EAAUtD,EAAQ,GACtB,MAAkB,KAAVsD,GAAkB,EAAItD,IA3BjB,IA2BwC,KAAOsD,GCN/C,OAJf,SAAkBtD,GAChB,OAAgB,MAATA,EAAgB,GAAK,GAAaA,ICJ5B,OAPf,SAAkBA,EAAOS,GACvB,OAAI,GAAQT,GACHA,EAEF,GAAMA,EAAOS,GAAU,CAACT,GAAS,GAAa,GAASA,KCEjD,OALf,SAAc0K,GACZ,IAAInH,EAAkB,MAATmH,EAAgB,EAAIA,EAAMnH,OACvC,OAAOA,EAASmH,EAAMnH,EAAS,QAAKuE,GCIvB,OARf,SAAe9H,GACb,GAAoB,iBAATA,GAAqB,GAASA,GACvC,OAAOA,EAET,IAAIsD,EAAUtD,EAAQ,GACtB,MAAkB,KAAVsD,GAAkB,EAAItD,IAdjB,IAcwC,KAAOsD,GCM/C,OAZf,SAAiB7C,EAAQ4Q,GAMvB,IAHA,IAAInN,EAAQ,EACRX,GAHJ8N,EAAO,GAASA,EAAM5Q,IAGJ8C,OAED,MAAV9C,GAAkByD,EAAQX,GAC/B9C,EAASA,EAAO,GAAM4Q,EAAKnN,OAE7B,OAAQA,GAASA,GAASX,EAAU9C,OAASqH,GCUhC,OArBf,SAAmB4C,EAAO2X,EAAOC,GAC/B,IAAIpe,GAAS,EACTX,EAASmH,EAAMnH,OAEf8e,EAAQ,IACVA,GAASA,EAAQ9e,EAAS,EAAKA,EAAS8e,IAE1CC,EAAMA,EAAM/e,EAASA,EAAS+e,GACpB,IACRA,GAAO/e,GAETA,EAAS8e,EAAQC,EAAM,EAAMA,EAAMD,IAAW,EAC9CA,KAAW,EAGX,IADA,IAAI/e,EAASqH,MAAMpH,KACVW,EAAQX,GACfD,EAAOY,GAASwG,EAAMxG,EAAQme,GAEhC,OAAO/e,GCZM,OAJf,SAAgB7C,EAAQ4Q,GACtB,OAAOA,EAAK9N,OAAS,EAAI9C,EAAS,GAAQA,EAAQ,GAAU4Q,EAAM,GAAI,KCOzD,OANf,SAAmB5Q,EAAQ4Q,GAGzB,OAFAA,EAAO,GAASA,EAAM5Q,GAEL,OADjBA,EAAS,GAAOA,EAAQ4Q,YACQ5Q,EAAO,GAAM,GAAK4Q,MCiBrC,OAJf,SAAe5Q,EAAQ4Q,GACrB,OAAiB,MAAV5Q,GAAwB,GAAUA,EAAQ4Q,ICEpC,OALf,SAAa5Q,EAAQ4Q,EAAMkR,GACzB,IAAIjf,EAAmB,MAAV7C,OAAiBqH,EAAY,GAAQrH,EAAQ4Q,GAC1D,YAAkBvJ,IAAXxE,EAAuBif,EAAejf,GCVhC,OAPf,SAA0B7C,EAAQH,EAAKN,SACtB8H,IAAV9H,IAAwB,EAAGS,EAAOH,GAAMN,SAC9B8H,IAAV9H,KAAyBM,KAAOG,KACnC,GAAgBA,EAAQH,EAAKN,ICSlB,ICTA,GDRf,SAAuBwiB,GACrB,OAAO,SAAS/hB,EAAQyL,EAAU6B,GAMhC,IALA,IAAI7J,GAAS,EACTue,EAAWhjB,OAAOgB,GAClB4L,EAAQ0B,EAAStN,GACjB8C,EAAS8I,EAAM9I,OAEZA,KAAU,CACf,IAAIjD,EAAM+L,EAAMmW,EAAYjf,IAAWW,GACvC,IAA+C,IAA3CgI,EAASuW,EAASniB,GAAMA,EAAKmiB,GAC/B,MAGJ,OAAOhiB,GCPG,GCmBC,OAJf,SAA2BT,GACzB,OAAO,EAAaA,IAAU,GAAYA,ICT7B,OAZf,SAAiBS,EAAQH,GACvB,IAAY,gBAARA,GAAgD,mBAAhBG,EAAOH,KAIhC,aAAPA,EAIJ,OAAOG,EAAOH,ICcD,OAJf,SAAuBN,GACrB,OAAO,GAAWA,EAAO,GAAOA,KCiEnB,OA9Df,SAAuBS,EAAQ2L,EAAQ9L,EAAKoiB,EAAUC,EAAWrW,EAAYxK,GAC3E,IAAIqK,EAAW,GAAQ1L,EAAQH,GAC3BsiB,EAAW,GAAQxW,EAAQ9L,GAC3B4P,EAAUpO,EAAMlC,IAAIgjB,GAExB,GAAI1S,EACF,GAAiBzP,EAAQH,EAAK4P,OADhC,CAIA,IAAI1D,EAAWF,EACXA,EAAWH,EAAUyW,EAAWtiB,EAAM,GAAKG,EAAQ2L,EAAQtK,QAC3DgG,EAEA+a,OAAwB/a,IAAb0E,EAEf,GAAIqW,EAAU,CACZ,IAAI5V,EAAQ,GAAQ2V,GAChBzV,GAAUF,GAAS,OAAAlF,GAAA,GAAS6a,GAC5BE,GAAW7V,IAAUE,GAAU,GAAayV,GAEhDpW,EAAWoW,EACP3V,GAASE,GAAU2V,EACjB,GAAQ3W,GACVK,EAAWL,EAEJ,GAAkBA,GACzBK,EAAW,GAAUL,GAEdgB,GACP0V,GAAW,EACXrW,EAAW,aAAYoW,GAAU,IAE1BE,GACPD,GAAW,EACXrW,EAAW,GAAgBoW,GAAU,IAGrCpW,EAAW,GAGN,EAAcoW,IAAa,GAAYA,IAC9CpW,EAAWL,EACP,GAAYA,GACdK,EAAW,GAAcL,GAEjB,EAASA,KAAa,EAAWA,KACzCK,EAAW,GAAgBoW,KAI7BC,GAAW,EAGXA,IAEF/gB,EAAMmJ,IAAI2X,EAAUpW,GACpBmW,EAAUnW,EAAUoW,EAAUF,EAAUpW,EAAYxK,GACpDA,EAAc,OAAE8gB,IAElB,GAAiBniB,EAAQH,EAAKkM,KCjDjB,OAtBf,SAASuW,EAAUtiB,EAAQ2L,EAAQsW,EAAUpW,EAAYxK,GACnDrB,IAAW2L,GAGf,GAAQA,GAAQ,SAASwW,EAAUtiB,GAEjC,GADAwB,IAAUA,EAAQ,IAAI,IAClB,EAAS8gB,GACX,GAAcniB,EAAQ2L,EAAQ9L,EAAKoiB,EAAUK,EAAWzW,EAAYxK,OAEjE,CACH,IAAI0K,EAAWF,EACXA,EAAW,GAAQ7L,EAAQH,GAAMsiB,EAAWtiB,EAAM,GAAKG,EAAQ2L,EAAQtK,QACvEgG,OAEaA,IAAb0E,IACFA,EAAWoW,GAEb,GAAiBniB,EAAQH,EAAKkM,MAE/B,KClBU,OAJf,SAAkBxM,GAChB,OAAOA,GCGM,OAVf,SAAe8J,EAAMkZ,EAASnQ,GAC5B,OAAQA,EAAKtP,QACX,KAAK,EAAG,OAAOuG,EAAK5K,KAAK8jB,GACzB,KAAK,EAAG,OAAOlZ,EAAK5K,KAAK8jB,EAASnQ,EAAK,IACvC,KAAK,EAAG,OAAO/I,EAAK5K,KAAK8jB,EAASnQ,EAAK,GAAIA,EAAK,IAChD,KAAK,EAAG,OAAO/I,EAAK5K,KAAK8jB,EAASnQ,EAAK,GAAIA,EAAK,GAAIA,EAAK,IAE3D,OAAO/I,EAAK+K,MAAMmO,EAASnQ,ICdzBoQ,GAAYrR,KAAKsR,IAgCN,OArBf,SAAkBpZ,EAAMuY,EAAOtY,GAE7B,OADAsY,EAAQY,QAAoBnb,IAAVua,EAAuBvY,EAAKvG,OAAS,EAAK8e,EAAO,GAC5D,WAML,IALA,IAAIxP,EAAOnG,UACPxI,GAAS,EACTX,EAAS0f,GAAUpQ,EAAKtP,OAAS8e,EAAO,GACxC3X,EAAQC,MAAMpH,KAETW,EAAQX,GACfmH,EAAMxG,GAAS2O,EAAKwP,EAAQne,GAE9BA,GAAS,EAET,IADA,IAAIif,EAAYxY,MAAM0X,EAAQ,KACrBne,EAAQme,GACfc,EAAUjf,GAAS2O,EAAK3O,GAG1B,OADAif,EAAUd,GAAStY,EAAUW,GACtB,GAAMZ,EAAMtI,KAAM2hB,KCNd,OANf,SAAkBnjB,GAChB,OAAO,WACL,OAAOA,ICAI,GATQ,GAA4B,SAAS8J,EAAMsS,GAChE,OAAO,GAAetS,EAAM,WAAY,CACtC,cAAgB,EAChB,YAAc,EACd,MAAS,GAASsS,GAClB,UAAY,KALwB,GCPpCgH,GAAYC,KAAKC,IA+BN,ICvBA,GDGf,SAAkBxZ,GAChB,IAAI9F,EAAQ,EACRuf,EAAa,EAEjB,OAAO,WACL,IAAIC,EAAQJ,KACRK,EApBO,IAoBiBD,EAAQD,GAGpC,GADAA,EAAaC,EACTC,EAAY,GACd,KAAMzf,GAzBI,IA0BR,OAAO0I,UAAU,QAGnB1I,EAAQ,EAEV,OAAO8F,EAAK+K,WAAM/M,EAAW4E,YCrBf,CAAS,ICKZ,OAJf,SAAkB5C,EAAMuY,GACtB,OAAO,GAAY,GAASvY,EAAMuY,EAAO,IAAWvY,EAAO,KCgB9C,OAdf,SAAwB9J,EAAOkE,EAAOzD,GACpC,IAAK,EAASA,GACZ,OAAO,EAET,IAAIgB,SAAcyC,EAClB,SAAY,UAARzC,EACK,GAAYhB,IAAW,GAAQyD,EAAOzD,EAAO8C,QACrC,UAAR9B,GAAoByC,KAASzD,IAE7B,EAAGA,EAAOyD,GAAQlE,ICYd,OA1Bf,SAAwB0jB,GACtB,OAAO,IAAS,SAASjjB,EAAQkjB,GAC/B,IAAIzf,GAAS,EACTX,EAASogB,EAAQpgB,OACjB+I,EAAa/I,EAAS,EAAIogB,EAAQpgB,EAAS,QAAKuE,EAChD8b,EAAQrgB,EAAS,EAAIogB,EAAQ,QAAK7b,EAWtC,IATAwE,EAAcoX,EAASngB,OAAS,GAA0B,mBAAd+I,GACvC/I,IAAU+I,QACXxE,EAEA8b,GAAS,GAAeD,EAAQ,GAAIA,EAAQ,GAAIC,KAClDtX,EAAa/I,EAAS,OAAIuE,EAAYwE,EACtC/I,EAAS,GAEX9C,EAAShB,OAAOgB,KACPyD,EAAQX,GAAQ,CACvB,IAAI6I,EAASuX,EAAQzf,GACjBkI,GACFsX,EAASjjB,EAAQ2L,EAAQlI,EAAOoI,GAGpC,OAAO7L,MCMI,GAJH,IAAe,SAASA,EAAQ2L,EAAQsW,GAClD,GAAUjiB,EAAQ2L,EAAQsW,MCWb,OA9Bf,SAAiBjiB,EAAQ4Q,EAAMrR,EAAOsM,GACpC,IAAK,EAAS7L,GACZ,OAAOA,EAST,IALA,IAAIyD,GAAS,EACTX,GAHJ8N,EAAO,GAASA,EAAM5Q,IAGJ8C,OACd2L,EAAY3L,EAAS,EACrBsgB,EAASpjB,EAEI,MAAVojB,KAAoB3f,EAAQX,GAAQ,CACzC,IAAIjD,EAAM,GAAM+Q,EAAKnN,IACjBsI,EAAWxM,EAEf,GAAIkE,GAASgL,EAAW,CACtB,IAAI/C,EAAW0X,EAAOvjB,QAELwH,KADjB0E,EAAWF,EAAaA,EAAWH,EAAU7L,EAAKujB,QAAU/b,KAE1D0E,EAAW,EAASL,GAChBA,EACC,GAAQkF,EAAKnN,EAAQ,IAAM,GAAK,IAGzC,GAAY2f,EAAQvjB,EAAKkM,GACzBqX,EAASA,EAAOvjB,GAElB,OAAOG,GCTM,OAJf,SAAaA,EAAQ4Q,EAAMrR,GACzB,OAAiB,MAAVS,EAAiBA,EAAS,GAAQA,EAAQ4Q,EAAMrR,ICf1C,MAAM,GAMpB,YAAa8jB,GAUZtiB,KAAKuiB,QAAU,GAQfviB,KAAKwiB,gBAAkBF,EAQxB,cACC,MAAMhZ,EAAUrL,OAAOqL,QAAStJ,KAAKuiB,SAGrC,OAFapZ,MAAMiK,KAAM9J,GAEZvH,OAQd,WACC,OAAK/B,KAAKyiB,QACF,EAGDziB,KAAK0iB,gBAAgB3gB,OAU7B,MAAO4gB,GACN3iB,KAAKuJ,QAEL,MAAMqZ,EAAezZ,MAAMiK,KAkrB7B,SAA4ByP,GAE3B,IAAIC,EAAY,KACZC,EAAoB,EACpBC,EAAqB,EACrBC,EAAe,KAEnB,MAAMC,EAAY,IAAIpP,IAGtB,GAAsB,KAAjB+O,EACJ,OAAOK,EAI+C,KAAlDL,EAAaM,OAAQN,EAAa9gB,OAAS,KAC/C8gB,GAA8B,KAI/B,IAAM,IAAItlB,EAAI,EAAGA,EAAIslB,EAAa9gB,OAAQxE,IAAM,CAC/C,MAAM6lB,EAAOP,EAAaM,OAAQ5lB,GAElC,GAAmB,OAAdulB,EAEJ,OAASM,GACR,IAAK,IAGEH,IAGLA,EAAeJ,EAAaxQ,OAAQ0Q,EAAmBxlB,EAAIwlB,GAE3DC,EAAqBzlB,EAAI,GAG1B,MAED,IAAK,IACL,IAAK,IAEJulB,EAAYM,EAEZ,MAED,IAAK,IAAK,CAGT,MAAMC,EAAgBR,EAAaxQ,OAAQ2Q,EAAoBzlB,EAAIylB,GAE9DC,GAEJC,EAAUzZ,IAAKwZ,EAAaK,OAAQD,EAAcC,QAGnDL,EAAe,KAGfF,EAAoBxlB,EAAI,EAExB,YAGS6lB,IAASN,IAEpBA,EAAY,MAId,OAAOI,EAxvB2BK,CAAmBZ,GAAcrZ,WAElE,IAAM,MAAQxK,EAAKN,KAAWokB,EAC7B5iB,KAAKwiB,gBAAgBgB,iBAAkB1kB,EAAKN,EAAOwB,KAAKuiB,SAgC1D,IAAKzkB,GACJ,GAAKkC,KAAKyiB,QACT,OAAO,EAGR,MAEMgB,EAFSzjB,KAAKwiB,gBAAgBkB,eAAgB5lB,EAAMkC,KAAKuiB,SAE7BnM,KAAM,EAAIlX,KAAgBA,IAAapB,GAGzE,OAAOqL,MAAMgC,QAASsY,GAoDvB,IAAKE,EAAcC,GAClB,GAAK,EAAUD,GACd,IAAM,MAAQ7kB,EAAKN,KAAWP,OAAOqL,QAASqa,GAC7C3jB,KAAKwiB,gBAAgBgB,iBAAkB1kB,EAAKN,EAAOwB,KAAKuiB,cAGzDviB,KAAKwiB,gBAAgBgB,iBAAkBG,EAAcC,EAAe5jB,KAAKuiB,SA4B3E,OAAQzkB,GACP,MAAM+R,EAAOgU,GAAQ/lB,GAErB,GAAOkC,KAAKuiB,QAAS1S,UACd7P,KAAKuiB,QAASzkB,GAErBkC,KAAK8jB,yBAA0BjU,GA4BhC,cAAe/R,GACd,OAAOkC,KAAKwiB,gBAAgBuB,cAAejmB,EAAMkC,KAAKuiB,SAyBvD,WACC,OAAKviB,KAAKyiB,QACF,GAGDziB,KAAKgkB,oBACV3Z,IAAK4Z,GAAOA,EAAIhgB,KAAM,MACtBigB,OACAjgB,KAAM,KAAQ,IAsDjB,YAAagf,GACZ,GAAKjjB,KAAKyiB,QACT,OAGD,GAAKziB,KAAKuiB,QAASU,KAAmB,EAAUjjB,KAAKuiB,QAASU,IAE7D,OAAOjjB,KAAKuiB,QAASU,GAGtB,MAEMQ,EAFSzjB,KAAKwiB,gBAAgBkB,eAAgBT,EAAcjjB,KAAKuiB,SAErCnM,KAAM,EAAIlX,KAAgBA,IAAa+jB,GAGzE,OAAK9Z,MAAMgC,QAASsY,GACZA,EAAoB,QAD5B,EAUD,gBACC,GAAKzjB,KAAKyiB,QACT,MAAO,GAKR,OAFgBziB,KAAKgkB,oBAEN3Z,IAAK,EAAIvL,KAAWA,GAMpC,QACCkB,KAAKuiB,QAAU,GAShB,oBACC,MAAM4B,EAAS,GAET3gB,EAAOvF,OAAOuF,KAAMxD,KAAKuiB,SAE/B,IAAM,MAAMzjB,KAAO0E,EAClB2gB,EAAOlhB,QAASjD,KAAKwiB,gBAAgBkB,eAAgB5kB,EAAKkB,KAAKuiB,UAGhE,OAAO4B,EASR,yBAA0BtU,GACzB,MAAMuU,EAAYvU,EAAKN,MAAO,KAG9B,KAFoB6U,EAAUriB,OAAS,GAGtC,OAGD,MAAMsiB,EAAaD,EAAUte,OAAQ,EAAGse,EAAUriB,OAAS,GAAIkC,KAAM,KAE/DqgB,EAAe,GAAKtkB,KAAKuiB,QAAS8B,GAExC,IAAMC,EACL,QAGsBnb,MAAMiK,KAAMnV,OAAOuF,KAAM8gB,IAAiBviB,QAGhE/B,KAAKmE,OAAQkgB,IAQT,MAAM,GAMZ,cACCrkB,KAAKukB,aAAe,IAAIzQ,IACxB9T,KAAKwkB,YAAc,IAAI1Q,IACvB9T,KAAKykB,UAAY,IAAI3Q,IACrB9T,KAAK0kB,aAAe,IAAI5Q,IAkBzB,iBAAkBhW,EAAMulB,EAAe5D,GACtC,GAAK,EAAU4D,GACdsB,GAAkBlF,EAAQoE,GAAQ/lB,GAAQulB,QAK3C,GAAKrjB,KAAKukB,aAAa7a,IAAK5L,GAAS,CACpC,MAAM8mB,EAAa5kB,KAAKukB,aAAanmB,IAAKN,IAEpC,KAAE+R,EAAI,MAAErR,GAAUomB,EAAYvB,GAEpCsB,GAAkBlF,EAAQ5P,EAAMrR,QAEhCmmB,GAAkBlF,EAAQ3hB,EAAMulB,GAuBlC,cAAevlB,EAAM2hB,GACpB,IAAM3hB,EACL,OAAO,GAAO,GAAI2hB,GAInB,QAAwBnZ,IAAnBmZ,EAAQ3hB,GACZ,OAAO2hB,EAAQ3hB,GAGhB,GAAKkC,KAAKwkB,YAAY9a,IAAK5L,GAAS,CACnC,MAAM+mB,EAAY7kB,KAAKwkB,YAAYpmB,IAAKN,GAExC,GAA0B,iBAAd+mB,EACX,OAAO,GAAKpF,EAAQoF,GAGrB,MAAMrmB,EAAQqmB,EAAW/mB,EAAM2hB,GAE/B,GAAKjhB,EACJ,OAAOA,EAIT,OAAO,GAAKihB,EAAQoE,GAAQ/lB,IAkC7B,eAAgBA,EAAM2hB,GACrB,MAAMqF,EAAkB9kB,KAAK+jB,cAAejmB,EAAM2hB,GAGlD,QAAyBnZ,IAApBwe,EACJ,MAAO,GAGR,GAAK9kB,KAAKykB,UAAU/a,IAAK5L,GAAS,CAGjC,OAFgBkC,KAAKykB,UAAUrmB,IAAKN,EAE7BinB,CAASD,GAGjB,MAAO,CAAE,CAAEhnB,EAAMgnB,IAkBlB,iBAAkBhnB,GACjB,OAAOkC,KAAK0kB,aAAatmB,IAAKN,IAAU,GAsDzC,cAAeA,EAAMoT,GACpBlR,KAAKukB,aAAa9a,IAAK3L,EAAMoT,GA0C9B,aAAcpT,EAAMknB,GACnBhlB,KAAKwkB,YAAY/a,IAAK3L,EAAMknB,GAoC7B,WAAYlnB,EAAMoT,GACjBlR,KAAKykB,UAAUhb,IAAK3L,EAAMoT,GAyB3B,iBAAkB+T,EAAeC,GAChCllB,KAAKmlB,eAAgBF,EAAeC,GAEpC,IAAM,MAAME,KAAYF,EACvBllB,KAAKmlB,eAAgBC,EAAU,CAAEH,IAWnC,eAAgBnnB,EAAMonB,GACfllB,KAAK0kB,aAAahb,IAAK5L,IAC5BkC,KAAK0kB,aAAajb,IAAK3L,EAAM,IAG9BkC,KAAK0kB,aAAatmB,IAAKN,GAAOmF,QAASiiB,IAkFzC,SAASrB,GAAQ/lB,GAChB,OAAOA,EAAKoM,QAAS,IAAK,KAQ3B,SAASya,GAAkBU,EAAcC,EAAY1B,GACpD,IAAI2B,EAAa3B,EAEZ,EAAUA,KACd2B,EAAa,GAAO,GAAI,GAAKF,EAAcC,GAAc1B,IAG1D,GAAKyB,EAAcC,EAAYC,GC7yBjB,MAAM,WAAgB,GAiBpC,YAAavkB,EAAUlD,EAAM0nB,EAAO1d,GAuCnC,GAtCAlI,MAAOoB,GAQPhB,KAAKlC,KAAOA,EAQZkC,KAAKylB,OAixBP,SAA0BD,GACzBA,EAAQlH,GAAOkH,GAEf,IAAM,MAAQ1mB,EAAKN,KAAWgnB,EACd,OAAVhnB,EACJgnB,EAAMzR,OAAQjV,GACa,iBAATN,GAClBgnB,EAAM/b,IAAK3K,EAAKgN,OAAQtN,IAI1B,OAAOgnB,EA5xBQE,CAAiBF,GAQ/BxlB,KAAK2lB,UAAY,GAEZ7d,GACJ9H,KAAK4lB,aAAc,EAAG9d,GASvB9H,KAAK6lB,SAAW,IAAIxN,IAEfrY,KAAKylB,OAAO/b,IAAK,SAAY,CAEjC,MAAMoc,EAAc9lB,KAAKylB,OAAOrnB,IAAK,SACrC2nB,GAAc/lB,KAAK6lB,SAAUC,GAC7B9lB,KAAKylB,OAAO1R,OAAQ,SASrB/T,KAAKuiB,QAAU,IAAI,GAAWviB,KAAKgB,SAASglB,iBAEvChmB,KAAKylB,OAAO/b,IAAK,WAErB1J,KAAKuiB,QAAQ0D,MAAOjmB,KAAKylB,OAAOrnB,IAAK,UAErC4B,KAAKylB,OAAO1R,OAAQ,UAUrB/T,KAAKkmB,kBAAoB,IAAIpS,IAS9B,iBACC,OAAO9T,KAAK2lB,UAAU5jB,OASvB,cACC,OAAiC,IAA1B/B,KAAK2lB,UAAU5jB,OA0BvB,GAAI9B,EAAMnC,EAAO,MAChB,OAAMA,EAKEA,IAASkC,KAAKlC,OAAmB,YAATmC,GAA+B,iBAATA,GAJrC,YAATA,GAA+B,iBAATA,GAEnB,SAATA,GAA4B,cAATA,EAYtB,SAAUyC,GACT,OAAO1C,KAAK2lB,UAAWjjB,GASxB,cAAe6P,GACd,OAAOvS,KAAK2lB,UAAU7S,QAASP,GAQhC,cACC,OAAOvS,KAAK2lB,UAAWrnB,OAAOiW,YAQ/B,oBACMvU,KAAK6lB,SAAS7c,KAAO,SACnB,SAGDhJ,KAAKuiB,QAAQE,eACZ,eAGAziB,KAAKylB,OAAOjiB,OAWpB,uBACQxD,KAAKylB,OAAOnc,UAEdtJ,KAAK6lB,SAAS7c,KAAO,SACnB,CAAE,QAAShJ,KAAKof,aAAc,WAG/Bpf,KAAKuiB,QAAQE,eACZ,CAAE,QAASziB,KAAKof,aAAc,WAUtC,aAActgB,GACb,GAAY,SAAPA,EACJ,OAAKkB,KAAK6lB,SAAS7c,KAAO,EAClB,IAAKhJ,KAAK6lB,UAAW5hB,KAAM,UAGnC,EAGD,GAAY,SAAPnF,EAAiB,CACrB,MAAM6jB,EAAc3iB,KAAKuiB,QAAQ7c,WAEjC,MAAsB,IAAfid,OAAoBrc,EAAYqc,EAGxC,OAAO3iB,KAAKylB,OAAOrnB,IAAKU,GASzB,aAAcA,GACb,MAAY,SAAPA,EACGkB,KAAK6lB,SAAS7c,KAAO,EAGjB,SAAPlK,GACIkB,KAAKuiB,QAAQE,QAGfziB,KAAKylB,OAAO/b,IAAK5K,GAWzB,UAAWqnB,GACV,KAAQA,aAAwB,IAC/B,OAAO,EAIR,GAAKnmB,OAASmmB,EACb,OAAO,EAIR,GAAKnmB,KAAKlC,MAAQqoB,EAAaroB,KAC9B,OAAO,EAIR,GAAKkC,KAAKylB,OAAOzc,OAASmd,EAAaV,OAAOzc,MAAQhJ,KAAK6lB,SAAS7c,OAASmd,EAAaN,SAAS7c,MAClGhJ,KAAKuiB,QAAQvZ,OAASmd,EAAa5D,QAAQvZ,KAC3C,OAAO,EAIR,IAAM,MAAQlK,EAAKN,KAAWwB,KAAKylB,OAClC,IAAMU,EAAaV,OAAO/b,IAAK5K,IAASqnB,EAAaV,OAAOrnB,IAAKU,KAAUN,EAC1E,OAAO,EAKT,IAAM,MAAM4nB,KAAapmB,KAAK6lB,SAC7B,IAAMM,EAAaN,SAASnc,IAAK0c,GAChC,OAAO,EAKT,IAAM,MAAMlnB,KAAYc,KAAKuiB,QAAQG,gBACpC,IACEyD,EAAa5D,QAAQ7Y,IAAKxK,IAC3BinB,EAAa5D,QAAQ8D,YAAannB,KAAec,KAAKuiB,QAAQ8D,YAAannB,GAE3E,OAAO,EAIT,OAAO,EAYR,YAAaknB,GACZ,IAAM,MAAMtoB,KAAQsoB,EACnB,IAAMpmB,KAAK6lB,SAASnc,IAAK5L,GACxB,OAAO,EAIT,OAAO,EAQR,gBACC,OAAOkC,KAAK6lB,SAASriB,OA6BtB,SAAUtE,GACT,OAAOc,KAAKuiB,QAAQ8D,YAAannB,GAiClC,mBAAoBA,GACnB,OAAOc,KAAKuiB,QAAQwB,cAAe7kB,GAQpC,gBACC,OAAOc,KAAKuiB,QAAQG,gBAYrB,YAAaxjB,GACZ,IAAM,MAAMpB,KAAQoB,EACnB,IAAMc,KAAKuiB,QAAQ7Y,IAAK5L,GACvB,OAAO,EAIT,OAAO,EAYR,gBAAiBmhB,GAChB,MAAMqH,EAAU,IAAI9H,MAAYS,GAChC,IAAIlC,EAAS/c,KAAK+c,OAElB,KAAQA,GAAS,CAChB,GAAKuJ,EAAQ5K,MAAOqB,GACnB,OAAOA,EAGRA,EAASA,EAAOA,OAGjB,OAAO,KASR,kBAAmBje,GAClB,OAAOkB,KAAKkmB,kBAAkB9nB,IAAKU,GASpC,6BACQkB,KAAKkmB,kBAAkB5c,UA0B/B,cACC,MAAMqV,EAAUxV,MAAMiK,KAAMpT,KAAK6lB,UAAW3B,OAAOjgB,KAAM,KACnDwb,EAASzf,KAAKuiB,QAAQ7c,WACtBpC,EAAa6F,MAAMiK,KAAMpT,KAAKylB,QAASpb,IAAK9M,GAAK,GAAIA,EAAG,OAAUA,EAAG,OAAU2mB,OAAOjgB,KAAM,KAElG,OAAOjE,KAAKlC,MACE,IAAX6gB,EAAgB,GAAK,WAAYA,OAChCc,EAAc,WAAYA,KAAjB,KACI,IAAdnc,EAAmB,GAAK,IAAKA,GAWjC,OAAQijB,GAAO,GACd,MAAMC,EAAgB,GAEtB,GAAKD,EACJ,IAAM,MAAME,KAASzmB,KAAK0mB,cACzBF,EAAcvjB,KAAMwjB,EAAME,OAAQJ,IAKpC,MAAMK,EAAS,IAAI5mB,KAAK0H,YAAa1H,KAAKgB,SAAUhB,KAAKlC,KAAMkC,KAAKylB,OAAQe,GAe5E,OAXAI,EAAOf,SAAW,IAAIxN,IAAKrY,KAAK6lB,UAChCe,EAAOrE,QAAQ9Y,IAAKzJ,KAAKuiB,QAAQwB,iBAGjC6C,EAAOV,kBAAoB,IAAIpS,IAAK9T,KAAKkmB,mBAKzCU,EAAOC,gBAAkB7mB,KAAK6mB,gBAEvBD,EAaR,aAAcjR,GACb,OAAO3V,KAAK4lB,aAAc5lB,KAAK8mB,WAAYnR,GAc5C,aAAcjT,EAAOiT,GACpB3V,KAAK+d,YAAa,WAAY/d,MAC9B,IAAIwC,EAAQ,EAEZ,MAAMukB,EAwRR,SAAoB/lB,EAAU+lB,GAE7B,GAAqB,iBAATA,EACX,MAAO,CAAE,IAAI,GAAM/lB,EAAU+lB,IAGxBzS,GAAYyS,KACjBA,EAAQ,CAAEA,IAIX,OAAO5d,MAAMiK,KAAM2T,GACjB1c,IAAKkI,GACe,iBAARA,EACJ,IAAI,GAAMvR,EAAUuR,GAGvBA,aAAgB,GACb,IAAI,GAAMvR,EAAUuR,EAAK5S,MAG1B4S,GA7SMyU,CAAWhnB,KAAKgB,SAAU2U,GAExC,IAAM,MAAMpD,KAAQwU,EAEE,OAAhBxU,EAAKwK,QACTxK,EAAK2D,UAGN3D,EAAKwK,OAAS/c,KACduS,EAAKvR,SAAWhB,KAAKgB,SAErBhB,KAAK2lB,UAAU7f,OAAQpD,EAAO,EAAG6P,GACjC7P,IACAF,IAGD,OAAOA,EAaR,gBAAiBE,EAAOukB,EAAU,GACjCjnB,KAAK+d,YAAa,WAAY/d,MAE9B,IAAM,IAAIzC,EAAImF,EAAOnF,EAAImF,EAAQukB,EAAS1pB,IACzCyC,KAAK2lB,UAAWpoB,GAAIwf,OAAS,KAG9B,OAAO/c,KAAK2lB,UAAU7f,OAAQpD,EAAOukB,GAYtC,cAAenoB,EAAKN,GACnBA,EAAQsN,OAAQtN,GAEhBwB,KAAK+d,YAAa,aAAc/d,MAEpB,SAAPlB,EACJinB,GAAc/lB,KAAK6lB,SAAUrnB,GACX,SAAPM,EACXkB,KAAKuiB,QAAQ0D,MAAOznB,GAEpBwB,KAAKylB,OAAOhc,IAAK3K,EAAKN,GAaxB,iBAAkBM,GAIjB,OAHAkB,KAAK+d,YAAa,aAAc/d,MAGpB,SAAPlB,EACCkB,KAAK6lB,SAAS7c,KAAO,IACzBhJ,KAAK6lB,SAAStc,SAEP,GAOG,SAAPzK,GACEkB,KAAKuiB,QAAQE,UAClBziB,KAAKuiB,QAAQhZ,SAEN,GAOFvJ,KAAKylB,OAAO1R,OAAQjV,GAc5B,UAAWsnB,GACVpmB,KAAK+d,YAAa,aAAc/d,MAEhC,IAAM,MAAMlC,KAAQuc,GAAS+L,GAC5BpmB,KAAK6lB,SAASjX,IAAK9Q,GAerB,aAAcsoB,GACbpmB,KAAK+d,YAAa,aAAc/d,MAEhC,IAAM,MAAMlC,KAAQuc,GAAS+L,GAC5BpmB,KAAK6lB,SAAS9R,OAAQjW,GAuBxB,UAAWoB,EAAUV,GACpBwB,KAAK+d,YAAa,aAAc/d,MAEhCA,KAAKuiB,QAAQ9Y,IAAKvK,EAAUV,GAkB7B,aAAcU,GACbc,KAAK+d,YAAa,aAAc/d,MAEhC,IAAM,MAAMlC,KAAQuc,GAASnb,GAC5Bc,KAAKuiB,QAAQpe,OAAQrG,GAavB,mBAAoBgB,EAAKN,GACxBwB,KAAKkmB,kBAAkBzc,IAAK3K,EAAKN,GAWlC,sBAAuBM,GACtB,OAAOkB,KAAKkmB,kBAAkBnS,OAAQjV,IA8DxC,SAASinB,GAAcmB,EAAYC,GAClC,MAAMC,EAAaD,EAAc5X,MAAO,OACxC2X,EAAW3d,QACX6d,EAAW3jB,QAAS3F,GAAQopB,EAAWtY,IAAK9Q,ICt1B9B,MAAM,WAAyB,GAa7C,YAAakD,EAAUlD,EAAM0nB,EAAO1d,GACnClI,MAAOoB,EAAUlD,EAAM0nB,EAAO1d,GAQ9B9H,KAAK6mB,gBAAkBA,GA6BxB,GAAI5mB,EAAMnC,EAAO,MAChB,OAAMA,EAMEA,IAASkC,KAAKlC,OACX,qBAATmC,GAAwC,0BAATA,GAEtB,YAATA,GAA+B,iBAATA,GARP,qBAATA,GAAwC,0BAATA,GAE5B,YAATA,GAA+B,iBAATA,GACb,SAATA,GAA4B,cAATA,GAgBhB,SAAS4mB,KACf,MAAM/e,EAAW,IAAK9H,KAAK0mB,eACrBW,EAAYvf,EAAU9H,KAAK8mB,WAAa,GAG9C,GAAKO,GAAaA,EAAUlnB,GAAI,UAAW,MAC1C,OAAOH,KAAK8mB,WAGb,IAAM,MAAML,KAAS3e,EAEpB,IAAM2e,EAAMtmB,GAAI,aACf,OAAO,KAKT,OAAOH,KAAK8mB,WCtFb,IAIe,GAJA,IAAe,SAAS7nB,EAAQ2L,GAC7C,GAAWA,EAAQ,GAAOA,GAAS3L,MCvBrC,MAAMqoB,GAA6BhpB,OAAQ,wBACrCipB,GAAyBjpB,OAAQ,oBACjCkpB,GAAwBlpB,OAAQ,mBAehCmpB,GAAkB,CAIvB,IAAK3pB,EAAMU,GAEV,GAAK,EAAUV,GAKd,YAJAG,OAAOuF,KAAM1F,GAAO2F,QAASvE,IAC5Bc,KAAKyJ,IAAKvK,EAAUpB,EAAMoB,KACxBc,MAKJ0nB,GAAgB1nB,MAEhB,MAAM2nB,EAAa3nB,KAAMsnB,IAEzB,GAAOxpB,KAAQkC,OAAW2nB,EAAWje,IAAK5L,GAgBzC,MAAM,IAAI,KAAe,iCAAkCkC,MAG5D/B,OAAOC,eAAgB8B,KAAMlC,EAAM,CAClCK,YAAY,EACZypB,cAAc,EAEdxpB,IAAG,IACKupB,EAAWvpB,IAAKN,GAGxB,IAAKU,GACJ,MAAMqpB,EAAWF,EAAWvpB,IAAKN,GAKjC,IAAIkN,EAAWhL,KAAKqU,KAAM,OAASvW,EAAMA,EAAMU,EAAOqpB,QAEpCvhB,IAAb0E,IACJA,EAAWxM,GAKPqpB,IAAa7c,GAAa2c,EAAWje,IAAK5L,KAC9C6pB,EAAWle,IAAK3L,EAAMkN,GACtBhL,KAAKqU,KAAM,UAAYvW,EAAMA,EAAMkN,EAAU6c,OAKhD7nB,KAAMlC,GAASU,GAMhB,QAASspB,GACR,IAAMA,EAAe/lB,SAAWgmB,GAAeD,GAM9C,MAAM,IAAI,KAAe,mCAAoC9nB,MAG9D,GAAK,IAAMqY,IAAKyP,GAAmB9e,OAAS8e,EAAe/lB,OAM1D,MAAM,IAAI,KAAe,uCAAwC/B,MAGlE0nB,GAAgB1nB,MAEhB,MAAMgoB,EAAkBhoB,KAAMwnB,IAE9BM,EAAerkB,QAASwf,IACvB,GAAK+E,EAAgBte,IAAKuZ,GAMzB,MAAM,IAAI,KAAe,yBAA0BjjB,QAIrD,MAAMioB,EAAW,IAAInU,IAsBrB,OAhBAgU,EAAerkB,QAASkZ,IACvB,MAAM9V,EAAU,CAAE3H,SAAUyd,EAAG/I,GAAI,IAEnCoU,EAAgBve,IAAKkT,EAAG9V,GACxBohB,EAASxe,IAAKkT,EAAG9V,KAYX,CACN+M,GAAIsU,GACJC,OAAQC,GAERC,YAAaroB,KACbsoB,gBAAiBR,EACjBS,IAAK,GACLC,UAAWP,IAOb,UAAWQ,GAEV,IAAQzoB,KAAMsnB,IACb,OAGD,MAAMU,EAAkBhoB,KAAMwnB,IACxBkB,EAAmB1oB,KAAMunB,IAE/B,GAAKkB,EAAiB1mB,OAAS,CAC9B,IAAMgmB,GAAeU,GAMpB,MAAM,IAAI,KAAe,qCAAsCzoB,MAGhEyoB,EAAiBhlB,QAASwf,IACzB,MAAMpc,EAAUmhB,EAAgB5pB,IAAK6kB,GAGrC,IAAMpc,EACL,OAGD,IAAI8hB,EAAcC,EAAYC,EAAcC,EAE5CjiB,EAAQ+M,GAAGnQ,QAASmQ,IAEnB+U,EAAe/U,EAAI,GACnBgV,EAAahV,EAAI,GACjBiV,EAAeH,EAAiBtqB,IAAKuqB,GACrCG,EAAqBD,EAAcD,GAEnCE,EAAmB/U,OAAQlN,GAErBiiB,EAAmB9f,aACjB6f,EAAcD,GAGhB3qB,OAAOuF,KAAMqlB,GAAe9mB,SACjC2mB,EAAiB3U,OAAQ4U,GACzB3oB,KAAKsR,cAAeqX,EAAc,aAIpCX,EAAgBjU,OAAQkP,UAGzByF,EAAiBjlB,QAAS,CAAEwkB,EAAUc,KACrC/oB,KAAKsR,cAAeyX,EAAiB,YAGtCL,EAAiBnf,QACjBye,EAAgBze,SAOlB,SAAUyf,GACT,MAAMC,EAAiBjpB,KAAMgpB,GAE7B,IAAMC,EAQL,MAAM,IAAI,KACT,4CACAjpB,KACA,CAAEf,OAAQe,KAAMgpB,eAIlBhpB,KAAKkpB,GAAIF,EAAY,CAAElS,EAAKzF,KAC3ByF,EAAIpD,OAASuV,EAAe5V,MAAOrT,KAAMqR,KAG1CrR,KAAMgpB,GAAe,YAAa3X,GACjC,OAAOrR,KAAKqU,KAAM2U,EAAY3X,MAKjC,GAAQoW,GAAiB,IAEV,UAMf,SAASC,GAAgByB,GAEnBA,EAAY7B,MAQjBrpB,OAAOC,eAAgBirB,EAAY7B,GAA4B,CAC9D9oB,MAAO,IAAIsV,MAgDZ7V,OAAOC,eAAgBirB,EAAY5B,GAAwB,CAC1D/oB,MAAO,IAAIsV,MAgCZ7V,OAAOC,eAAgBirB,EAAY3B,GAAuB,CACzDhpB,MAAO,IAAIsV,OAQb,SAASoU,MAAW7W,GACnB,MAAM+X,EA+HP,YAA6B/X,GAE5B,IAAMA,EAAKtP,OAMV,MAAM,IAAI,KAAe,iCAAkC,MAG5D,MAAMoiB,EAAS,CAAEvQ,GAAI,IACrB,IAAIyV,EAEmC,mBAA3BhY,EAAMA,EAAKtP,OAAS,KAC/BoiB,EAAOjT,SAAWG,EAAKjI,OAcxB,OAXAiI,EAAK5N,QAASkZ,IACb,GAAiB,iBAALA,EACX0M,EAAe1B,WAAW1kB,KAAM0Z,OAC1B,IAAiB,iBAALA,EAIlB,MAAM,IAAI,KAAe,iCAAkC,MAH3D0M,EAAiB,CAAEF,WAAYxM,EAAGgL,WAAY,IAC9CxD,EAAOvQ,GAAG3Q,KAAMomB,MAMXlF,EA5JYmF,IAAoBjY,GACjCkY,EAAepgB,MAAMiK,KAAMpT,KAAKwoB,UAAUhlB,QAC1CgmB,EAAmBD,EAAaxnB,OAGtC,IAAMqnB,EAAWlY,UAAYkY,EAAWxV,GAAG7R,OAAS,EAMnD,MAAM,IAAI,KAAe,iCAAkC/B,MAI5D,GAAKwpB,EAAmB,GAAKJ,EAAWlY,SAMvC,MAAM,IAAI,KACT,oCACAlR,MAyPH,IAAgCmpB,EArP/BC,EAAWxV,GAAGnQ,QAASmQ,IAEtB,GAAKA,EAAG+T,WAAW5lB,QAAU6R,EAAG+T,WAAW5lB,SAAWynB,EAMrD,MAAM,IAAI,KAAe,uCAAwCxpB,MAK5D4T,EAAG+T,WAAW5lB,SACnB6R,EAAG+T,WAAa3nB,KAAKsoB,mBAIvBtoB,KAAKuoB,IAAMa,EAAWxV,GAGjBwV,EAAWlY,WACflR,KAAKwoB,UAAUpqB,IAAKmrB,EAAc,IAAMrY,SAAWkY,EAAWlY,UA+NhCiY,EA5NRnpB,KAAKqoB,YAAaroB,KAAKuoB,IA6NnC9kB,QAASmQ,IACnB,MAAM8U,EAAmBS,EAAY5B,IACrC,IAAIU,EAIES,EAAiBtqB,IAAKwV,EAAGuV,aAC9BA,EAAWhY,SAAUyC,EAAGuV,WAAY,SAAU,CAAErS,EAAKmM,KACpDgF,EAAWS,EAAiBtqB,IAAKwV,EAAGuV,YAAclG,GAI7CgF,GACJA,EAASxkB,QAASoD,IACjB4iB,GAA+BN,EAAYtiB,EAAQ3H,gBAnEzD,SAA4BwqB,GAC3B,IAAId,EAEJc,EAAMlB,UAAU/kB,QAAS,CAAEoD,EAASoc,KAInCyG,EAAMnB,IAAI9kB,QAASmQ,IAClBgV,EAAahV,EAAG+T,WAAY9gB,EAAQqK,SAAW,EAAIwY,EAAMpB,gBAAgBxV,QAASmQ,IAElFpc,EAAQ+M,GAAG3Q,KAAM,CAAE2Q,EAAGuV,WAAYP,IAjErC,SAAiCO,EAAYtiB,EAAS8hB,EAAcgB,GACnE,MAAMjB,EAAmBS,EAAY5B,IAC/BqC,EAAuBlB,EAAiBtqB,IAAKuqB,GAC7CV,EAAW2B,GAAwB,GAEnC3B,EAAU0B,KACf1B,EAAU0B,GAAmB,IAAItR,KAIlC4P,EAAU0B,GAAiB/a,IAAK/H,GAE1B+iB,GACLlB,EAAiBjf,IAAKkf,EAAcV,GAqDnC4B,CAAwBH,EAAMrB,YAAaxhB,EAAS+M,EAAGuV,WAAYP,OAhLrEkB,CAAmB9pB,MAGnBA,KAAKsoB,gBAAgB7kB,QAASwf,IAC7BwG,GAA+BzpB,KAAKqoB,YAAapF,KAUnD,SAASmF,GAAY2B,EAAa5K,EAAWjO,GAC5C,GAAKlR,KAAKwoB,UAAUxf,KAAO,EAM1B,MAAM,IAAI,KAAe,0CAA2ChJ,MAGrEA,KAAK4T,MAcN,SAA4BmW,EAAa5K,GACxC,MAAM6K,EAA8BD,EAAY1f,IAAK8e,GAAc,CAAEA,EAAYhK,IAGjF,OAAOhW,MAAMhK,UAAUsD,OAAO4Q,MAAO,GAAI2W,GAhBrCC,CAAmBF,EAAa5K,GAEnCjO,GAsBF,SAAS6W,GAAe9D,GACvB,OAAOA,EAAIiG,MAAOvN,GAAiB,iBAALA,GAwI/B,SAAS8M,GAA+BN,EAAYlG,GACnD,MACMpc,EADkBsiB,EAAY3B,IACJppB,IAAK6kB,GACrC,IAAII,EAOCxc,EAAQqK,SACZmS,EAAgBxc,EAAQqK,SAASmC,MAAO8V,EAAYtiB,EAAQ+M,GAAGvJ,IAAKuJ,GAAMA,EAAI,GAAKA,EAAI,OAEvFyP,EAAgBxc,EAAQ+M,GAAI,GAC5ByP,EAAgBA,EAAe,GAAKA,EAAe,KAG/CplB,OAAOkB,UAAUC,eAAe1B,KAAMyrB,EAAYlG,GACtDkG,EAAYlG,GAAiBI,EAE7B8F,EAAW1f,IAAKwZ,EAAcI,GClmBjB,MAAM,WAAwB,GAO5C,YAAariB,EAAUlD,EAAM0nB,EAAO1d,GACnClI,MAAOoB,EAAUlD,EAAM0nB,EAAO1d,GAQ9B9H,KAAKyJ,IAAK,cAAc,GAYxBzJ,KAAKyJ,IAAK,aAAa,GAEvBzJ,KAAKjB,KAAM,cAAe6U,GAAI5S,GAE9BhB,KAAKjB,KAAM,aAAc6U,GACxB5S,EACA,YACAmpB,GAAaA,GAAanpB,EAASopB,UAAUC,iBAAmBrqB,MAIjEA,KAAKmR,SAAUnQ,EAASopB,UAAW,SAAU,KAC5CpqB,KAAKmqB,UAAYnpB,EAASmpB,WAAanpB,EAASopB,UAAUC,iBAAmBrqB,OA8B/E,GAAIC,EAAMnC,EAAO,MAChB,OAAMA,EAOEA,IAASkC,KAAKlC,OACX,oBAATmC,GAAuC,yBAATA,GAErB,qBAATA,GAAwC,0BAATA,GACtB,YAATA,GAA+B,iBAATA,GAVP,oBAATA,GAAuC,yBAATA,GAE3B,qBAATA,GAAwC,0BAATA,GACtB,YAATA,GAA+B,iBAATA,GACb,SAATA,GAA4B,cAATA,EAWtB,UACCD,KAAKsR,iBAIPkD,GAAK,GAAiB,IC1GtB,MAAM8V,GAAiBhsB,OAAQ,YAShB,MAAM,WAA4B,GAOhD,YAAa0C,EAAUlD,GACtB8B,MAAOoB,EAAUlD,GASjBkC,KAAKuqB,SAAW,OA8BjB,GAAItqB,EAAMnC,EAAO,MAChB,OAAMA,EAQEA,IAASkC,KAAKlC,OACX,gBAATmC,GAAmC,qBAATA,GAEjB,oBAATA,GAAuC,yBAATA,GACrB,qBAATA,GAAwC,0BAATA,GACtB,YAATA,GAA+B,iBAATA,GAZP,gBAATA,GAAmC,qBAATA,GAEvB,oBAATA,GAAuC,yBAATA,GACrB,qBAATA,GAAwC,0BAATA,GACtB,YAATA,GAA+B,iBAATA,GACb,SAATA,GAA4B,cAATA,EAYtB,eACC,OAAOD,KAAKwqB,kBAAmBF,IAGhC,aAAcC,GACbvqB,KAAKyqB,mBAAoBH,GAAgBC,GAY1C,UAAWzsB,GACVkC,KAAKlC,KAAOA,GCtFC,MAAM,GAmBpB,YAAaoE,EAAU,IACtB,IAAMA,EAAQwoB,aAAexoB,EAAQyoB,cAMpC,MAAM,IAAI,KACT,qCACA,MAIF,GAAKzoB,EAAQ0oB,WAAkC,WAArB1oB,EAAQ0oB,WAA+C,YAArB1oB,EAAQ0oB,UAMnE,MAAM,IAAI,KAAe,qCAAsC1oB,EAAQyoB,cAAe,CAAEC,UAAW1oB,EAAQ0oB,YAc5G5qB,KAAK0qB,WAAaxoB,EAAQwoB,YAAc,KASnCxoB,EAAQyoB,cACZ3qB,KAAK6qB,SAAW,GAASC,UAAW5oB,EAAQyoB,eAE5C3qB,KAAK6qB,SAAW,GAASC,UAAW5oB,EAAQwoB,WAAiC,YAArBxoB,EAAQ0oB,UAA0B,MAAQ,UASnG5qB,KAAK4qB,UAAY1oB,EAAQ0oB,WAAa,UAStC5qB,KAAK+qB,mBAAqB7oB,EAAQ6oB,iBASlC/qB,KAAKgrB,UAAY9oB,EAAQ8oB,QAUzBhrB,KAAKirB,mBAAqB/oB,EAAQ+oB,iBAQlCjrB,KAAKkrB,qBAAuBlrB,KAAK0qB,WAAa1qB,KAAK0qB,WAAW7J,MAAM9D,OAAS,KAQ7E/c,KAAKmrB,mBAAqBnrB,KAAK0qB,WAAa1qB,KAAK0qB,WAAW5J,IAAI/D,OAAS,KAQ1E,CAAEze,OAAOiW,YACR,OAAOvU,KAeR,KAAMorB,GACL,IAAIC,EAAM7sB,EAAO8sB,EAEjB,GACCA,EAAetrB,KAAK6qB,WAEhBQ,OAAM7sB,SAAUwB,KAAKurB,eACfF,GAAQD,EAAM5sB,IAEnB6sB,IACLrrB,KAAK6qB,SAAWS,GAUlB,OACC,MAAuB,WAAlBtrB,KAAK4qB,UACF5qB,KAAKwrB,QAELxrB,KAAKyrB,YAYd,QACC,IAAIZ,EAAW7qB,KAAK6qB,SAASa,QAC7B,MAAMC,EAAmB3rB,KAAK6qB,SACxB9N,EAAS8N,EAAS9N,OAGxB,GAAuB,OAAlBA,EAAOA,QAAmB8N,EAASve,SAAWyQ,EAAO+J,WACzD,MAAO,CAAEuE,MAAM,GAIhB,GAAKtO,IAAW/c,KAAKmrB,oBAAsBN,EAASve,QAAUtM,KAAK0qB,WAAW5J,IAAIxU,OACjF,MAAO,CAAE+e,MAAM,GAIhB,IAAI9Y,EAGJ,GAAKwK,aAAkB,GAAO,CAC7B,GAAK8N,EAASe,QAIb,OAFA5rB,KAAK6qB,SAAW,GAASgB,aAAc9O,GAEhC/c,KAAKwrB,QAGbjZ,EAAOwK,EAAOpd,KAAMkrB,EAASve,aAE7BiG,EAAOwK,EAAOG,SAAU2N,EAASve,QAGlC,GAAKiG,aAAgB,GASpB,OARMvS,KAAKgrB,QAGVH,EAASve,SAFTue,EAAW,IAAI,GAAUtY,EAAM,GAKhCvS,KAAK6qB,SAAWA,EAET7qB,KAAK8rB,mBAAoB,eAAgBvZ,EAAMoZ,EAAkBd,EAAU,GAC5E,GAAKtY,aAAgB,GAAO,CAClC,GAAKvS,KAAK+qB,iBAIT,OAHAF,EAAW,IAAI,GAAUtY,EAAM,GAC/BvS,KAAK6qB,SAAWA,EAET7qB,KAAKwrB,QACN,CACN,IACInpB,EADA0pB,EAAkBxZ,EAAK5S,KAAKoC,OAgBhC,OAZKwQ,GAAQvS,KAAKmrB,oBACjBY,EAAkB/rB,KAAK0qB,WAAW5J,IAAIxU,OACtCjK,EAAO,IAAI,GAAWkQ,EAAM,EAAGwZ,GAC/BlB,EAAW,GAASgB,aAAcxpB,KAElCA,EAAO,IAAI,GAAWkQ,EAAM,EAAGA,EAAK5S,KAAKoC,QAEzC8oB,EAASve,UAGVtM,KAAK6qB,SAAWA,EAET7qB,KAAK8rB,mBAAoB,OAAQzpB,EAAMspB,EAAkBd,EAAUkB,IAErE,GAAoB,iBAARxZ,EAAmB,CACrC,IAAIyZ,EAEJ,GAAKhsB,KAAK+qB,iBACTiB,EAAa,MACP,CAINA,GAFkBjP,IAAW/c,KAAKmrB,mBAAqBnrB,KAAK0qB,WAAW5J,IAAIxU,OAASyQ,EAAOpd,KAAKoC,QAEvE8oB,EAASve,OAGnC,MAAM2f,EAAY,IAAI,GAAWlP,EAAQ8N,EAASve,OAAQ0f,GAK1D,OAHAnB,EAASve,QAAU0f,EACnBhsB,KAAK6qB,SAAWA,EAET7qB,KAAK8rB,mBAAoB,OAAQG,EAAWN,EAAkBd,EAAUmB,GAM/E,OAHAnB,EAAW,GAASgB,aAAc9O,GAClC/c,KAAK6qB,SAAWA,EAEX7qB,KAAKirB,iBACFjrB,KAAKwrB,QAELxrB,KAAK8rB,mBAAoB,aAAc/O,EAAQ4O,EAAkBd,GAa3E,YACC,IAAIA,EAAW7qB,KAAK6qB,SAASa,QAC7B,MAAMC,EAAmB3rB,KAAK6qB,SACxB9N,EAAS8N,EAAS9N,OAGxB,GAAuB,OAAlBA,EAAOA,QAAuC,IAApB8N,EAASve,OACvC,MAAO,CAAE+e,MAAM,GAIhB,GAAKtO,GAAU/c,KAAKkrB,sBAAwBL,EAASve,QAAUtM,KAAK0qB,WAAW7J,MAAMvU,OACpF,MAAO,CAAE+e,MAAM,GAIhB,IAAI9Y,EAGJ,GAAKwK,aAAkB,GAAO,CAC7B,GAAK8N,EAASqB,UAIb,OAFAlsB,KAAK6qB,SAAW,GAASsB,cAAepP,GAEjC/c,KAAKyrB,YAGblZ,EAAOwK,EAAOpd,KAAMkrB,EAASve,OAAS,QAEtCiG,EAAOwK,EAAOG,SAAU2N,EAASve,OAAS,GAG3C,GAAKiG,aAAgB,GACpB,OAAMvS,KAAKgrB,SAUVH,EAASve,SACTtM,KAAK6qB,SAAWA,EAET7qB,KAAK8rB,mBAAoB,eAAgBvZ,EAAMoZ,EAAkBd,EAAU,KAZlFA,EAAW,IAAI,GAAUtY,EAAMA,EAAKuU,YACpC9mB,KAAK6qB,SAAWA,EAEX7qB,KAAKirB,iBACFjrB,KAAKyrB,YAELzrB,KAAK8rB,mBAAoB,aAAcvZ,EAAMoZ,EAAkBd,IAQlE,GAAKtY,aAAgB,GAAO,CAClC,GAAKvS,KAAK+qB,iBAIT,OAHAF,EAAW,IAAI,GAAUtY,EAAMA,EAAK5S,KAAKoC,QACzC/B,KAAK6qB,SAAWA,EAET7qB,KAAKyrB,YACN,CACN,IACIppB,EADA0pB,EAAkBxZ,EAAK5S,KAAKoC,OAIhC,GAAKwQ,GAAQvS,KAAKkrB,qBAAuB,CACxC,MAAM5e,EAAStM,KAAK0qB,WAAW7J,MAAMvU,OAErCjK,EAAO,IAAI,GAAWkQ,EAAMjG,EAAQiG,EAAK5S,KAAKoC,OAASuK,GACvDyf,EAAkB1pB,EAAK1C,KAAKoC,OAC5B8oB,EAAW,GAASsB,cAAe9pB,QAEnCA,EAAO,IAAI,GAAWkQ,EAAM,EAAGA,EAAK5S,KAAKoC,QAEzC8oB,EAASve,SAKV,OAFAtM,KAAK6qB,SAAWA,EAET7qB,KAAK8rB,mBAAoB,OAAQzpB,EAAMspB,EAAkBd,EAAUkB,IAErE,GAAoB,iBAARxZ,EAAmB,CACrC,IAAIyZ,EAEJ,GAAMhsB,KAAK+qB,iBAMViB,EAAa,MANgB,CAE7B,MAAMI,EAAcrP,IAAW/c,KAAKkrB,qBAAuBlrB,KAAK0qB,WAAW7J,MAAMvU,OAAS,EAE1F0f,EAAanB,EAASve,OAAS8f,EAKhCvB,EAASve,QAAU0f,EAEnB,MAAMC,EAAY,IAAI,GAAWlP,EAAQ8N,EAASve,OAAQ0f,GAI1D,OAFAhsB,KAAK6qB,SAAWA,EAET7qB,KAAK8rB,mBAAoB,OAAQG,EAAWN,EAAkBd,EAAUmB,GAM/E,OAHAnB,EAAW,GAASsB,cAAepP,GACnC/c,KAAK6qB,SAAWA,EAET7qB,KAAK8rB,mBAAoB,eAAgB/O,EAAQ4O,EAAkBd,EAAU,GAetF,mBAAoB5qB,EAAMoC,EAAMspB,EAAkBU,EAActqB,GA6B/D,OAxBKM,aAAgB,KAEfA,EAAK+b,aAAe/b,EAAK1C,KAAKoC,QAAUM,EAAK8b,SAASxe,KAAKoC,SACxC,WAAlB/B,KAAK4qB,WAA6B5qB,KAAK0qB,YAAc1qB,KAAK0qB,WAAW5J,IAAIwL,QAAStsB,KAAK6qB,UAK3Fc,EAAmB,GAASE,aAAcxpB,EAAK8b,WAJ/CkO,EAAe,GAASR,aAAcxpB,EAAK8b,UAE3Cne,KAAK6qB,SAAWwB,IAOS,IAAtBhqB,EAAK+b,eACc,YAAlBpe,KAAK4qB,WAA8B5qB,KAAK0qB,YAAc1qB,KAAK0qB,WAAW7J,MAAMyL,QAAStsB,KAAK6qB,UAK9Fc,EAAmB,GAASQ,cAAe9pB,EAAK8b,WAJhDkO,EAAe,GAASF,cAAe9pB,EAAK8b,UAE5Cne,KAAK6qB,SAAWwB,KAOZ,CACNhB,MAAM,EACN7sB,MAAO,CACNyB,OACAoC,OACAspB,mBACAU,eACAtqB,YCxaW,MAAM,GAOpB,YAAagb,EAAQzQ,GAQpBtM,KAAK+c,OAASA,EAQd/c,KAAKsM,OAASA,EAUf,gBACC,OAAKtM,KAAK+c,OAAO5c,GAAI,SACb,KAGDH,KAAK+c,OAAOG,SAAUld,KAAKsM,SAAY,KAU/C,iBACC,OAAKtM,KAAK+c,OAAO5c,GAAI,SACb,KAGDH,KAAK+c,OAAOG,SAAUld,KAAKsM,OAAS,IAAO,KASnD,gBACC,OAAuB,IAAhBtM,KAAKsM,OASb,cACC,MAAMigB,EAAYvsB,KAAK+c,OAAO5c,GAAI,SAAYH,KAAK+c,OAAOpd,KAAKoC,OAAS/B,KAAK+c,OAAO+J,WAEpF,OAAO9mB,KAAKsM,SAAWigB,EASxB,WACC,OAAOvsB,KAAK+c,OAAOlgB,KASpB,sBACC,IAAI2vB,EAAWxsB,KAAK+c,OAEpB,OAAWyP,aAAoB,KAAoB,CAClD,IAAKA,EAASzP,OAGb,OAAO,KAFPyP,EAAWA,EAASzP,OAMtB,OAAOyP,EASR,aAAcC,GACb,MAAMC,EAAU,GAAS5B,UAAW9qB,MAE9BsM,EAASogB,EAAQpgB,OAASmgB,EAGhC,OAFAC,EAAQpgB,OAASA,EAAS,EAAI,EAAIA,EAE3BogB,EAmBR,wBAAyBtB,EAAMlpB,EAAU,IACxCA,EAAQyoB,cAAgB3qB,KAExB,MAAM2sB,EAAa,IAAI,GAAYzqB,GAGnC,OAFAyqB,EAAWvB,KAAMA,GAEVuB,EAAW9B,SAQnB,eACC,OAAK7qB,KAAK+c,OAAO5c,GAAI,oBACb,CAAEH,KAAK+c,QAEP/c,KAAK+c,OAAOS,aAAc,CAAEJ,aAAa,IAWlD,kBAAmByN,GAClB,MAAMtN,EAAavd,KAAKwd,eAClBC,EAAaoN,EAASrN,eAE5B,IAAIjgB,EAAI,EAER,KAAQggB,EAAYhgB,IAAOkgB,EAAYlgB,IAAOggB,EAAYhgB,IACzDA,IAGD,OAAa,IAANA,EAAU,KAAOggB,EAAYhgB,EAAI,GAkBzC,GAAI0C,GACH,MAAgB,aAATA,GAAgC,kBAATA,EAS/B,QAAS2sB,GACR,OAAS5sB,KAAK+c,QAAU6P,EAAc7P,QAAU/c,KAAKsM,QAAUsgB,EAActgB,OAa9E,SAAUsgB,GACT,MAA4C,UAArC5sB,KAAK6sB,YAAaD,GAa1B,QAASA,GACR,MAA4C,SAArC5sB,KAAK6sB,YAAaD,GAU1B,YAAaA,GACZ,GAAK5sB,KAAKnD,OAAS+vB,EAAc/vB,KAChC,MAAO,YAGR,GAAKmD,KAAKssB,QAASM,GAClB,MAAO,OAIR,MAAMlP,EAAW1d,KAAK+c,OAAO5c,GAAI,QAAWH,KAAK+c,OAAOY,UAAY,GAC9DmP,EAAYF,EAAc7P,OAAO5c,GAAI,QAAWysB,EAAc7P,OAAOY,UAAY,GAGvFD,EAASza,KAAMjD,KAAKsM,QACpBwgB,EAAU7pB,KAAM2pB,EAActgB,QAG9B,MAAMxK,EAAS4a,GAAegB,EAAUoP,GAExC,OAAShrB,GACR,IAAK,SACJ,MAAO,SAER,IAAK,YACJ,MAAO,QAER,QACC,OAAO4b,EAAU5b,GAAWgrB,EAAWhrB,GAAW,SAAW,SAahE,UAAWI,EAAU,IAGpB,OAFAA,EAAQyoB,cAAgB3qB,KAEjB,IAAI,GAAYkC,GAGxB,QACC,OAAO,IAAI,GAAUlC,KAAK+c,OAAQ/c,KAAKsM,QAqBxC,iBAAkBygB,EAAgBzgB,GACjC,GAAKygB,aAA0B,GAC9B,OAAO,IAAI/sB,KAAM+sB,EAAehQ,OAAQgQ,EAAezgB,QACjD,CACN,MAAMiG,EAAOwa,EAEb,GAAe,OAAVzgB,EACJA,EAASiG,EAAKpS,GAAI,SAAYoS,EAAK5S,KAAKoC,OAASwQ,EAAKuU,eAChD,IAAe,UAAVxa,EACX,OAAOtM,KAAKmsB,cAAe5Z,GACrB,GAAe,SAAVjG,EACX,OAAOtM,KAAK6rB,aAActZ,GACpB,GAAgB,IAAXjG,IAAiBA,EAO5B,MAAM,IAAI,KAAe,wCAAyCiG,GAGnE,OAAO,IAAI,GAAUA,EAAMjG,IAW7B,oBAAqBjK,GAEpB,GAAKA,EAAKlC,GAAI,cACb,OAAO,IAAI,GAAUkC,EAAK8b,SAAU9b,EAAK+b,aAAe/b,EAAK1C,KAAKoC,QAGnE,IAAMM,EAAK0a,OAOV,MAAM,IAAI,KAAe,2BAA4B1a,EAAM,CAAExF,KAAMwF,IAGpE,OAAO,IAAI,GAAUA,EAAK0a,OAAQ1a,EAAKK,MAAQ,GAUhD,qBAAsBL,GAErB,GAAKA,EAAKlC,GAAI,cACb,OAAO,IAAI,GAAUkC,EAAK8b,SAAU9b,EAAK+b,cAG1C,IAAM/b,EAAK0a,OAOV,MAAM,IAAI,KAAe,4BAA6B1a,EAAM,CAAExF,KAAMwF,IAGrE,OAAO,IAAI,GAAUA,EAAK0a,OAAQ1a,EAAKK,QC3Y1B,MAAM,GASpB,YAAame,EAAOC,EAAM,MAOzB9gB,KAAK6gB,MAAQA,EAAM6K,QAQnB1rB,KAAK8gB,IAAMA,EAAMA,EAAI4K,QAAU7K,EAAM6K,QAgBtC,EAAIptB,OAAOiW,kBACH,IAAI,GAAY,CAAEmW,WAAY1qB,KAAMirB,kBAAkB,IAQ9D,kBACC,OAAOjrB,KAAK6gB,MAAMyL,QAAStsB,KAAK8gB,KASjC,aACC,OAAO9gB,KAAK6gB,MAAM9D,SAAW/c,KAAK8gB,IAAI/D,OAQvC,WACC,OAAO/c,KAAK6gB,MAAMhkB,KAoBnB,cACC,IAAIgkB,EAAQ7gB,KAAK6gB,MAAMmM,wBAAyBC,GAAiB,CAAErC,UAAW,aAC1E9J,EAAM9gB,KAAK8gB,IAAIkM,wBAAyBC,IAW5C,OARKpM,EAAM9D,OAAO5c,GAAI,UAAa0gB,EAAMqL,YACxCrL,EAAQ,GAASsL,cAAetL,EAAM9D,SAGlC+D,EAAI/D,OAAO5c,GAAI,UAAa2gB,EAAI8K,UACpC9K,EAAM,GAAS+K,aAAc/K,EAAI/D,SAG3B,IAAI,GAAO8D,EAAOC,GAoB1B,aACC,IAAID,EAAQ7gB,KAAK6gB,MAAMmM,wBAAyBC,IAEhD,GAAKpM,EAAMqM,QAASltB,KAAK8gB,MAASD,EAAMyL,QAAStsB,KAAK8gB,KACrD,OAAO,IAAI,GAAOD,EAAOA,GAG1B,IAAIC,EAAM9gB,KAAK8gB,IAAIkM,wBAAyBC,GAAiB,CAAErC,UAAW,aAC1E,MAAMuC,EAAiBtM,EAAMuM,UACvBC,EAAgBvM,EAAIwM,WAW1B,OARKH,GAAkBA,EAAehtB,GAAI,WACzC0gB,EAAQ,IAAI,GAAUsM,EAAgB,IAGlCE,GAAiBA,EAAcltB,GAAI,WACvC2gB,EAAM,IAAI,GAAUuM,EAAeA,EAAc1tB,KAAKoC,SAGhD,IAAI,GAAO8e,EAAOC,GAS1B,QAASyM,GACR,OAAOvtB,MAAQutB,GAAgBvtB,KAAK6gB,MAAMyL,QAASiB,EAAW1M,QAAW7gB,KAAK8gB,IAAIwL,QAASiB,EAAWzM,KAUvG,iBAAkB+J,GACjB,OAAOA,EAASqC,QAASltB,KAAK6gB,QAAWgK,EAAShN,SAAU7d,KAAK8gB,KAalE,cAAeyM,EAAYC,GAAQ,GAC7BD,EAAWE,cACfD,GAAQ,GAGT,MAAME,EAAgB1tB,KAAK2tB,iBAAkBJ,EAAW1M,QAAa2M,GAASxtB,KAAK6gB,MAAMyL,QAASiB,EAAW1M,OACvG+M,EAAc5tB,KAAK2tB,iBAAkBJ,EAAWzM,MAAW0M,GAASxtB,KAAK8gB,IAAIwL,QAASiB,EAAWzM,KAEvG,OAAO4M,GAAiBE,EAkCzB,cAAeL,GACd,MAAMM,EAAS,GAqBf,OAnBK7tB,KAAK8tB,eAAgBP,IAGpBvtB,KAAK2tB,iBAAkBJ,EAAW1M,QAGtCgN,EAAO5qB,KAAM,IAAI,GAAOjD,KAAK6gB,MAAO0M,EAAW1M,QAG3C7gB,KAAK2tB,iBAAkBJ,EAAWzM,MAGtC+M,EAAO5qB,KAAM,IAAI,GAAOsqB,EAAWzM,IAAK9gB,KAAK8gB,OAI9C+M,EAAO5qB,KAAMjD,KAAK0rB,SAGZmC,EAwBR,gBAAiBN,GAChB,GAAKvtB,KAAK8tB,eAAgBP,GAAe,CAGxC,IAAIQ,EAAmB/tB,KAAK6gB,MACxBmN,EAAiBhuB,KAAK8gB,IAc1B,OAZK9gB,KAAK2tB,iBAAkBJ,EAAW1M,SAGtCkN,EAAmBR,EAAW1M,OAG1B7gB,KAAK2tB,iBAAkBJ,EAAWzM,OAGtCkN,EAAiBT,EAAWzM,KAGtB,IAAI,GAAOiN,EAAkBC,GAIrC,OAAO,KAaR,UAAW9rB,EAAU,IAGpB,OAFAA,EAAQwoB,WAAa1qB,KAEd,IAAI,GAAYkC,GASxB,oBACC,OAAOlC,KAAK6gB,MAAMoN,kBAAmBjuB,KAAK8gB,KAU3C,sBACC,GAAK9gB,KAAKytB,YACT,OAAO,KAGR,IAAIN,EAAiBntB,KAAK6gB,MAAMuM,UAC5BC,EAAgBrtB,KAAK8gB,IAAIwM,WAmB7B,OARKttB,KAAK6gB,MAAM9D,OAAO5c,GAAI,UAAaH,KAAK6gB,MAAM+K,SAAW5rB,KAAK6gB,MAAM9D,OAAOmR,cAC/Ef,EAAiBntB,KAAK6gB,MAAM9D,OAAOmR,aAG/BluB,KAAK8gB,IAAI/D,OAAO5c,GAAI,UAAaH,KAAK8gB,IAAIoL,WAAalsB,KAAK8gB,IAAI/D,OAAOoR,kBAC3Ed,EAAgBrtB,KAAK8gB,IAAI/D,OAAOoR,iBAG5BhB,GAAkBA,EAAehtB,GAAI,YAAegtB,IAAmBE,EACpEF,EAGD,KAQR,QACC,OAAO,IAAI,GAAOntB,KAAK6gB,MAAO7gB,KAAK8gB,KAiBpC,UAAY5e,EAAU,IACrBA,EAAQwoB,WAAa1qB,KACrBkC,EAAQ+oB,kBAAmB,EAE3B,MAAM0B,EAAa,IAAI,GAAYzqB,GAEnC,IAAM,MAAM1D,KAASmuB,QACdnuB,EAAM6D,KAiBd,cAAgBH,EAAU,IACzBA,EAAQwoB,WAAa1qB,KAErB,MAAM2sB,EAAa,IAAI,GAAYzqB,SAE7ByqB,EAAW9B,SAEjB,IAAM,MAAMrsB,KAASmuB,QACdnuB,EAAM6tB,aAmBd,GAAIpsB,GACH,MAAgB,UAATA,GAA6B,eAATA,EAS5B,eAAgBstB,GACf,OAAOvtB,KAAK6gB,MAAMhD,SAAU0P,EAAWzM,MAAS9gB,KAAK8gB,IAAIoM,QAASK,EAAW1M,OAe9E,oCAAqCuN,EAAchC,EAAaiC,EAAY9B,GAC3E,OAAO,IAAIvsB,KACV,IAAI,GAAUouB,EAAchC,GAC5B,IAAI,GAAUiC,EAAY9B,IAa5B,mCAAoC1B,EAAU4B,GAC7C,MAAM5L,EAAQgK,EACR/J,EAAM+J,EAASyD,aAAc7B,GAEnC,OAAOA,EAAQ,EAAI,IAAIzsB,KAAM6gB,EAAOC,GAAQ,IAAI9gB,KAAM8gB,EAAKD,GAW5D,iBAAkBjC,GACjB,OAAO5e,KAAKuuB,6BAA8B3P,EAAS,EAAGA,EAASA,EAAQkI,YAUxE,iBAAkBzkB,GACjB,MAAM2G,EAAO3G,EAAKlC,GAAI,cAAiBkC,EAAKmsB,WAAa,EAEzD,OAAOxuB,KAAKyuB,4BAA6B,GAAStC,cAAe9pB,GAAQ2G,IAK3E,SAASikB,GAAiBzuB,GACzB,SAAKA,EAAM6D,KAAKlC,GAAI,sBAAwB3B,EAAM6D,KAAKlC,GAAI,cC9f7C,SAAS,GAAOoU,GAC9B,IAAI/R,EAAQ,EAEZ,IAAM,MAAMksB,KAAKna,EAChB/R,IAGD,OAAOA,ECOO,MAAM,GAiEpB,YAAamsB,EAAa,KAAMC,EAAe1sB,GAO9ClC,KAAK6uB,QAAU,GAQf7uB,KAAK8uB,oBAAqB,EAQ1B9uB,KAAK+uB,SAAU,EAQf/uB,KAAKgvB,oBAAsB,GAE3BhvB,KAAKimB,MAAO0I,EAAYC,EAAe1sB,GASxC,aACC,OAAOlC,KAAK+uB,QASb,yBACC,OAAO/uB,KAAKgvB,oBAYb,aACC,IAAMhvB,KAAK6uB,QAAQ9sB,OAClB,OAAO,KAER,MAAMktB,EAAQjvB,KAAK6uB,QAAS7uB,KAAK6uB,QAAQ9sB,OAAS,GAGlD,OAFe/B,KAAK8uB,mBAAqBG,EAAMnO,IAAMmO,EAAMpO,OAE7C6K,QASf,YACC,IAAM1rB,KAAK6uB,QAAQ9sB,OAClB,OAAO,KAER,MAAMktB,EAAQjvB,KAAK6uB,QAAS7uB,KAAK6uB,QAAQ9sB,OAAS,GAGlD,OAFc/B,KAAK8uB,mBAAqBG,EAAMpO,MAAQoO,EAAMnO,KAE/C4K,QASd,kBACC,OAA2B,IAApB1rB,KAAKkvB,YAAoBlvB,KAAK6uB,QAAS,GAAIpB,YAQnD,iBACC,OAAOztB,KAAK6uB,QAAQ9sB,OAQrB,iBACC,OAAQ/B,KAAKytB,aAAeztB,KAAK8uB,mBASlC,sBACC,OAAK9uB,KAAKmvB,OACFnvB,KAAKmvB,OAAO9E,gBAGb,KAQR,aACC,IAAM,MAAM4E,KAASjvB,KAAK6uB,cACnBI,EAAMvD,QAYd,gBACC,IAAI0D,EAAQ,KAEZ,IAAM,MAAMH,KAASjvB,KAAK6uB,QACnBO,IAASH,EAAMpO,MAAMhD,SAAUuR,EAAMvO,SAC1CuO,EAAQH,GAIV,OAAOG,EAAQA,EAAM1D,QAAU,KAUhC,eACC,IAAI2D,EAAO,KAEX,IAAM,MAAMJ,KAASjvB,KAAK6uB,QACnBQ,IAAQJ,EAAMnO,IAAIoM,QAASmC,EAAKvO,OACrCuO,EAAOJ,GAIT,OAAOI,EAAOA,EAAK3D,QAAU,KAU9B,mBACC,MAAM4D,EAAatvB,KAAKuvB,gBAExB,OAAOD,EAAaA,EAAWzO,MAAM6K,QAAU,KAUhD,kBACC,MAAM8D,EAAYxvB,KAAKyvB,eAEvB,OAAOD,EAAYA,EAAU1O,IAAI4K,QAAU,KAW5C,QAASgE,GACR,GAAK1vB,KAAK2vB,QAAUD,EAAeC,OAClC,OAAO,EAGR,GAAK3vB,KAAK2vB,QAAU3vB,KAAK4vB,oBAAsBF,EAAeE,mBAC7D,OAAO,EAGR,GAAK5vB,KAAKkvB,YAAcQ,EAAeR,WACtC,OAAO,EACD,GAAyB,IAApBlvB,KAAKkvB,WAChB,OAAO,EAGR,IAAMlvB,KAAKmvB,OAAO7C,QAASoD,EAAeP,UAAanvB,KAAK6vB,MAAMvD,QAASoD,EAAeG,OACzF,OAAO,EAGR,IAAM,MAAMC,KAAa9vB,KAAK6uB,QAAU,CACvC,IAAIkB,GAAQ,EAEZ,IAAM,MAAMxC,KAAcmC,EAAeb,QACxC,GAAKiB,EAAUxD,QAASiB,GAAe,CACtCwC,GAAQ,EACR,MAIF,IAAMA,EACL,OAAO,EAIT,OAAO,EAYR,UAAWL,GACV,GAAK1vB,KAAKgwB,YAAcN,EAAeM,WACtC,OAAO,EAGR,MAAMC,EAAe,GAAOjwB,KAAKkwB,aAIjC,GAAKD,GAHgB,GAAOP,EAAeQ,aAI1C,OAAO,EAIR,GAAqB,GAAhBD,EACJ,OAAO,EAIR,IAAM,IAAIE,KAAUnwB,KAAKkwB,YAAc,CACtCC,EAASA,EAAOC,aAEhB,IAAIL,GAAQ,EAEZ,IAAM,IAAIM,KAAUX,EAAeQ,YAGlC,GAFAG,EAASA,EAAOD,aAEXD,EAAOtP,MAAMyL,QAAS+D,EAAOxP,QAAWsP,EAAOrP,IAAIwL,QAAS+D,EAAOvP,KAAQ,CAC/EiP,GAAQ,EACR,MAKF,IAAMA,EACL,OAAO,EAKT,OAAO,EAUR,qBACC,OAAyB,IAApB/vB,KAAKkvB,WACF,KAGDlvB,KAAKuvB,gBAAgBe,sBAgE7B,MAAO3B,EAAYC,EAAe1sB,GACjC,GAAoB,OAAfysB,EACJ3uB,KAAKuwB,WAAY,IACjBvwB,KAAKwwB,gBAAiB5B,QAChB,GAAKD,aAAsB,IAAaA,aAAsB,GACpE3uB,KAAKuwB,WAAY5B,EAAWuB,YAAavB,EAAWqB,YACpDhwB,KAAKwwB,gBAAiB,CAAEC,KAAM9B,EAAWgB,OAAQe,MAAO/B,EAAWiB,0BAC7D,GAAKjB,aAAsB,GACjC3uB,KAAKuwB,WAAY,CAAE5B,GAAcC,GAAiBA,EAAc+B,UAChE3wB,KAAKwwB,gBAAiB5B,QAChB,GAAKD,aAAsB,GACjC3uB,KAAKuwB,WAAY,CAAE,IAAI,GAAO5B,KAC9B3uB,KAAKwwB,gBAAiB5B,QAChB,GAAKD,aAAsB,GAAO,CACxC,MAAMgC,IAAazuB,KAAaA,EAAQyuB,SACxC,IAAI1B,EAEJ,QAAuB3oB,IAAlBsoB,EAMJ,MAAM,IAAI,KAAe,iDAAkD5uB,MAE3EivB,EAD4B,MAAjBL,EACH,GAAMgC,UAAWjC,GACG,MAAjBC,EACH,GAAMiC,UAAWlC,GAEjB,IAAI,GAAO,GAAS7D,UAAW6D,EAAYC,IAGpD5uB,KAAKuwB,WAAY,CAAEtB,GAAS0B,GAC5B3wB,KAAKwwB,gBAAiBtuB,OAChB,KAAKoS,GAAYqa,GAWvB,MAAM,IAAI,KAAe,sCAAuC3uB,MARhEA,KAAKuwB,WAAY5B,EAAYC,GAAiBA,EAAc+B,UAC5D3wB,KAAKwwB,gBAAiB5B,GAUvB5uB,KAAKqU,KAAM,UAcZ,SAAU0Y,EAAgBzgB,GACzB,GAAqB,OAAhBtM,KAAKmvB,OAMT,MAAM,IAAI,KAAe,oCAAqCnvB,MAG/D,MAAM8wB,EAAW,GAAShG,UAAWiC,EAAgBzgB,GAErD,GAA2C,QAAtCwkB,EAASjE,YAAa7sB,KAAK6vB,OAC/B,OAGD,MAAMV,EAASnvB,KAAKmvB,OAEpBnvB,KAAK6uB,QAAQzlB,MAE0B,UAAlC0nB,EAASjE,YAAasC,GAC1BnvB,KAAK+wB,UAAW,IAAI,GAAOD,EAAU3B,IAAU,GAE/CnvB,KAAK+wB,UAAW,IAAI,GAAO5B,EAAQ2B,IAGpC9wB,KAAKqU,KAAM,UAkBZ,GAAIpU,GACH,MAAgB,cAATA,GAAiC,mBAATA,EAahC,WAAY+wB,EAAWC,GAAiB,GAGvCD,EAAY7nB,MAAMiK,KAAM4d,GAExBhxB,KAAK6uB,QAAU,GAEf,IAAM,MAAMI,KAAS+B,EACpBhxB,KAAK+wB,UAAW9B,GAGjBjvB,KAAK8uB,qBAAuBmC,EAgB7B,gBAAiB/uB,EAAU,IAC1BlC,KAAK+uB,UAAY7sB,EAAQuuB,KACzBzwB,KAAKgvB,oBAAsB9sB,EAAQuuB,MAAOvuB,EAAQwuB,OAAc,GAoBjE,UAAWzB,EAAOe,GAAa,GAC9B,KAAQf,aAAiB,IAMxB,MAAM,IAAI,KACT,qCACAjvB,MAIFA,KAAKkxB,WAAYjC,GACjBjvB,KAAK8uB,qBAAuBkB,EAY7B,WAAYf,GACX,IAAM,MAAMkC,KAAenxB,KAAK6uB,QAC/B,GAAKI,EAAMnB,eAAgBqD,GAQ1B,MAAM,IAAI,KACT,kCACAnxB,KACA,CAAEoxB,WAAYnC,EAAOoC,kBAAmBF,IAK3CnxB,KAAK6uB,QAAQ5rB,KAAM,IAAI,GAAOgsB,EAAMpO,MAAOoO,EAAMnO,OAUnDtM,GAAK,GAAW,ICtqBD,MAAM,GAyDpB,YAAama,EAAa,KAAMC,EAAe1sB,GAO9ClC,KAAKsxB,WAAa,IAAI,GAGtBtxB,KAAKsxB,WAAWC,SAAU,UAAW3d,GAAI5T,MAGzCA,KAAKsxB,WAAWrL,MAAO0I,EAAYC,EAAe1sB,GASnD,aACC,OAAOlC,KAAKsxB,WAAW3B,OASxB,yBACC,OAAO3vB,KAAKsxB,WAAW1B,mBAYxB,aACC,OAAO5vB,KAAKsxB,WAAWnC,OASxB,YACC,OAAOnvB,KAAKsxB,WAAWzB,MASxB,kBACC,OAAO7vB,KAAKsxB,WAAW7D,YAQxB,iBACC,OAAOztB,KAAKsxB,WAAWpC,WAQxB,iBACC,OAAOlvB,KAAKsxB,WAAWtB,WASxB,sBACC,OAAOhwB,KAAKsxB,WAAWjH,gBAQxB,cACC,OAAOrqB,KAAKsxB,WAAWzC,QAQxB,mBACQ7uB,KAAKsxB,WAAWpB,YAWxB,gBACC,OAAOlwB,KAAKsxB,WAAW/B,gBAUxB,eACC,OAAOvvB,KAAKsxB,WAAW7B,eAUxB,mBACC,OAAOzvB,KAAKsxB,WAAWE,mBAUxB,kBACC,OAAOxxB,KAAKsxB,WAAWG,kBAUxB,qBACC,OAAOzxB,KAAKsxB,WAAWI,qBAWxB,QAAShC,GACR,OAAO1vB,KAAKsxB,WAAWhF,QAASoD,GAYjC,UAAWA,GACV,OAAO1vB,KAAKsxB,WAAWK,UAAWjC,GAoBnC,GAAIzvB,GACH,MAAgB,cAATA,GACE,qBAARA,GACQ,kBAARA,GACQ,0BAARA,EA8DF,OAAQ0uB,EAAYC,EAAe1sB,GAClClC,KAAKsxB,WAAWrL,MAAO0I,EAAYC,EAAe1sB,GAenD,UAAW6qB,EAAgBzgB,GAC1BtM,KAAKsxB,WAAWM,SAAU7E,EAAgBzgB,IAU5CkI,GAAK,GAAmB,IC5WT,MAAM,GAMpB,YAAawR,GAOZhmB,KAAKoqB,UAAY,IAAI,GAarBpqB,KAAK6xB,MAAQ,IAAI,GAAY,CAAEzc,WAAY,aAQ3CpV,KAAKgmB,gBAAkBA,EAUvBhmB,KAAKyJ,IAAK,cAAc,GAYxBzJ,KAAKyJ,IAAK,aAAa,GAYvBzJ,KAAKyJ,IAAK,eAAe,GAQzBzJ,KAAK8xB,YAAc,IAAIzZ,IAWxB,QAASva,EAAO,QACf,OAAOkC,KAAK6xB,MAAMzzB,IAAKN,GAkDxB,kBAAmBi0B,GAClB/xB,KAAK8xB,YAAYljB,IAAKmjB,GAMvB,UACC/xB,KAAK6xB,MAAMxnB,IAAKxN,GAAQA,EAAKqd,WAC7Bla,KAAKsR,gBASN,gBAAiB0gB,GAChB,IAAIC,GAAW,EAEf,GACC,IAAM,MAAM/gB,KAAYlR,KAAK8xB,YAG5B,GAFAG,EAAW/gB,EAAU8gB,GAEhBC,EACJ,YAGOA,IAgBZzd,GAAK,GAAU,ICjLA,MAAM,WAAyB,GAa7C,YAAaxT,EAAUlD,EAAM0nB,EAAO1d,GACnClI,MAAOoB,EAAUlD,EAAM0nB,EAAO1d,GAQ9B9H,KAAK6mB,gBAAkB,GAQvB7mB,KAAKkyB,UA7CkB,GAsDvBlyB,KAAKmyB,IAAM,KAWXnyB,KAAKoyB,aAAe,KASrB,eACC,OAAOpyB,KAAKkyB,UAUb,SACC,OAAOlyB,KAAKmyB,IAeb,wBACC,GAAiB,OAAZnyB,KAAKsC,GAMT,MAAM,IAAI,KACT,oDACAtC,MAIF,OAAO,IAAIqY,IAAKrY,KAAKoyB,cA6BtB,GAAInyB,EAAMnC,EAAO,MAChB,OAAMA,EAMEA,IAASkC,KAAKlC,OACX,qBAATmC,GAAwC,0BAATA,GAEtB,YAATA,GAA+B,iBAATA,GARP,qBAATA,GAAwC,0BAATA,GAE5B,YAATA,GAA+B,iBAATA,GACb,SAATA,GAA4B,cAATA,EA+BtB,UAAWkmB,GAEV,OAAiB,OAAZnmB,KAAKsC,IAAmC,OAApB6jB,EAAa7jB,GAC9BtC,KAAKsC,KAAO6jB,EAAa7jB,GAG1B1C,MAAM+xB,UAAWxL,IAAkBnmB,KAAKyQ,UAAY0V,EAAa1V,SAWzE,OAAQ8V,GACP,MAAMK,EAAShnB,MAAM+mB,OAAQJ,GAQ7B,OALAK,EAAOsL,UAAYlyB,KAAKkyB,UAGxBtL,EAAOuL,IAAMnyB,KAAKmyB,IAEXvL,GAcT,SAAS,KAER,GAAKyL,GAAoBryB,MACxB,OAAO,KAGR,IAAI4e,EAAU5e,KAAK+c,OAGnB,KAAQ6B,GAAWA,EAAQze,GAAI,qBAAuB,CACrD,GAAKkyB,GAAoBzT,GAAY,EACpC,OAAO,KAGRA,EAAUA,EAAQ7B,OAGnB,OAAM6B,GAAWyT,GAAoBzT,GAAY,EACzC,KAID5e,KAAK8mB,WAOb,SAASuL,GAAoBzT,GAC5B,OAAOzV,MAAMiK,KAAMwL,EAAQ8H,eAAgB1iB,OAAQ4a,IAAYA,EAAQze,GAAI,cAAgB4B,OAnC5F,GAAiBuwB,iBAtNQ,GCQV,MAAM,WAAqB,GAezC,YAAatxB,EAAUlD,EAAM0nB,EAAO1d,GACnClI,MAAOoB,EAAUlD,EAAM0nB,EAAO1d,GAQ9B9H,KAAK6mB,gBAAkB,GA6BxB,GAAI5mB,EAAMnC,EAAO,MAChB,OAAMA,EAMEA,IAASkC,KAAKlC,OACX,iBAATmC,GAAoC,sBAATA,GAClB,YAATA,GAA+B,iBAATA,GAPP,iBAATA,GAAoC,sBAATA,GAExB,YAATA,GAA+B,iBAATA,GACb,SAATA,GAA4B,cAATA,EAgBtB,aAAcyC,EAAOqkB,GACpB,GAAKA,IAAWA,aAAiB,IAAQ5d,MAAMiK,KAAM2T,GAAQhlB,OAAS,GAMrE,MAAM,IAAI,KACT,+BACA,CAAE/B,KAAM+mB,KASZ,SAAS,KACR,OAAO,KCvGR,MAAMwL,GAAYC,UAAUD,UAAUE,cAkEvB,OA3DH,CAOXC,MA4DM,SAAgBH,GACtB,OAAOA,EAAUzf,QAAS,cAAiB,EA7DpC4f,CAAOH,IAQdI,QA8DM,SAAkBJ,GACxB,QAASA,EAAU7W,MAAO,cA/DjBiX,CAASJ,IAQlBK,SAgEM,SAAmBL,GACzB,OAAOA,EAAUzf,QAAS,kBAAqB,IAAwC,IAAnCyf,EAAUzf,QAAS,UAjE7D8f,CAAUL,IAQpBM,UAkEM,SAAoBN,GAC1B,OAAOA,EAAUzf,QAAS,YAAe,EAnE9B+f,CAAWN,IAQtBO,QAoEM,SAAkBP,GAGxB,OAAOA,EAAUzf,QAAS,YAAe,GAAKyf,EAAUzf,QAAS,SAAY,EAvEpEggB,CAASP,IAQlBQ,SAAU,CAQTC,iCAiEK,WACN,IAAIC,GAAc,EAKlB,IAECA,EAA8D,IAAhD,IAAIC,OAAQ,IAAIjpB,OAAQ,WAAY,MACjD,MAAQ7J,IAIV,OAAO6yB,EA9E4BD,KC3DpC,MAAMG,GAAuB,CAC5B,IAAK,OACL,IAAK,QACL,IAAK,OAGAC,GAAuB,CAC5B,KAAQ,IACR,MAAS,IACT,IAAO,KAeKC,GAuJb,WACC,MAAMA,EAAW,CAChBC,UAAW,GACXC,QAAS,GACTC,WAAY,GACZC,UAAW,GACXC,UAAW,EACX3f,OAAQ,GACR4f,MAAO,GACPC,MAAO,GACPC,IAAK,GACLC,IAAK,EAILC,KAAM,QAGNC,IAAK,QACLvH,MAAO,QACPwH,IAAK,SAIN,IAAM,IAAIC,EAAO,GAAIA,GAAQ,GAAIA,IAAS,CACzC,MAAMC,EAASroB,OAAOsoB,aAAcF,GAEpCb,EAAUc,EAAO1B,eAAkByB,EAIpC,IAAM,IAAIA,EAAO,GAAIA,GAAQ,GAAIA,IAChCb,EAAUa,EAAO,IAAOA,EAIzB,IAAM,IAAIA,EAAO,IAAKA,GAAQ,IAAKA,IAClCb,EAAU,KAAQa,EAAO,MAAUA,EAGpC,OAAOb,EA/LgBgB,GAWjB,SAASC,GAASx1B,GACxB,IAAIy1B,EAEJ,GAAmB,iBAAPz1B,GAGX,GAFAy1B,EAAUlB,GAAUv0B,EAAI2zB,gBAElB8B,EAOL,MAAM,IAAI,KAAe,uBAAwB,KAAM,CAAEz1B,aAG1Dy1B,EAAUz1B,EAAIy1B,SACXz1B,EAAI01B,OAASnB,GAASY,IAAM,IAC5Bn1B,EAAI21B,QAAUpB,GAASU,KAAO,IAC9Bj1B,EAAI41B,SAAWrB,GAAS5G,MAAQ,GAGpC,OAAO8H,EAqBD,SAASI,GAAgBC,GAK/B,MAJyB,iBAAbA,IACXA,EAAYC,GAAoBD,IAG1BA,EACLvqB,IAAKvL,GAAuB,iBAAPA,EAAoBw1B,GAASx1B,GAAQA,GAC1DuY,OAAQ,CAAEvY,EAAKg2B,IAASA,EAAMh2B,EAAK,GAU/B,SAASi2B,GAAqBH,GACpC,OAAM,GAAIlC,MAIHmC,GAAoBD,GAEzBvqB,IAAKvL,GAAOs0B,GAAsBt0B,EAAI2zB,gBAAmB3zB,GAGzDuY,OAAQ,CAAE7Y,EAAOM,IACZN,EAAMiJ,OAAQ,KAAO0rB,GAClB30B,EAAQM,EAERN,EAAQ,IAAMM,GAZhB81B,EAuBF,SAASI,GAAgBT,GAC/B,OAAOA,GAAWlB,GAASG,YAC1Be,GAAWlB,GAASC,WACpBiB,GAAWlB,GAASE,SACpBgB,GAAWlB,GAASI,UAef,SAASwB,GAAmCV,EAAS/Y,GAC3D,MAAM0Z,EAA4C,QAA7B1Z,EAErB,OAAS+Y,GACR,KAAKlB,GAASC,UACb,OAAO4B,EAAe,OAAS,QAEhC,KAAK7B,GAASG,WACb,OAAO0B,EAAe,QAAU,OAEjC,KAAK7B,GAASE,QACb,MAAO,KAER,KAAKF,GAASI,UACb,MAAO,QAgBH,SAAS0B,GAAuBZ,EAAS/Y,GAC/C,MAAM4Z,EAA4BH,GAAmCV,EAAS/Y,GAE9E,MAAqC,SAA9B4Z,GAAsE,UAA9BA,EA8ChD,SAASP,GAAoBD,GAC5B,OAAOA,EAAUrlB,MAAO,YCvMV,MAAM,WAAkB,GAetC,YAAavO,EAAUlD,EAAMwF,EAAYwE,GACxClI,MAAOoB,EAAUlD,EAAMwF,EAAYwE,GAQnC9H,KAAK6mB,gBAAkB,GA6BxB,GAAI5mB,EAAMnC,EAAO,MAChB,OAAMA,EAMEA,IAASkC,KAAKlC,OACX,cAATmC,GAAiC,mBAATA,GACf,YAATA,GAA+B,iBAATA,GAPP,cAATA,GAAiC,mBAATA,GAErB,YAATA,GAA+B,iBAATA,GACb,SAATA,GAA4B,cAATA,EAgBtB,aAAcyC,EAAOqkB,GACpB,GAAKA,IAAWA,aAAiB,IAAQ5d,MAAMiK,KAAM2T,GAAQhlB,OAAS,GAMrE,MAAM,IAAI,KAAe,4BAA6B/B,MAwBxD,OAAQq1B,GACP,OAAOr1B,KAAKs1B,aAAcD,GAU3B,aAAcA,GACb,MAAME,EAAaF,EAAYhyB,cAAerD,KAAKlC,MAEnD,IAAM,MAAMgB,KAAOkB,KAAKw1B,mBACvBD,EAAW7xB,aAAc5E,EAAKkB,KAAKof,aAActgB,IAGlD,OAAOy2B,GAaF,SAASE,GAAyBC,GACxCA,EAAK10B,SAASkoB,GAAI,UAAW,CAAEpS,EAAKnX,IAarC,SAA4BmX,EAAKnX,EAAMg2B,GACtC,GAAKh2B,EAAK40B,SAAWlB,GAASG,WAAa,CAC1C,MAAMoC,EAAej2B,EAAKk2B,UAAUC,cAAcC,YAAYC,eACxDC,EAAmD,GAA3BL,EAAa1G,YAAmB0G,EAAaM,WAAY,GAAIC,UAG3F,GAAKF,GAAyBt2B,EAAK+0B,SAAW,CAC7C,MAAM0B,EAAYR,EAAaS,UACzBC,EAAYV,EAAaW,YAEzBC,EAAeb,EAAac,kBAAmBL,EAAWE,GAGhE,GAAsB,OAAjBE,EACJ,OAID,IAAIE,GAAyB,EAE7B,MAAMC,EAAmBH,EAAaxJ,wBAAyBxuB,IACzDA,EAAM6D,KAAKlC,GAAI,eAEnBu2B,GAAyB,MAIrBl4B,EAAM6D,KAAKlC,GAAI,eAAiB3B,EAAM6D,KAAKlC,GAAI,uBAUrD,GAAKu2B,EAAyB,CAC7B,MAAME,EAAiBjB,EAAakB,kBAAmBF,GAElDV,EAEJL,EAAakB,SAAUF,EAAe7Z,OAAQ6Z,EAAetqB,QAG7DspB,EAAamB,OAAQH,EAAe7Z,OAAQ6Z,EAAetqB,WA1DjB0qB,CAAmBlgB,EAAKnX,EAAM+1B,EAAKC,eAMlF,SAAS,KACR,OAAO,KCnJO,MAAM,WAAmB,GAevC,YAAa30B,EAAUlD,EAAM0nB,EAAO1d,GACnClI,MAAOoB,EAAUlD,EAAM0nB,EAAO1d,GAQ9B9H,KAAK6mB,gBAAkB,GA8BxB,GAAI5mB,EAAMnC,EAAO,MAChB,OAAMA,EAOEA,IAASkC,KAAKlC,OACX,eAATmC,GAAkC,oBAATA,GAChB,YAATA,GAA+B,iBAATA,GARP,eAATA,GAAkC,oBAATA,GAE/BA,IAASD,KAAKlC,MAAQmC,IAAS,QAAUD,KAAKlC,MACrC,YAATmC,GAA+B,iBAATA,GACb,SAATA,GAA4B,cAATA,EAgBtB,aAAcyC,EAAOqkB,GACpB,GAAKA,IAAWA,aAAiB,IAAQ5d,MAAMiK,KAAM2T,GAAQhlB,OAAS,GAMrE,MAAM,IAAI,KACT,6BACA,CAAE/B,KAAM+mB,KA0BZ,SAAS,KACR,OAAO,KCzHO,MAAM,GASpB,YAAa/lB,EAAU8G,GAOtB9H,KAAKgB,SAAWA,EAQhBhB,KAAK2lB,UAAY,GAEZ7d,GACJ9H,KAAK4lB,aAAc,EAAG9d,GAWxB,CAAExJ,OAAOiW,YACR,OAAOvU,KAAK2lB,UAAWrnB,OAAOiW,YAS/B,iBACC,OAAOvU,KAAK2lB,UAAU5jB,OASvB,cACC,OAA2B,IAApB/B,KAAK8mB,WASb,WACC,OAAO9mB,KASR,aACC,OAAO,KAkBR,GAAIC,GACH,MAAgB,qBAATA,GAAwC,0BAATA,EAUvC,aAAc0V,GACb,OAAO3V,KAAK4lB,aAAc5lB,KAAK8mB,WAAYnR,GAS5C,SAAUjT,GACT,OAAO1C,KAAK2lB,UAAWjjB,GASxB,cAAe6P,GACd,OAAOvS,KAAK2lB,UAAU7S,QAASP,GAQhC,cACC,OAAOvS,KAAK2lB,UAAWrnB,OAAOiW,YAW/B,aAAc7R,EAAOiT,GACpB3V,KAAK+d,YAAa,WAAY/d,MAC9B,IAAIwC,EAAQ,EAEZ,MAAMukB,EA0ER,SAAoB/lB,EAAU+lB,GAE7B,GAAqB,iBAATA,EACX,MAAO,CAAE,IAAI,GAAM/lB,EAAU+lB,IAGxBzS,GAAYyS,KACjBA,EAAQ,CAAEA,IAIX,OAAO5d,MAAMiK,KAAM2T,GACjB1c,IAAKkI,GACe,iBAARA,EACJ,IAAI,GAAMvR,EAAUuR,GAGvBA,aAAgB,GACb,IAAI,GAAMvR,EAAUuR,EAAK5S,MAG1B4S,GA/FM,CAAWvS,KAAKgB,SAAU2U,GAExC,IAAM,MAAMpD,KAAQwU,EAEE,OAAhBxU,EAAKwK,QACTxK,EAAK2D,UAGN3D,EAAKwK,OAAS/c,KAEdA,KAAK2lB,UAAU7f,OAAQpD,EAAO,EAAG6P,GACjC7P,IACAF,IAGD,OAAOA,EAUR,gBAAiBE,EAAOukB,EAAU,GACjCjnB,KAAK+d,YAAa,WAAY/d,MAE9B,IAAM,IAAIzC,EAAImF,EAAOnF,EAAImF,EAAQukB,EAAS1pB,IACzCyC,KAAK2lB,UAAWpoB,GAAIwf,OAAS,KAG9B,OAAO/c,KAAK2lB,UAAU7f,OAAQpD,EAAOukB,GAWtC,YAAahnB,EAAMsS,GAClBvS,KAAKqU,KAAM,UAAYpU,EAAMsS,IAwB/BiC,GAAK,GAAkB,IC5MR,MAAM,GAIpB,YAAaxT,GAOZhB,KAAKgB,SAAWA,EAShBhB,KAAKi3B,aAAe,IAAInjB,IAmEzB,aAAc6a,EAAYC,EAAe1sB,GACxClC,KAAKgB,SAASopB,UAAU8M,OAAQvI,EAAYC,EAAe1sB,GAa5D,kBAAmB6qB,EAAgBzgB,GAClCtM,KAAKgB,SAASopB,UAAU+M,UAAWpK,EAAgBzgB,GAWpD,WAAY3M,GACX,OAAO,IAAI,GAAMK,KAAKgB,SAAUrB,GAsBjC,uBAAwB7B,EAAMwF,EAAYpB,EAAU,IACnD,MAAMk1B,EAAmB,IAAI,GAAkBp3B,KAAKgB,SAAUlD,EAAMwF,GAUpE,OARKpB,EAAQuO,WACZ2mB,EAAiBlF,UAAYhwB,EAAQuO,UAGjCvO,EAAQI,KACZ80B,EAAiBjF,IAAMjwB,EAAQI,IAGzB80B,EAqBR,uBAAwBt5B,EAAMwF,GAC7B,OAAO,IAAI,GAAkBtD,KAAKgB,SAAUlD,EAAMwF,GAgBnD,sBAAuBxF,EAAMwF,GAC5B,MAAM+mB,EAAkB,IAAI,GAAiBrqB,KAAKgB,SAAUlD,EAAMwF,GAGlE,OAFA+mB,EAAgBgN,UAAYr3B,KAAKgB,SAE1BqpB,EAaR,mBAAoBvsB,EAAMwF,GACzB,OAAO,IAAI,GAActD,KAAKgB,SAAUlD,EAAMwF,GA4B/C,gBAAiBxF,EAAMwF,EAAYg0B,GAClC,MAAMC,EAAY,IAAI,GAAWv3B,KAAKgB,SAAUlD,EAAMwF,GAMtD,OAJKg0B,IACJC,EAAUC,OAASF,GAGbC,EA2BR,iBAAkBz5B,EAAMwF,EAAYg0B,GACnC,MAAMG,EAAa,IAAI,GAAYz3B,KAAKgB,SAAUlD,EAAMwF,GAIxD,OAFAm0B,EAAWD,OAASF,GAAkB,SAE/BG,EAYR,aAAc34B,EAAKN,EAAOogB,GACzBA,EAAQ8Y,cAAe54B,EAAKN,GAW7B,gBAAiBM,EAAK8f,GACrBA,EAAQ+Y,iBAAkB74B,GAY3B,SAAUsnB,EAAWxH,GACpBA,EAAQgZ,UAAWxR,GAYpB,YAAaA,EAAWxH,GACvBA,EAAQiZ,aAAczR,GAoBvB,SAAUlnB,EAAUV,EAAOogB,GACrB,EAAe1f,SAA0BoH,IAAZsY,IACjCA,EAAUpgB,GAGXogB,EAAQkZ,UAAW54B,EAAUV,GAgB9B,YAAaU,EAAU0f,GACtBA,EAAQmZ,aAAc74B,GAWvB,kBAAmBJ,EAAKN,EAAOogB,GAC9BA,EAAQ6L,mBAAoB3rB,EAAKN,GAUlC,qBAAsBM,EAAK8f,GAC1B,OAAOA,EAAQoZ,sBAAuBl5B,GAwCvC,gBAAiBm5B,GAChB,OAAKA,aAA2B,GACxBj4B,KAAKk4B,iBAAkBD,GAEvBj4B,KAAKm4B,sBAAuBF,GA2BrC,eAAgBpN,GACf,MAAMjM,EAAUiM,EAAS9N,OAEzB,IAAQ6B,EAAQze,GAAI,oBAMnB,MAAM,IAAI,KAAe,0CAA2CH,KAAKgB,UAG1E,IAAM4d,EAAQ7B,OAMb,MAAM,IAAI,KAAe,yBAA0B/c,KAAKgB,UAGzD,GAAK6pB,EAASqB,UACb,OAAO,GAASC,cAAevN,GACzB,IAAMiM,EAASe,QAAU,CAC/B,MAAMwM,EAAaxZ,EAAQ+H,QAAQ,GAEnC3mB,KAAK2D,OAAQ,GAASkoB,aAAcjN,GAAWwZ,GAE/C,MAAMC,EAAc,IAAI,GAAOxN,EAAU,GAASC,UAAWlM,EAAS,QAChE0Z,EAAiB,IAAI,GAAUF,EAAY,GAEjDp4B,KAAKu4B,KAAMF,EAAaC,GAGzB,OAAO,GAASzM,aAAcjN,GA6B/B,gBAAiBiM,GAChB,MAAM2N,EAAiB3N,EAASve,OAC1BmsB,EAAiB5N,EAAS9N,OAGhC,GAAK0b,EAAet4B,GAAI,SACvB,OAAO0qB,EAIR,GAAK4N,EAAet4B,GAAI,qBAAsD,IAA9Bs4B,EAAe3R,WAAmB,CACjF,MAAM/J,EAAS0b,EAAe1b,OACxBzQ,EAASmsB,EAAe/1B,MAK9B,OAHA+1B,EAAeviB,UACflW,KAAK04B,+BAAgCD,GAE9Bz4B,KAAK24B,gBAAiB,IAAI,GAAU5b,EAAQzQ,IAGpD,MAAMghB,EAAamL,EAAevb,SAAUsb,EAAiB,GACvDpL,EAAYqL,EAAevb,SAAUsb,GAG3C,IAAMlL,IAAeF,EACpB,OAAOvC,EAIR,GAAKyC,EAAWntB,GAAI,UAAaitB,EAAUjtB,GAAI,SAC9C,OAAOy4B,GAAgBtL,EAAYF,GAG/B,GAAKE,EAAWntB,GAAI,qBAAwBitB,EAAUjtB,GAAI,qBAAwBmtB,EAAWqE,UAAWvE,GAAc,CAE1H,MAAM5qB,EAAQ8qB,EAAWxG,WAQzB,OAPAwG,EAAWuL,aAAczL,EAAU1G,eAEnC0G,EAAUlX,UACVlW,KAAK04B,+BAAgCtL,GAI9BptB,KAAK24B,gBAAiB,IAAI,GAAUrL,EAAY9qB,IAGxD,OAAOqoB,EAqBR,gBAAiBA,GAChB,MAAMiO,EAAOjO,EAASyC,WAChB/B,EAAOV,EAASuC,UAEtB,KAAM0L,GAASvN,GAASuN,EAAK34B,GAAI,qBAAyBorB,EAAKprB,GAAI,qBAMlE,MAAM,IAAI,KAAe,gDAAiDH,KAAKgB,UAGhF,MAAMqmB,EAAYyR,EAAK5b,SAAU4b,EAAKhS,WAAa,GAC7CiS,EAAc1R,aAAqB,GAAO,GAASyD,UAAWzD,EAAW,OAAU,GAASyD,UAAWgO,EAAM,OAKnH,OAHA94B,KAAKu4B,KAAM,GAAM3H,UAAWrF,GAAQ,GAAST,UAAWgO,EAAM,QAC9D94B,KAAKmE,OAAQ,GAAM0sB,UAAWtF,IAEvBwN,EAyBR,OAAQlO,EAAU9D,IA2tCnB,SAASiS,EAAuBjS,EAAOkS,GACtC,IAAM,MAAM1mB,KAAQwU,EAAQ,CAC3B,IAAMmS,GAAmBC,KAAQC,GAAa7mB,aAAgB6mB,GAgB7D,MAAM,IAAI,KAAe,uCAAwCH,GAG5D1mB,EAAKpS,GAAI,UACd64B,EAAuBzmB,EAAKmU,cAAeuS,KA7uC5CD,CAHAjS,EAAQzS,GAAYyS,GAAU,IAAKA,GAAU,CAAEA,GAGjB/mB,KAAKgB,UAEnC,MAAMq4B,EAAYC,GAAoBzO,GAEtC,IAAMwO,EAML,MAAM,IAAI,KACT,yCACAr5B,KAAKgB,UAIP,MAAMu4B,EAAoBv5B,KAAKk4B,iBAAkBrN,GAAU,GACrD9oB,EAASs3B,EAAUzT,aAAc2T,EAAkBjtB,OAAQya,GAEjE,IAAM,MAAMxU,KAAQwU,EACnB/mB,KAAKw5B,0BAA2BjnB,GAGjC,MAAMknB,EAAcF,EAAkBjL,aAAcvsB,GAC9C8e,EAAQ7gB,KAAK24B,gBAAiBY,GAGpC,GAAgB,IAAXx3B,EACJ,OAAO,IAAI,GAAO8e,EAAOA,GACnB,CAEAA,EAAMyL,QAASiN,IACpBE,EAAYntB,SAGb,MAAMwU,EAAM9gB,KAAK24B,gBAAiBc,GAElC,OAAO,IAAI,GAAO5Y,EAAOC,IAgB3B,OAAQ4Y,GACP,MAAMzK,EAAQyK,aAAuB,GAAQA,EAAc,GAAM7I,UAAW6I,GAK5E,GAHAC,GAAwB1K,EAAOjvB,KAAKgB,UAG/BiuB,EAAMxB,YACV,OAAO,IAAI,GAAkBztB,KAAKgB,UAInC,MAAQ6f,MAAO+Y,EAAY9Y,IAAK+Y,GAAa75B,KAAKm4B,sBAAuBlJ,GAAO,GAC1E6K,EAAkBF,EAAW7c,OAE7Bva,EAAQq3B,EAASvtB,OAASstB,EAAWttB,OAGrCwJ,EAAUgkB,EAAgBhc,gBAAiB8b,EAAWttB,OAAQ9J,GAEpE,IAAM,MAAM+P,KAAQuD,EACnB9V,KAAK04B,+BAAgCnmB,GAItC,MAAMwnB,EAAgB/5B,KAAK24B,gBAAiBiB,GAK5C,OAJA3K,EAAMpO,MAAQkZ,EACd9K,EAAMnO,IAAMiZ,EAAcrO,QAGnB,IAAI,GAAkB1rB,KAAKgB,SAAU8U,GAa7C,MAAOmZ,EAAOrQ,GACb+a,GAAwB1K,EAAOjvB,KAAKgB,UAIpC,MAAMg5B,EAAS/K,EAAMgL,UAAW,CAC/BrP,UAAW,WACXK,kBAAkB,IAInB,IAAM,MAAMiP,KAAWF,EAAS,CAC/B,MAAM33B,EAAO63B,EAAQ73B,KACrB,IAAI83B,EAGJ,GAAK93B,EAAKlC,GAAI,YAAeye,EAAQ+S,UAAWtvB,GAE/C83B,EAAgB,GAAMtJ,UAAWxuB,QAE3B,IAAM63B,EAAQ7N,aAAaa,QAAS+B,EAAMpO,QAAWxe,EAAKlC,GAAI,cAAiB,CAErF,MAAMi6B,EAAgB/3B,EAAKmb,eAAepH,KAAMikB,GACxCA,EAASl6B,GAAI,YAAeye,EAAQ+S,UAAW0I,IAIlDD,IACJD,EAAgB,GAAMvJ,UAAWwJ,IAK9BD,IAECA,EAAcrZ,IAAIoM,QAAS+B,EAAMnO,OACrCqZ,EAAcrZ,IAAMmO,EAAMnO,KAGtBqZ,EAActZ,MAAMhD,SAAUoR,EAAMpO,SACxCsZ,EAActZ,MAAQoO,EAAMpO,OAI7B7gB,KAAKmE,OAAQg2B,KAiBhB,KAAM9B,EAAaC,GAClB,IAAIvR,EAEJ,GAAKuR,EAAepL,QAASmL,EAAYvX,KAAQ,CAGhD,MAAM/D,GAFNub,EAAiBt4B,KAAKk4B,iBAAkBI,GAAgB,IAE1Bvb,OACxBud,EAAcvd,EAAO+J,WAE3BuR,EAAcr4B,KAAKm4B,sBAAuBE,GAAa,GAEvDtR,EAAQ/mB,KAAKmE,OAAQk0B,GAErBC,EAAehsB,QAAYyQ,EAAO+J,WAAawT,OAE/CvT,EAAQ/mB,KAAKmE,OAAQk0B,GAGtB,OAAOr4B,KAAK2D,OAAQ20B,EAAgBvR,GAwBrC,KAAMkI,EAAO9P,GACZ,KAAQA,aAAqB,IAC5B,MAAM,IAAI,KACT,qCACAnf,KAAKgB,UAMP,GAFA24B,GAAwB1K,EAAOjvB,KAAKgB,UAE9BiuB,EAAMxB,YAGL,CAEN,IAAI5C,EAAWoE,EAAMpO,MAEhBgK,EAAS9N,OAAO5c,GAAI,aAi4BA4c,EAj4BmC8N,EAAS9N,QAk4BhE5T,MAAMiK,KAAM2J,EAAO2J,eAAgByS,KAAM1S,IAAUA,EAAMtmB,GAAI,iBAj4BjE0qB,EAAWA,EAASmC,wBAAyBxuB,GAASA,EAAM6D,KAAKlC,GAAI,eAGtE0qB,EAAW7qB,KAAKu6B,cAAe1P,EAAU1L,GACzC,MAAMqb,EAAgBx6B,KAAKgB,SAASopB,UAOpC,OAJKoQ,EAAc/M,aAAe+M,EAAchJ,mBAAmBlF,QAAS2C,EAAMpO,QACjF7gB,KAAKy6B,aAAc5P,GAGb,IAAI,GAAOA,GAjBlB,OAAO7qB,KAAK06B,WAAYzL,EAAO9P,GAs4BlC,IAA4BpC,EAv2B3B,OAAQkS,EAAO9P,GACd,KAAQA,aAAqB,IAO5B,MAAM,IAAI,KACT,uCACAnf,KAAKgB,UAOP,GAHA24B,GAAwB1K,EAAOjvB,KAAKgB,UAG/BiuB,EAAMxB,YACV,OAAOwB,EAIR,MAAQpO,MAAO+Y,EAAY9Y,IAAK+Y,GAAa75B,KAAKm4B,sBAAuBlJ,GAAO,GAC1E6K,EAAkBF,EAAW7c,OAG7B4d,EAAW36B,KAAK46B,gBAAiBd,EAAiBF,EAAWttB,OAAQutB,EAASvtB,OAAQ6S,GAGtF0B,EAAQ7gB,KAAK24B,gBAAiBgC,EAAS9Z,OAGvCA,EAAMyL,QAASqO,EAAS9Z,QAC7B8Z,EAAS7Z,IAAIxU,SAGd,MAAMwU,EAAM9gB,KAAK24B,gBAAiBgC,EAAS7Z,KAE3C,OAAO,IAAI,GAAOD,EAAOC,GAe1B,OAAQ+Z,EAASC,GAChB,MAAM1C,EAAa,IAAI,GAAkBp4B,KAAKgB,SAAU65B,EAASC,EAAYC,iBAM7E,OAJA/6B,KAAK2D,OAAQ,GAASkoB,aAAciP,GAAe1C,GACnDp4B,KAAKu4B,KAAM,GAAM3H,UAAWkK,GAAe,GAAShQ,UAAWsN,EAAY,IAC3Ep4B,KAAKmE,OAAQ,GAAM0sB,UAAWiK,IAEvB1C,EAiBR,yBAA0B4C,GACzBh7B,KAAKi3B,aAAaljB,OAAQinB,GAoB3B,iBAAkBjO,EAAgBzgB,GACjC,OAAO,GAASwe,UAAWiC,EAAgBzgB,GAS5C,oBAAqBjK,GACpB,OAAO,GAASwpB,aAAcxpB,GAS/B,qBAAsBA,GACrB,OAAO,GAAS8pB,cAAe9pB,GAYhC,YAAawe,EAAOC,GACnB,OAAO,IAAI,GAAOD,EAAOC,GAS1B,cAAeze,GACd,OAAO,GAAMwuB,UAAWxuB,GAUzB,cAAeuc,GACd,OAAO,GAAMgS,UAAWhS,GA+DzB,gBAAiB+P,EAAYC,EAAe1sB,GAC3C,OAAO,IAAI,GAAWysB,EAAYC,EAAe1sB,GAalD,cAAe6a,EAAQqP,EAAaG,EAAW0O,GAC9C,IAAI19B,EAAI6uB,EACR,MAAM8O,EAAgB,GAEtB,KAAQ39B,EAAIgvB,GAAY,CACvB,MAAM9F,EAAQ1J,EAAOG,SAAU3f,GACzB49B,EAAS1U,EAAMtmB,GAAI,SACnBi7B,EAAc3U,EAAMtmB,GAAI,oBACxBsiB,EAAUgE,EAAMtmB,GAAI,gBACpBk7B,EAAO5U,EAAMtmB,GAAI,aACjBm7B,EAAQ7U,EAAMtmB,GAAI,cAUxB,GAAKi7B,GAAep7B,KAAKu7B,sBAAuBN,EAAaxU,GAC5DyU,EAAcj4B,KAAM,IAAI,GAAU8Z,EAAQxf,SAQtC,GAAK49B,GAAU1Y,GAAW4Y,GAAQC,GAAWF,GAAeI,GAAmBP,EAAaxU,GAAY,CAE5G,MAAMgV,EAAeR,EAAYtU,SAGjCF,EAAMvQ,UACNulB,EAAa5C,aAAcpS,GAE3B1J,EAAO6I,aAAcroB,EAAGk+B,GACxBz7B,KAAKw5B,0BAA2BiC,GAEhCP,EAAcj4B,KAAM,IAAI,GAAU8Z,EAAQxf,SAOjC69B,GACTp7B,KAAK07B,cAAejV,EAAO,EAAGA,EAAMK,WAAYmU,GAGjD19B,IAID,IAAIo+B,EAAe,EAEnB,IAAM,MAAM9Q,KAAYqQ,EAAgB,CAIvC,GAHArQ,EAASve,QAAUqvB,EAGd9Q,EAASve,QAAU8f,EACvB,SAGmBpsB,KAAK24B,gBAAiB9N,GAGxByB,QAASzB,KAC1B8Q,IACApP,KAIF,OAAO,GAAMgC,6BAA8BxR,EAAQqP,EAAarP,EAAQwP,GAazE,gBAAiBxP,EAAQqP,EAAaG,EAAWqP,GAChD,IAAIr+B,EAAI6uB,EACR,MAAMyP,EAAkB,GAKxB,KAAQt+B,EAAIgvB,GAAY,CACvB,MAAM9F,EAAQ1J,EAAOG,SAAU3f,GAG/B,GAAMkpB,EAAMtmB,GAAI,oBAahB,GAAKsmB,EAAMkL,UAAWiK,GAAtB,CACC,MAAME,EAAYrV,EAAMC,cAClBlkB,EAAQikB,EAAMK,WAGpBL,EAAMvQ,UACN6G,EAAO6I,aAAcroB,EAAGu+B,GAExB97B,KAAK04B,+BAAgCjS,GAGrCoV,EAAgB54B,KACf,IAAI,GAAU8Z,EAAQxf,GACtB,IAAI,GAAUwf,EAAQxf,EAAIiF,IAI3BjF,GAAKiF,EACL+pB,GAAa/pB,EAAQ,OAYjBxC,KAAK+7B,wBAAyBH,EAAenV,IACjDoV,EAAgB54B,KACf,IAAI,GAAU8Z,EAAQxf,GACtB,IAAI,GAAUwf,EAAQxf,EAAI,IAG3BA,MAUDyC,KAAK46B,gBAAiBnU,EAAO,EAAGA,EAAMK,WAAY8U,GAElDr+B,UA5DCA,IAgEF,IAAIo+B,EAAe,EAEnB,IAAM,MAAM9Q,KAAYgR,EAAkB,CAIzC,GAHAhR,EAASve,QAAUqvB,EAGd9Q,EAASve,QAAU8f,GAAevB,EAASve,QAAUigB,EACzD,SAGmBvsB,KAAK24B,gBAAiB9N,GAGxByB,QAASzB,KAC1B8Q,IACApP,KAIF,OAAO,GAAMgC,6BAA8BxR,EAAQqP,EAAarP,EAAQwP,GAezE,WAAY0C,EAAO9P,GAElB,MAAQ0B,MAAO+Y,EAAY9Y,IAAK+Y,GAAa75B,KAAKm4B,sBAAuBlJ,GAAO,GAC1E6K,EAAkBF,EAAW7c,OAG7B4d,EAAW36B,KAAK07B,cAAe5B,EAAiBF,EAAWttB,OAAQutB,EAASvtB,OAAQ6S,GAGpF0B,EAAQ7gB,KAAK24B,gBAAiBgC,EAAS9Z,OAGvCA,EAAMyL,QAASqO,EAAS9Z,QAC7B8Z,EAAS7Z,IAAIxU,SAEd,MAAMwU,EAAM9gB,KAAK24B,gBAAiBgC,EAAS7Z,KAE3C,OAAO,IAAI,GAAOD,EAAOC,GAe1B,cAAe+J,EAAU1L,GAExB,GAAKA,EAAUwS,UAAW9G,EAAS9N,QAClC,OAAOif,GAAwBnR,EAASa,SAIpCb,EAAS9N,OAAO5c,GAAI,WACxB0qB,EAAWoR,GAAepR,IAI3B,MAAMqR,EAAel8B,KAAKm8B,yBAC1BD,EAAahK,UAAYhX,OAAOkhB,kBAChCF,EAAavK,UAAY,KAAM,EAG/B9G,EAAS9N,OAAO6I,aAAciF,EAASve,OAAQ4vB,GAG/C,MAAMG,EAAY,IAAI,GAAOxR,EAAUA,EAASyD,aAAc,IAG9DtuB,KAAKs8B,KAAMD,EAAWld,GAGtB,MAAM4Z,EAAc,IAAI,GAAUmD,EAAanf,OAAQmf,EAAax5B,OACpEw5B,EAAahmB,UAGb,MAAMoX,EAAayL,EAAYzL,WACzBF,EAAY2L,EAAY3L,UAE9B,OAAKE,aAAsB,IAAQF,aAAqB,GAChDwL,GAAgBtL,EAAYF,GAI7B4O,GAAwBjD,GAahC,sBAAuBwD,EAASC,GAC/B,IAAMC,GAAaF,EAASC,GAC3B,OAAO,EAIR,GAAKD,EAAQz+B,OAAS0+B,EAAO1+B,MAAQy+B,EAAQ9rB,WAAa+rB,EAAO/rB,SAChE,OAAO,EAIR,IAAM,MAAM3R,KAAOy9B,EAAQ/G,mBAE1B,GAAa,UAAR12B,GAA2B,UAARA,GAKnB09B,EAAOtd,aAAcpgB,IAAS09B,EAAOpd,aAActgB,KAAUy9B,EAAQnd,aAActgB,GACvF,OAAO,EAKT,IAAM,MAAMA,KAAOy9B,EAAQ7Z,gBAC1B,GAAK8Z,EAAO9c,SAAU5gB,IAAS09B,EAAO7c,SAAU7gB,KAAUy9B,EAAQ5c,SAAU7gB,GAC3E,OAAO,EAKT,IAAM,MAAMA,KAAOy9B,EAAQ/G,mBAEb,UAAR12B,GAA2B,UAARA,IAKlB09B,EAAOtd,aAAcpgB,IAC1BkB,KAAK0D,aAAc5E,EAAKy9B,EAAQnd,aAActgB,GAAO09B,IAIvD,IAAM,MAAM19B,KAAOy9B,EAAQ7Z,gBACpB8Z,EAAO9c,SAAU5gB,IACtBkB,KAAK08B,SAAU59B,EAAKy9B,EAAQ5c,SAAU7gB,GAAO09B,GAI/C,IAAM,MAAM19B,KAAOy9B,EAAQjd,gBACpBkd,EAAOjd,SAAUzgB,IACtBkB,KAAK28B,SAAU79B,EAAK09B,GAItB,OAAO,EAaR,wBAAyBD,EAASK,GACjC,IAAMH,GAAaF,EAASK,GAC3B,OAAO,EAIR,GAAKL,EAAQz+B,OAAS8+B,EAAS9+B,MAAQy+B,EAAQ9rB,WAAamsB,EAASnsB,SACpE,OAAO,EAIR,IAAM,MAAM3R,KAAOy9B,EAAQ/G,mBAE1B,GAAa,UAAR12B,GAA2B,UAARA,KAKlB89B,EAAS1d,aAAcpgB,IAAS89B,EAASxd,aAActgB,KAAUy9B,EAAQnd,aAActgB,IAC5F,OAAO,EAKT,IAAM89B,EAASrd,YAAagd,EAAQjd,iBACnC,OAAO,EAIR,IAAM,MAAMxgB,KAAOy9B,EAAQ7Z,gBAE1B,IAAMka,EAASld,SAAU5gB,IAAS89B,EAASjd,SAAU7gB,KAAUy9B,EAAQ5c,SAAU7gB,GAChF,OAAO,EAKT,IAAM,MAAMA,KAAOy9B,EAAQ/G,mBAEb,UAAR12B,GAA2B,UAARA,GAIxBkB,KAAK4E,gBAAiB9F,EAAK89B,GAS5B,OALA58B,KAAK68B,YAAa1zB,MAAMiK,KAAMmpB,EAAQjd,iBAAmBsd,GAGzD58B,KAAK88B,YAAa3zB,MAAMiK,KAAMmpB,EAAQ7Z,iBAAmBka,IAElD,EAYR,sBAAuB3N,EAAO8N,GAAiB,GAC9C,MAAMC,EAAa/N,EAAMpO,MACnBoc,EAAWhO,EAAMnO,IAKvB,GAHA6Y,GAAwB1K,EAAOjvB,KAAKgB,UAG/BiuB,EAAMxB,YAAc,CACxB,MAAM5C,EAAW7qB,KAAKk4B,iBAAkBjJ,EAAMpO,MAAOkc,GAErD,OAAO,IAAI,GAAOlS,EAAUA,GAG7B,MAAMgP,EAAW75B,KAAKk4B,iBAAkB+E,EAAUF,GAC5Cv6B,EAAQq3B,EAAS9c,OAAO+J,WACxB8S,EAAa55B,KAAKk4B,iBAAkB8E,EAAYD,GAKtD,OAFAlD,EAASvtB,QAAUutB,EAAS9c,OAAO+J,WAAatkB,EAEzC,IAAI,GAAOo3B,EAAYC,GAkB/B,iBAAkBhP,EAAUkS,GAAiB,GAC5C,MAAMvE,EAAiB3N,EAASve,OAC1BmsB,EAAiB5N,EAAS9N,OAGhC,GAAK8N,EAAS9N,OAAO5c,GAAI,gBAUxB,MAAM,IAAI,KAAe,yCAA0CH,KAAKgB,UAIzE,GAAK6pB,EAAS9N,OAAO5c,GAAI,aAUxB,MAAM,IAAI,KAAe,sCAAuCH,KAAKgB,UAItE,GAAK6pB,EAAS9N,OAAO5c,GAAI,cAUxB,MAAM,IAAI,KAAe,uCAAwCH,KAAKgB,UAIvE,IAAM+7B,GAAkBtE,EAAet4B,GAAI,UAAa+8B,GAAuBzE,EAAe1b,QAC7F,OAAO8N,EAASa,QAIjB,GAAKwR,GAAuBzE,GAC3B,OAAO5N,EAASa,QAIjB,GAAK+M,EAAet4B,GAAI,SACvB,OAAOH,KAAKk4B,iBAAkB+D,GAAepR,GAAYkS,GAQ1D,GAAKvE,GALUC,EAAe3R,WAKE,CAC/B,MAAMiS,EAAc,IAAI,GAAUN,EAAe1b,OAAQ0b,EAAe/1B,MAAQ,GAEhF,OAAO1C,KAAKk4B,iBAAkBa,EAAagE,GAK3C,GAAwB,IAAnBvE,EAAuB,CAC3B,MAAMO,EAAc,IAAI,GAAUN,EAAe1b,OAAQ0b,EAAe/1B,OAExE,OAAO1C,KAAKk4B,iBAAkBa,EAAagE,GAMvC,CACJ,MAAMI,EAAc1E,EAAe/1B,MAAQ,EAGrC06B,EAAa3E,EAAe9R,SAGlC8R,EAAe1b,OAAO6I,aAAcuX,EAAaC,GACjDp9B,KAAKw5B,0BAA2B4D,GAGhC,MAAM56B,EAAQi2B,EAAe3R,WAAa0R,EACpC6E,EAAc5E,EAAe3a,gBAAiB0a,EAAgBh2B,GAGpE46B,EAAWvE,aAAcwE,GAGzB,MAAMtE,EAAc,IAAI,GAAUN,EAAe1b,OAAQogB,GAEzD,OAAOn9B,KAAKk4B,iBAAkBa,EAAagE,IAiB9C,0BAA2Bne,GAE1B,IAAMA,EAAQ/hB,KAAKsD,GAAI,eACtB,OAKD,GAAKye,EAAQze,GAAI,WAChB,IAAM,MAAMsmB,KAAS7H,EAAQ8H,cAC5B1mB,KAAKw5B,0BAA2B/S,GAIlC,MAAMnkB,EAAKsc,EAAQtc,GAEnB,IAAMA,EACL,OAGD,IAAIg7B,EAAQt9B,KAAKi3B,aAAa74B,IAAKkE,GAE7Bg7B,IACLA,EAAQ,IAAIjlB,IACZrY,KAAKi3B,aAAaxtB,IAAKnH,EAAIg7B,IAG5BA,EAAM1uB,IAAKgQ,GACXA,EAAQwT,aAAekL,EAexB,+BAAgC1e,GAG/B,GAAKA,EAAQze,GAAI,WAChB,IAAM,MAAMsmB,KAAS7H,EAAQ8H,cAC5B1mB,KAAK04B,+BAAgCjS,GAIvC,MAAMnkB,EAAKsc,EAAQtc,GAEnB,IAAMA,EACL,OAGD,MAAMg7B,EAAQt9B,KAAKi3B,aAAa74B,IAAKkE,GAE/Bg7B,GAINA,EAAMvpB,OAAQ6K,IAyBhB,SAAS0a,GAAoBzO,GAC5B,IAAI9N,EAAS8N,EAAS9N,OAEtB,MAASmgB,GAAuBngB,IAAW,CAC1C,IAAMA,EACL,OAEDA,EAASA,EAAOA,OAGjB,OAAOA,EAWR,SAASye,GAAmB7e,EAAGC,GAC9B,OAAKD,EAAElM,SAAWmM,EAAEnM,YAERkM,EAAElM,SAAWmM,EAAEnM,WAKpBkM,EAAE4gB,cAAgB3gB,EAAE2gB,cAY5B,SAASvB,GAAwBnR,GAChC,MAAMyC,EAAazC,EAASyC,WAE5B,GAAKA,GAAcA,EAAWntB,GAAI,SACjC,OAAO,IAAI,GAAUmtB,EAAYA,EAAW3tB,KAAKoC,QAGlD,MAAMqrB,EAAYvC,EAASuC,UAE3B,OAAKA,GAAaA,EAAUjtB,GAAI,SACxB,IAAI,GAAUitB,EAAW,GAG1BvC,EAWR,SAASoR,GAAepR,GACvB,GAAKA,EAASve,QAAUue,EAAS9N,OAAOpd,KAAKoC,OAC5C,OAAO,IAAI,GAAU8oB,EAAS9N,OAAOA,OAAQ8N,EAAS9N,OAAOra,MAAQ,GAGtE,GAAyB,IAApBmoB,EAASve,OACb,OAAO,IAAI,GAAUue,EAAS9N,OAAOA,OAAQ8N,EAAS9N,OAAOra,OAI9D,MAAM86B,EAAa3S,EAAS9N,OAAOpd,KAAK8H,MAAOojB,EAASve,QASxD,OANAue,EAAS9N,OAAO0gB,MAAQ5S,EAAS9N,OAAOpd,KAAK8H,MAAO,EAAGojB,EAASve,QAGhEue,EAAS9N,OAAOA,OAAO6I,aAAciF,EAAS9N,OAAOra,MAAQ,EAAG,IAAI,GAAMmoB,EAAShuB,KAAKmE,SAAUw8B,IAG3F,IAAI,GAAU3S,EAAS9N,OAAOA,OAAQ8N,EAAS9N,OAAOra,MAAQ,GAStE,SAASk2B,GAAgB8E,EAAIC,GAE5B,MAAMC,EAAmBF,EAAG/9B,KAAKoC,OAIjC,OAHA27B,EAAGD,OAASE,EAAGh+B,KACfg+B,EAAGznB,UAEI,IAAI,GAAUwnB,EAAIE,GAqC1B,MAAM1E,GAAqB,CAAE,GAAM,GAAkB,GAAkB,GAAc,GAAY,IAMjG,SAASgE,GAAuB3qB,GAC/B,OAAOA,IAAUA,EAAKpS,GAAI,qBAAwBoS,EAAKpS,GAAI,qBAS5D,SAASw5B,GAAwB1K,EAAOgK,GACvC,MAAM4E,EAAiBvE,GAAoBrK,EAAMpO,OAC3Cid,EAAexE,GAAoBrK,EAAMnO,KAE/C,IAAM+c,IAAmBC,GAAgBD,IAAmBC,EAiB3D,MAAM,IAAI,KAAe,sCAAuC7E,GAWlE,SAASwD,GAAa9f,EAAGC,GACxB,OAAgB,OAATD,EAAEra,IAAwB,OAATsa,EAAEta,GCt7DZ,SAAS,GAAQK,GAC/B,MAAgD,iBAAzC1E,OAAOkB,UAAUuG,SAAShI,KAAMiF,GC2BjC,MAAMo7B,GAAc1I,GAAeA,EAAY9wB,eAAgB,KASzDy5B,GAAY3I,IACxB,MAAM4I,EAAW5I,EAAYhyB,cAAe,MAG5C,OAFA46B,EAASC,QAAQC,WAAY,EAEtBF,GAaKG,GAAgB,MAC5B,IAAIC,EAAe,GAEnB,IAAM,IAAI9gC,EAAI,EAAGA,EAVkB,EAUQA,IAC1C8gC,GAAgB,IAGjB,OAAOA,GAPqB,GAqBtB,SAASC,GAAkBC,GACjC,OAAO,GAAQA,IAAeA,EAAQ5+B,KAAK0S,OAAQ,EA7BhB,KA6B8C+rB,GAY3E,SAASI,GAAgBC,GAC/B,OA1CmC,GA0C5BA,EAAQ9+B,KAAKoC,QAAkCu8B,GAAkBG,GAalE,SAASC,GAAsBD,GACrC,OAAKH,GAAkBG,GACfA,EAAQ9+B,KAAK8H,MAzDc,GA2D3Bg3B,EAAQ9+B,KAejB,SAASg/B,GAAsB7nB,EAAKnX,GACnC,GAAKA,EAAK40B,SAAWlB,GAASC,UAAY,CACzC,MAAMsC,EAAej2B,EAAKk2B,UAAUC,cAAcC,YAAYC,eAE9D,GAAgC,GAA3BJ,EAAa1G,YAAmB0G,EAAaM,WAAY,GAAIC,UAAY,CAC7E,MAAMC,EAAYR,EAAaM,WAAY,GAAI2H,eACzCvH,EAAYV,EAAaM,WAAY,GAAI9J,YAE1CkS,GAAkBlI,IAAeE,GAlFL,GAmFhCV,EAAakB,SAAUV,EAAW,KCjDvB,SAASwI,GAAUjiB,EAAGC,EAAGiiB,EAAKC,GAAgB,GAE5DD,EAAMA,GAAO,SAAUliB,EAAGC,GACzB,OAAOD,IAAMC,GASRzT,MAAMgC,QAASwR,KACpBA,EAAIxT,MAAMhK,UAAUsI,MAAM/J,KAAMif,IAG3BxT,MAAMgC,QAASyR,KACpBA,EAAIzT,MAAMhK,UAAUsI,MAAM/J,KAAMkf,IAIjC,MAAMmiB,EAsBP,SAAoCC,EAAMC,EAAMJ,GAE/C,MAAMK,EAAaC,GAA0BH,EAAMC,EAAMJ,GAGzD,IAAqB,IAAhBK,EACJ,MAAO,CAAEA,YAAa,EAAGE,cAAe,EAAGC,cAAe,GAI3D,MAAMC,EAAmBC,GAAeP,EAAME,GACxCM,EAAmBD,GAAeN,EAAMC,GAaxCxxB,EAAYyxB,GAA0BG,EAAkBE,EAAkBX,GAG1EO,EAAeJ,EAAKj9B,OAAS2L,EAC7B2xB,EAAeJ,EAAKl9B,OAAS2L,EAEnC,MAAO,CAAEwxB,aAAYE,eAAcC,gBApDbI,CAA2B9iB,EAAGC,EAAGiiB,GAGvD,OAAOC,EAkHR,SAAuCC,EAAeW,GACrD,MAAM,WAAER,EAAU,aAAEE,EAAY,aAAEC,GAAiBN,EAGnD,IAAqB,IAAhBG,EACJ,OAAO/1B,MAAOu2B,GAAYzvB,KAAM,SAGjC,IAAInO,EAAS,GACRo9B,EAAa,IACjBp9B,EAASA,EAAOW,OAAQ0G,MAAO+1B,GAAajvB,KAAM,WAG9CovB,EAAeH,EAAa,IAChCp9B,EAASA,EAAOW,OAAQ0G,MAAOk2B,EAAeH,GAAajvB,KAAM,YAG7DmvB,EAAeF,EAAa,IAChCp9B,EAASA,EAAOW,OAAQ0G,MAAOi2B,EAAeF,GAAajvB,KAAM,YAG7DovB,EAAeK,IACnB59B,EAASA,EAAOW,OAAQ0G,MAAOu2B,EAAYL,GAAepvB,KAAM,WAGjE,OAAOnO,EA3IgB69B,CAA8BZ,EAAeniB,EAAE7a,QAmFvE,SAAiC69B,EAAUb,GAC1C,MAAMj9B,EAAS,IACT,WAAEo9B,EAAU,aAAEE,EAAY,aAAEC,GAAiBN,EAK9CM,EAAeH,EAAa,GAChCp9B,EAAOmB,KAAM,CACZP,MAAOw8B,EACPj/B,KAAM,SACNoM,OAAQuzB,EAASn4B,MAAOy3B,EAAYG,KAIjCD,EAAeF,EAAa,GAChCp9B,EAAOmB,KAAM,CACZP,MAAOw8B,GAAeG,EAAeH,GACrCj/B,KAAM,SACNgnB,QAASmY,EAAeF,IAI1B,OAAOp9B,EA1G0E+9B,CAAwBjjB,EAAGmiB,GA0D7G,SAASI,GAA0BH,EAAMC,EAAMJ,GAC9C,IAAM,IAAIthC,EAAI,EAAGA,EAAI6S,KAAKsR,IAAKsd,EAAKj9B,OAAQk9B,EAAKl9B,QAAUxE,IAC1D,QAAmB+I,IAAd04B,EAAMzhC,SAAmC+I,IAAd24B,EAAM1hC,KAAsBshC,EAAKG,EAAMzhC,GAAK0hC,EAAM1hC,IACjF,OAAOA,EAIT,OAAQ,EAQT,SAASgiC,GAAetb,EAAKgD,GAC5B,OAAOhD,EAAIxc,MAAOwf,GAAU6Y,UCpKd,SAAS,GAAMnjB,EAAGC,EAAGiiB,GAEnCA,EAAMA,GAAO,SAAUliB,EAAGC,GACzB,OAAOD,IAAMC,GAGd,MAAMmjB,EAAUpjB,EAAE5a,OACZi+B,EAAUpjB,EAAE7a,OAGlB,GAAKg+B,EAAU,KAAOC,EAAU,KAAOD,EAAUC,EAAU,IAC1D,OAAO,GAAKpB,SAAUjiB,EAAGC,EAAGiiB,GAAK,GAIlC,IAAIoB,EAASC,EAGb,GAAKF,EAAUD,EAAU,CACxB,MAAMI,EAAMxjB,EAEZA,EAAIC,EACJA,EAAIujB,EAGJF,EAAU,SACVC,EAAU,cAEVD,EAAU,SACVC,EAAU,SAGX,MAAMviC,EAAIgf,EAAE5a,OACN/C,EAAI4d,EAAE7a,OACNq+B,EAAQphC,EAAIrB,EAGZ0iC,EAAK,GAELC,EAAK,GAEX,SAASC,EAAOC,GAGf,MAAMC,QAAuBn6B,IAAhBg6B,EAAIE,EAAI,GAAoBF,EAAIE,EAAI,IAAO,GAAM,EAExDE,OAAqBp6B,IAAhBg6B,EAAIE,EAAI,GAAoBF,EAAIE,EAAI,IAAO,EAEhDG,EAAMF,EAAKC,GAAM,EAAI,EAGtBL,EAAIG,EAAIG,KACZN,EAAIG,GAAMH,EAAIG,EAAIG,GAAMl5B,MAAO,IAI1B44B,EAAIG,KACTH,EAAIG,GAAM,IAIXH,EAAIG,GAAIv9B,KAAMw9B,EAAKC,EAAKT,EAAUC,GAGlC,IAAIU,EAAIxwB,KAAKsR,IAAK+e,EAAIC,GAClBG,EAAID,EAAIJ,EAGZ,KAAQK,EAAIljC,GAAKijC,EAAI5hC,GAAK6/B,EAAKliB,EAAGkkB,GAAKjkB,EAAGgkB,KACzCC,IACAD,IAEAP,EAAIG,GAAIv9B,KAAM,SAGf,OAAO29B,EAGR,IACIJ,EADAnhC,EAAI,EAIR,EAAG,CAEF,IAAMmhC,GAAKnhC,EAAGmhC,EAAIJ,EAAOI,IACxBF,EAAIE,GAAMD,EAAOC,GAIlB,IAAMA,EAAIJ,EAAQ/gC,EAAGmhC,EAAIJ,EAAOI,IAC/BF,EAAIE,GAAMD,EAAOC,GAKlBF,EAAIF,GAAUG,EAAOH,GAErB/gC,UACSihC,EAAIF,KAAYphC,GAI1B,OAAOqhC,EAAID,GAAQ34B,MAAO,GCpHZ,SAAS,GAAU2yB,EAAe13B,EAAOo+B,GACvD1G,EAAc11B,aAAco8B,EAAc1G,EAAc51B,WAAY9B,IAAW,MCHjE,SAAS,GAAQ6P,GAC/B,MAAMwK,EAASxK,EAAKlN,WAEf0X,GACJA,EAAOtY,YAAa8N,GCHP,SAASwuB,GAAQp+B,GAC/B,GAAKA,EAAM,CACV,GAAKA,EAAIozB,YACR,OAAOpzB,aAAeA,EAAIozB,YAAYiL,SAChC,GAAKr+B,EAAImzB,eAAiBnzB,EAAImzB,cAAcC,YAClD,OAAOpzB,aAAeA,EAAImzB,cAAcC,YAAYkL,KAItD,OAAO,EHiHR,GAAKrC,SAAWA,GIlGD,MAAM,GAOpB,YAAajJ,EAAcvL,GAO1BpqB,KAAKkhC,aAAe,IAAI7oB,IAQxBrY,KAAK21B,aAAeA,EAQpB31B,KAAKmhC,iBAAmB,IAAI9oB,IAQ5BrY,KAAKohC,eAAiB,IAAI/oB,IAQ1BrY,KAAKqhC,YAAc,IAAIhpB,IAQvBrY,KAAKoqB,UAAYA,EAQjBpqB,KAAKmqB,WAAY,EAQjBnqB,KAAKshC,cAAgB,KAQrBthC,KAAKuhC,wBAA0B,KAehC,WAAYthC,EAAMsS,GACjB,GAAc,SAATtS,EACCD,KAAK21B,aAAa6L,aAAcjvB,EAAKwK,SACzC/c,KAAKqhC,YAAYzyB,IAAK2D,OAEjB,CAGN,IAAMvS,KAAK21B,aAAa6L,aAAcjvB,GACrC,OAGD,GAAc,eAATtS,EACJD,KAAKmhC,iBAAiBvyB,IAAK2D,OACrB,IAAc,aAATtS,EAQX,MAAM,IAAI,KAAe,6BAA8BD,MAPvDA,KAAKohC,eAAexyB,IAAK2D,KAuB5B,SACC,IAAIkvB,EAGJ,IAAM,MAAM7iB,KAAW5e,KAAKohC,eAC3BphC,KAAK0hC,wBAAyB9iB,GAM1B5e,KAAKshC,gBAAkBthC,KAAK2hC,8BAChC3hC,KAAK4hC,sBAID5hC,KAAKshC,cACTG,EAAuBzhC,KAAK6hC,2BAGnB7hC,KAAK8hC,kCACdL,EAAuBzhC,KAAKoqB,UAAUoH,mBAGtCxxB,KAAKohC,eAAexyB,IAAK6yB,EAAqB1kB,SAG/C,IAAM,MAAM6B,KAAW5e,KAAKmhC,iBAC3BnhC,KAAK+hC,aAAcnjB,GAGpB,IAAM,MAAMA,KAAW5e,KAAKohC,eAC3BphC,KAAKgiC,gBAAiBpjB,EAAS,CAAE6iB,yBAGlC,IAAM,MAAMlvB,KAAQvS,KAAKqhC,aAClBrhC,KAAKohC,eAAe13B,IAAK6I,EAAKwK,SAAY/c,KAAK21B,aAAa6L,aAAcjvB,EAAKwK,SACpF/c,KAAKiiC,YAAa1vB,EAAM,CAAEkvB,yBAU5B,GAAKA,EAAuB,CAC3B,MAAMS,EAAoBliC,KAAK21B,aAAakB,kBAAmB4K,GACzDpM,EAAc6M,EAAkBnlB,OAAO+Y,cAEvCwI,GAAkB4D,EAAkBnlB,QAKzC/c,KAAKshC,cAAgBY,EAAkBnlB,OAHvC/c,KAAKshC,cAAgBa,GAAiB9M,EAAa6M,EAAkBnlB,OAAQmlB,EAAkB51B,aAOhGtM,KAAKshC,cAAgB,KAGtBthC,KAAKoiC,mBACLpiC,KAAKqiC,eAELriC,KAAKqhC,YAAY93B,QACjBvJ,KAAKmhC,iBAAiB53B,QACtBvJ,KAAKohC,eAAe73B,QAarB,wBAAyBuxB,GACxB,MAAMvF,EAAav1B,KAAK21B,aAAa6L,aAAc1G,GAEnD,IAAMvF,EAEL,OAGD,MAAM+M,EAAoBtiC,KAAK21B,aAAa6L,aAAc1G,GAAct2B,WAClE+9B,EAAsBp5B,MAAMiK,KACjCpT,KAAK21B,aAAa6M,kBAAmB1H,EAAavF,EAAWO,cAAe,CAAE2M,cAAc,KAEvFC,EAAO1iC,KAAK2iC,eAAgBL,EAAmBC,GAC/CK,EAAU5iC,KAAK6iC,oBAAqBH,EAAMJ,EAAmBC,GAEnE,IAAuC,IAAlCK,EAAQ9vB,QAAS,WAAqB,CAC1C,MAAMgwB,EAAU,CAAEC,MAAO,EAAGp/B,OAAQ,EAAGoQ,OAAQ,GAE/C,IAAM,MAAMivB,KAAUJ,EACrB,GAAgB,YAAXI,EAAuB,CAC3B,MAAMC,EAAcH,EAAQC,MAAQD,EAAQn/B,OACtCu/B,EAAcJ,EAAQC,MAAQD,EAAQ/uB,OACtCovB,EAAYrI,EAAY5d,SAAU+lB,IAKnCE,GAAgBA,EAAUhjC,GAAI,cAAiBgjC,EAAUhjC,GAAI,eACjEH,KAAKojC,uBAAwBD,EAAWb,EAAmBY,IAG5D,GAAQX,EAAqBU,IAC7BH,EAAQC,aAERD,EAASE,MAab,uBAAwBlI,EAAavF,GAEpCv1B,KAAK21B,aAAa0N,iBAAkB9N,GACpCv1B,KAAK21B,aAAa2N,aAAc/N,EAAYuF,GAG5C96B,KAAKohC,eAAexyB,IAAKksB,GAWzB96B,KAAKmhC,iBAAiBvyB,IAAKksB,GAgB5B,2BACC,MAAMyI,EAAWvjC,KAAKoqB,UAAUoH,mBAEhC,OAAK+R,EAASxmB,OAAO5c,GAAI,SACjB,GAAagsB,cAAensB,KAAKoqB,UAAUoH,mBAAmBzU,QAE9DwmB,EAYT,6BACC,GAAkC,GAA7BvjC,KAAKoqB,UAAU8E,aAAoBlvB,KAAKoqB,UAAUqD,YACtD,OAAO,EAYR,MAAM+V,EAAoBxjC,KAAKoqB,UAAUoH,mBACnC3G,EAAW7qB,KAAK21B,aAAakB,kBAAmB2M,GAEtD,SAAK3Y,GAAY,GAAQA,EAAS9N,SAAYuhB,GAAkBzT,EAAS9N,SAY1E,sBACC,MAAM0mB,EAAgBzjC,KAAKshC,cAG3B,IAAMhD,GAAkBmF,GAOvB,MAAM,IAAI,KAAe,gCAAiCzjC,MAGtDw+B,GAAgBiF,GACpBA,EAAcp+B,WAAWZ,YAAag/B,GAEtCA,EAAc9jC,KAAO8jC,EAAc9jC,KAAK0S,ON7UP,GMgVlCrS,KAAKshC,cAAgB,KAStB,gCACC,GAAkC,GAA7BthC,KAAKoqB,UAAU8E,aAAoBlvB,KAAKoqB,UAAUqD,YACtD,OAAO,EAGR,MAAM+V,EAAoBxjC,KAAKoqB,UAAUoH,mBACnCkS,EAAkBF,EAAkBzmB,OACpC4mB,EAAkBH,EAAkBl3B,OAG1C,IAAMtM,KAAK21B,aAAa6L,aAAckC,EAAgB7mC,MACrD,OAAO,EAGR,IAAQ6mC,EAAgBvjC,GAAI,WAC3B,OAAO,EAKR,IAscF,SAAqBye,GACpB,GAAkD,SAA7CA,EAAQQ,aAAc,mBAC1B,OAAO,EAGR,MAAMrC,EAAS6B,EAAQglB,aAAchlB,GAAWA,EAAQM,aAAc,oBAEtE,OAAQnC,GAAsD,QAA5CA,EAAOqC,aAAc,mBA7chCykB,CAAYH,GACjB,OAAO,EAIR,GAAKC,IAAoBD,EAAgB7c,kBACxC,OAAO,EAGR,MAAMyG,EAAakW,EAAkBlW,WAC/BF,EAAYoW,EAAkBpW,UAEpC,QAAKE,aAAsB,IAAYF,aAAqB,IAgB7D,YAAa0W,EAAU5hC,GACtB,MAAMu8B,EAAUz+B,KAAK21B,aAAaoO,yBAA0BD,GACtDE,EAAahkC,KAAK21B,aAAasO,UAAWH,EAAUrF,EAAQ3I,eAE5DoO,EAAazF,EAAQ9+B,KAC3B,IAAIwkC,EAAeH,EAAWrkC,KAE9B,MAAMykC,EAASliC,EAAQu/B,qBAMvB,GAJK2C,GAAUA,EAAOrnB,QAAU+mB,EAAS/mB,QAAUqnB,EAAO93B,QAAUw3B,EAASphC,QAC5EyhC,EAAe/F,GAAgB+F,GAG3BD,GAAcC,EAAe,CACjC,MAAMvB,EAAUhE,GAAUsF,EAAYC,GAEtC,IAAM,MAAMnB,KAAUJ,EACA,WAAhBI,EAAO/iC,KACXw+B,EAAQ4F,WAAYrB,EAAOtgC,MAAOsgC,EAAO32B,OAAOpI,KAAM,KAEtDw6B,EAAQ6F,WAAYtB,EAAOtgC,MAAOsgC,EAAO/b,UAY7C,aAAc6T,GACb,MAAMvF,EAAav1B,KAAK21B,aAAa6L,aAAc1G,GAEnD,IAAMvF,EAKL,OAGD,MAAMgP,EAAcp7B,MAAMiK,KAAMmiB,EAAWjyB,YAAa+G,IAAKm6B,GAAQA,EAAK1mC,MACpE2mC,EAAe3J,EAAYtF,mBAGjC,IAAM,MAAM12B,KAAO2lC,EAClBlP,EAAW7xB,aAAc5E,EAAKg8B,EAAY1b,aAActgB,IAIzD,IAAM,MAAMA,KAAOylC,EACZzJ,EAAY5b,aAAcpgB,IAC/By2B,EAAW3wB,gBAAiB9F,GAc/B,gBAAiBg8B,EAAa54B,GAC7B,MAAMqzB,EAAav1B,KAAK21B,aAAa6L,aAAc1G,GAEnD,IAAMvF,EAGL,OAGD,MAAMkM,EAAuBv/B,EAAQu/B,qBAC/Ba,EAAoBtiC,KAAK21B,aAAa6L,aAAc1G,GAAct2B,WAClE+9B,EAAsBp5B,MAAMiK,KACjCpT,KAAK21B,aAAa6M,kBAAmB1H,EAAavF,EAAWO,cAAe,CAAE/2B,MAAM,EAAM0iC,0BAMtFA,GAAwBA,EAAqB1kB,SAAW+d,GAC5DqH,GAAiB5M,EAAWO,cAAeyM,EAAqBd,EAAqBn1B,QAGtF,MAAMo2B,EAAO1iC,KAAK2iC,eAAgBL,EAAmBC,GAErD,IAAIhlC,EAAI,EACR,MAAMmnC,EAAgB,IAAIrsB,IAQ1B,IAAM,MAAM2qB,KAAUN,EACL,WAAXM,GACJ0B,EAAc91B,IAAK0zB,EAAmB/kC,IACtC,GAAQ+kC,EAAmB/kC,KACL,UAAXylC,GACXzlC,IAIFA,EAAI,EAEJ,IAAM,MAAMylC,KAAUN,EACL,WAAXM,GACJ,GAAUzN,EAAYh4B,EAAGglC,EAAqBhlC,IAC9CA,KACsB,UAAXylC,IAGXhjC,KAAK2kC,0BAA2B3kC,KAAK21B,aAAaiP,UAAWrC,EAAqBhlC,KAClFA,KAOF,IAAM,MAAMgV,KAAQmyB,EACbnyB,EAAKlN,YACVrF,KAAK21B,aAAa0N,iBAAkB9wB,GAavC,eAAgB+vB,EAAmBC,GAGlC,OAAO,GAFPD,EA0YF,SAA0CuC,EAAcC,GACvD,MAAMC,EAAY57B,MAAMiK,KAAMyxB,GAE9B,GAAyB,GAApBE,EAAUhjC,SAAgB+iC,EAC9B,OAAOC,EAGKA,EAAWA,EAAUhjC,OAAS,IAE9B+iC,GACZC,EAAU37B,MAGX,OAAO27B,EAvZcC,CAAiC1C,EAAmBtiC,KAAKuhC,yBAE7CgB,EAAqB,GAAUxjC,KAAM,KAAMiB,KAAK21B,eAkBjF,oBAAqBiN,EAASqC,EAAWC,GAExC,IAAsC,IAAjCtC,EAAQ9vB,QAAS,YAAsD,IAAjC8vB,EAAQ9vB,QAAS,UAC3D,OAAO8vB,EAGR,IAAIuC,EAAa,GACbC,EAAc,GACdC,EAAgB,GAEpB,MAAMvC,EAAU,CAAEC,MAAO,EAAGp/B,OAAQ,EAAGoQ,OAAQ,GAE/C,IAAM,MAAMivB,KAAUJ,EACL,WAAXI,EACJqC,EAAcpiC,KAAMiiC,EAAapC,EAAQC,MAAQD,EAAQn/B,SACnC,WAAXq/B,EACXoC,EAAYniC,KAAMgiC,EAAWnC,EAAQC,MAAQD,EAAQ/uB,UAErDoxB,EAAaA,EAAW1iC,OAAQ,GAAM2iC,EAAaC,EAAeC,IAAaj7B,IAAKw2B,GAAW,UAANA,EAAgB,UAAYA,IACrHsE,EAAWliC,KAAM,SAEjBmiC,EAAc,GACdC,EAAgB,IAEjBvC,EAASE,KAGV,OAAOmC,EAAW1iC,OAAQ,GAAM2iC,EAAaC,EAAeC,IAAaj7B,IAAKw2B,GAAW,UAANA,EAAgB,UAAYA,IAWhH,0BAA2B0E,GAC1B,GAAMA,EAIN,GAAKA,EAASplC,GAAI,SACjBH,KAAKqhC,YAAYzyB,IAAK22B,QAChB,GAAKA,EAASplC,GAAI,WACxB,IAAM,MAAMsmB,KAAS8e,EAAS7e,cAC7B1mB,KAAK2kC,0BAA2Ble,GAUnC,mBAEC,GAAmC,IAA9BzmB,KAAKoqB,UAAU8E,WAInB,OAHAlvB,KAAKwlC,2BACLxlC,KAAKylC,uBAKN,MAAMC,EAAU1lC,KAAK21B,aAAa6L,aAAcxhC,KAAKoqB,UAAUC,iBAGzDrqB,KAAKmqB,WAAcub,IAKpB1lC,KAAKoqB,UAAUuF,OACnB3vB,KAAK2lC,qBAAsBD,IAE3B1lC,KAAKylC,uBACLzlC,KAAK4lC,oBAAqBF,KAU5B,qBAAsBA,GACrB,MAAMrQ,EAAcqQ,EAAQ5P,cAEtB91B,KAAKuhC,0BACVvhC,KAAKuhC,wBA+SR,SAAuClM,GACtC,MAAMgE,EAAYhE,EAAYhyB,cAAe,OAe7C,OAbAg2B,EAAUjT,UAAY,8BAEtBnoB,OAAO4nC,OAAQxM,EAAUj2B,MAAO,CAC/BynB,SAAU,QACVib,IAAK,EACLC,KAAM,UAENC,MAAO,SAIR3M,EAAU4M,YAAc,IAEjB5M,EA/T0B6M,CAA8B7Q,IAG9D,MAAMgE,EAAYr5B,KAAKuhC,wBAKvB,GAFAvhC,KAAK21B,aAAawQ,kBAAmB9M,EAAWr5B,KAAKoqB,YAE/CpqB,KAAKomC,0BAA2BV,GACrC,OAGKrM,EAAUe,eAAiBf,EAAUe,eAAiBsL,GAC3DA,EAAQ9hC,YAAay1B,GAGtBA,EAAU4M,YAAcjmC,KAAKoqB,UAAUwF,oBAAsB,IAE7D,MAAMgG,EAAeP,EAAYW,eAC3BqQ,EAAWhR,EAAYiR,cAE7B1Q,EAAa2Q,kBACbF,EAASG,mBAAoBnN,GAC7BzD,EAAa6Q,SAAUJ,GASxB,oBAAqBX,GACpB,MAAM9P,EAAe8P,EAAQ5P,cAAcC,YAAYC,eAGvD,IAAMh2B,KAAK0mC,yBAA0B9Q,GACpC,OAQD,MAAMzG,EAASnvB,KAAK21B,aAAakB,kBAAmB72B,KAAKoqB,UAAU+E,QAC7DU,EAAQ7vB,KAAK21B,aAAakB,kBAAmB72B,KAAKoqB,UAAUyF,OAIlE6V,EAAQ7V,QAER+F,EAAakB,SAAU3H,EAAOpS,OAAQoS,EAAO7iB,QAC7CspB,EAAamB,OAAQlH,EAAM9S,OAAQ8S,EAAMvjB,QAGpC,GAAIqmB,SAgNX,SAAmC9C,EAAO+F,GACzC,MAAM7Y,EAAS8S,EAAM9S,OAIrB,GAAKA,EAAO5W,UAAY86B,KAAK0F,cAAgB9W,EAAMvjB,QAAUyQ,EAAOvY,WAAWzC,OAAS,EACvF,OAGD,MAAM6kC,EAAgB7pB,EAAOvY,WAAYqrB,EAAMvjB,QAI1Cs6B,GAA0C,MAAzBA,EAAcC,SACnCjR,EAAa6Q,SAAU7Q,EAAaM,WAAY,IA7N/C4Q,CAA0BjX,EAAO+F,GAWnC,yBAA0BA,GACzB,IAAM51B,KAAK21B,aAAaoR,sBAAuBnR,GAE9C,OAAO,EAGR,MAAMoR,EAAmBpR,GAAgB51B,KAAK21B,aAAasR,mBAAoBrR,GAE/E,QAAKoR,IAAoBhnC,KAAKoqB,UAAUkC,QAAS0a,QAK3ChnC,KAAKoqB,UAAUqD,aAAeztB,KAAKoqB,UAAUuH,UAAWqV,IAgB/D,0BAA2BtB,GAC1B,MAAMrM,EAAYr5B,KAAKuhC,wBACjB3L,EAAe8P,EAAQ5P,cAAcE,eAI3C,OAAMqD,GAAaA,EAAUe,gBAAkBsL,IAK1C9P,EAAasR,aAAe7N,IAAcA,EAAU8N,SAAUvR,EAAasR,aAIzE7N,EAAU4M,cAAgBjmC,KAAKoqB,UAAUwF,oBAQjD,sBACC,IAAM,MAAMwX,KAAOpnC,KAAKkhC,aAAe,CAGtC,GAFqBkG,EAAIpR,eAEP9G,WAAa,CAC9B,MAAMmY,EAAmBD,EAAIE,cACvBxM,EAAc96B,KAAK21B,aAAa4R,aAAcF,GAE/CA,GAAoBvM,GACxBsM,EAAIpR,eAAeuQ,oBAWvB,uBACC,MAAMlN,EAAYr5B,KAAKuhC,wBAElBlI,GACJA,EAAUl1B,SASZ,eACC,GAAKnE,KAAKmqB,UAAY,CACrB,MAAMqC,EAAWxsB,KAAKoqB,UAAUC,gBAE3BmC,GACJxsB,KAAK21B,aAAa9F,MAAOrD,KAiC7B,SAAS2V,GAAiB9M,EAAamS,EAAkBl7B,GACxD,MAAM9H,EAAagjC,aAA4Br+B,MAAQq+B,EAAmBA,EAAiBhjC,WACrFijC,EAAkBjjC,EAAY8H,GAEpC,GAAK,GAAQm7B,GAGZ,OAFAA,EAAgB9nC,KAAOy+B,GAAgBqJ,EAAgB9nC,KAEhD8nC,EACD,CACN,MAAMC,EAAarS,EAAY9wB,eAAgB65B,IAQ/C,OANKj1B,MAAMgC,QAASq8B,GACnBhjC,EAAWsB,OAAQwG,EAAQ,EAAGo7B,GAE9B,GAAUF,EAAkBl7B,EAAQo7B,GAG9BA,GAWT,SAASpC,GAAYqC,EAAOC,GAC3B,OAAO7G,GAAQ4G,IAAW5G,GAAQ6G,KAChC,GAAQD,KAAY,GAAQC,IAC7BD,EAAMxhC,WAAa86B,KAAK4G,cAAgBD,EAAMzhC,WAAa86B,KAAK4G,cAChEF,EAAMd,QAAQpU,gBAAkBmV,EAAMf,QAAQpU,cAehD,SAAS,GAAWkD,EAAcmS,EAAgBC,GAEjD,OAAKD,IAAmBC,IAId,GAAQD,IAAoB,GAAQC,GACtCD,EAAenoC,OAASooC,EAAiBpoC,QAGvCg2B,EAAaqS,cAAeF,KACrCnS,EAAaqS,cAAeD,KArF9BvzB,GAAK,GAAU,ICj1BA,QAAErX,cAAQ6D,mBCVV,SAAS8R,GAASP,GAChC,IAAI7P,EAAQ,EAEZ,KAAQ6P,EAAK4b,iBACZ5b,EAAOA,EAAK4b,gBACZzrB,IAGD,OAAOA,ECHO,SAAS8a,GAAcjL,GACrC,MAAMwU,EAAQ,GAGd,KAAQxU,GAAQA,EAAKpM,UAAY86B,KAAKgH,eACrClhB,EAAM5J,QAAS5K,GACfA,EAAOA,EAAKlN,WAGb,OAAO0hB,ECAR,MAAMmhB,GAAgBlK,GAAWh9B,UAelB,MAAM,GAQpB,YAAaA,EAAUkB,EAAU,IAKhClC,KAAKgB,SAAWA,EAQhBhB,KAAKmoC,gBAAkBjmC,EAAQimC,iBAAmB,KAQlDnoC,KAAKooC,YAAc,CAAE,OAarBpoC,KAAKqoC,cAAgB,CAAE,IAAK,MAAO,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,aAAc,KAAM,MAU7GroC,KAAKsoC,aAAuC,MAAxBtoC,KAAKmoC,gBAA0BnK,GAAYD,GAQ/D/9B,KAAKuoC,kBAAoB,IAAIjzB,QAQ7BtV,KAAKwoC,kBAAoB,IAAIlzB,QAQ7BtV,KAAKyoC,sBAAwB,IAAInzB,QASjCtV,KAAK0oC,0BAA4B,IAAIlqB,GAQrCxe,KAAK2oC,+BAAiC,IAAIC,QAY3C,kBAAmBrT,EAAYsT,GAC9B7oC,KAAKyoC,sBAAsBh/B,IAAK8rB,EAAY,IAAI,GAAesT,IAUhE,oBAAqBtT,GACpB,OAAOv1B,KAAKyoC,sBAAsBrqC,IAAKm3B,GAWxC,aAAcA,EAAYuF,GACzB96B,KAAKuoC,kBAAkB9+B,IAAK8rB,EAAYuF,GACxC96B,KAAKwoC,kBAAkB/+B,IAAKqxB,EAAavF,GAS1C,iBAAkBA,GACjB,MAAMuF,EAAc96B,KAAKuoC,kBAAkBnqC,IAAKm3B,GAEhD,GAAKuF,EAAc,CAClB96B,KAAKuoC,kBAAkBx0B,OAAQwhB,GAC/Bv1B,KAAKwoC,kBAAkBz0B,OAAQ+mB,GAE/B,IAAM,MAAMrU,KAAS8O,EAAW/wB,WAC/BxE,KAAKqjC,iBAAkB5c,IAa1B,sBAAuBqiB,EAAaC,GACnC/oC,KAAKuoC,kBAAkB9+B,IAAKq/B,EAAaC,GACzC/oC,KAAKwoC,kBAAkB/+B,IAAKs/B,EAAcD,GAe3C,UAAWvD,EAAUlQ,EAAanzB,EAAU,IAC3C,GAAKqjC,EAASplC,GAAI,SAAY,CAC7B,MAAM6oC,EAAWhpC,KAAKipC,yBAA0B1D,GAEhD,OAAOlQ,EAAY9wB,eAAgBykC,GAC7B,CACN,GAAKhpC,KAAKwhC,aAAc+D,GACvB,OAAOvlC,KAAKwhC,aAAc+D,GAG3B,IAAIhQ,EAEJ,GAAKgQ,EAASplC,GAAI,oBAEjBo1B,EAAaF,EAAY6T,yBAEpBhnC,EAAQnD,MACZiB,KAAKmpC,sBAAuB5T,EAAYgQ,OAEnC,IAAKA,EAASplC,GAAI,aAQxB,OANAo1B,EAAagQ,EAAS/N,OAAQnC,GAEzBnzB,EAAQnD,MACZiB,KAAKsjC,aAAc/N,EAAYgQ,GAGzBhQ,EAINA,EADIgQ,EAASrmB,aAAc,SACdmW,EAAY+T,gBAAiB7D,EAASnmB,aAAc,SAAWmmB,EAASznC,MAExEu3B,EAAYhyB,cAAekiC,EAASznC,MAK7CynC,EAASplC,GAAI,eACjBolC,EAAS/N,OAAQjC,GAGbrzB,EAAQnD,MACZiB,KAAKsjC,aAAc/N,EAAYgQ,GAIhC,IAAM,MAAMzmC,KAAOymC,EAAS/P,mBAC3BD,EAAW7xB,aAAc5E,EAAKymC,EAASnmB,aAActgB,IAIvD,IAA8B,IAAzBoD,EAAQugC,aACZ,IAAM,MAAMhc,KAASzmB,KAAKwiC,kBAAmB+C,EAAUlQ,EAAanzB,GACnEqzB,EAAW3xB,YAAa6iB,GAI1B,OAAO8O,GAcT,mBAAqBuF,EAAazF,EAAanzB,EAAU,IACxD,MAAMmnC,EAAuBvO,EAAYjU,iBAAmBiU,EAAYjU,kBACxE,IAAIva,EAAS,EAEb,IAAM,MAAMg9B,KAAaxO,EAAYpU,cAC/B2iB,IAAyB/8B,UACvBtM,KAAKsoC,aAAcjT,UAGpBr1B,KAAKikC,UAAWqF,EAAWjU,EAAanzB,GAE9CoK,IAGI+8B,IAAyB/8B,UACvBtM,KAAKsoC,aAAcjT,IAW3B,eAAgBkU,GACf,MAAMC,EAAWxpC,KAAK62B,kBAAmB0S,EAAU1oB,OAC7C4oB,EAASzpC,KAAK62B,kBAAmB0S,EAAUzoB,KAE3CulB,EAAWrlC,SAASslC,cAI1B,OAHAD,EAASqD,SAAUF,EAASzsB,OAAQysB,EAASl9B,QAC7C+5B,EAASsD,OAAQF,EAAO1sB,OAAQ0sB,EAAOn9B,QAEhC+5B,EAcR,kBAAmB7P,GAClB,MAAMoT,EAAapT,EAAazZ,OAEhC,GAAK6sB,EAAWzpC,GAAI,SAAY,CAC/B,MAAMi2B,EAAYp2B,KAAK+jC,yBAA0B6F,GAEjD,IAAMxT,EAEL,OAAO,KAGR,IAAI9pB,EAASkqB,EAAalqB,OAM1B,OAJKgyB,GAAkBlI,KACtB9pB,GVrSgC,GUwS1B,CAAEyQ,OAAQqZ,EAAW9pB,UACtB,CAEN,IAAI8pB,EAAWyT,EAAWC,EAE1B,GAA6B,IAAxBtT,EAAalqB,OAAe,CAGhC,GAFA8pB,EAAYp2B,KAAKwhC,aAAcoI,IAEzBxT,EAEL,OAAO,KAGR0T,EAAW1T,EAAU5xB,WAAY,OAC3B,CACN,MAAM8oB,EAAakJ,EAAalJ,WAMhC,GAJAuc,EAAYvc,EAAWntB,GAAI,SAC1BH,KAAK+jC,yBAA0BzW,GAC/BttB,KAAKwhC,aAAchL,EAAalJ,aAE3Buc,EAEL,OAAO,KAGRzT,EAAYyT,EAAUxkC,WACtBykC,EAAWD,EAAU3b,YAKtB,GAAK,GAAQ4b,IAAcxL,GAAkBwL,GAC5C,MAAO,CAAE/sB,OAAQ+sB,EAAUx9B,OVzUK,GU8UjC,MAAO,CAAEyQ,OAAQqZ,EAAW9pB,OAFbu9B,EAAY/2B,GAAS+2B,GAAc,EAAI,IAoBxD,UAAWtL,EAASr8B,EAAU,IAC7B,GAAKlC,KAAKgoC,cAAezJ,EAASv+B,KAAKmoC,iBACtC,OAAO,KAIR,MAAM4B,EAAc/pC,KAAKgqC,mBAAoBzL,GAE7C,GAAKwL,EACJ,OAAOA,EAGR,GAAK,GAAQxL,GAAY,CACxB,GAAKC,GAAgBD,GACpB,OAAO,KACD,CACN,MAAMyK,EAAWhpC,KAAKiqC,wBAAyB1L,GAE/C,MAAoB,KAAbyK,EAAkB,KAAO,IAAI,GAAUhpC,KAAKgB,SAAUgoC,IAExD,GAAKhpC,KAAKkqC,UAAW3L,GAC3B,OAAO,KACD,CACN,GAAKv+B,KAAKunC,aAAchJ,GACvB,OAAOv+B,KAAKunC,aAAchJ,GAG3B,IAAIzD,EAEJ,GAAK96B,KAAKmqC,mBAAoB5L,GAE7BzD,EAAc,IAAI,GAAsB96B,KAAKgB,UAExCkB,EAAQnD,MACZiB,KAAKmpC,sBAAuB5K,EAASzD,OAEhC,CAEN,MAAMsP,EAAWloC,EAAQmoC,iBAAmB9L,EAAQsI,QAAUtI,EAAQsI,QAAQpU,cAC9EqI,EAAc,IAAI,GAAa96B,KAAKgB,SAAUopC,GAEzCloC,EAAQnD,MACZiB,KAAKsjC,aAAc/E,EAASzD,GAI7B,MAAMtV,EAAQ+Y,EAAQj7B,WAEtB,IAAM,IAAI/F,EAAIioB,EAAMzjB,OAAS,EAAGxE,GAAK,EAAGA,IACvCu9B,EAAYpD,cAAelS,EAAOjoB,GAAIO,KAAM0nB,EAAOjoB,GAAIiB,OAIxD,IAA8B,IAAzB0D,EAAQugC,cAA0BziC,KAAK0oC,0BAA0BhtB,MAAOof,GAM5E,OALAA,EAAYrQ,mBAAoB,cAAe8T,EAAQ+L,WAGvDtqC,KAAK2oC,+BAA+B/5B,IAAK2vB,GAElCzD,EAIT,IAA8B,IAAzB54B,EAAQugC,aACZ,IAAM,MAAMhc,KAASzmB,KAAKuqC,kBAAmBhM,EAASr8B,GACrD44B,EAAYjC,aAAcpS,GAI5B,OAAOqU,GAaT,mBAAqBvF,EAAYrzB,EAAU,IAC1C,IAAM,IAAI3E,EAAI,EAAGA,EAAIg4B,EAAW/wB,WAAWzC,OAAQxE,IAAM,CACxD,MAAMitC,EAAWjV,EAAW/wB,WAAYjH,GAClC4lC,EAAYnjC,KAAK4kC,UAAW4F,EAAUtoC,GAEzB,OAAdihC,UACEA,IAYT,mBAAoBvN,GAGnB,GAAiC,IAA5BA,EAAa1G,WAAmB,CACpC,IAAImK,EAAYzD,EAAaM,WAAY,GAAI2H,eAGxC,GAAQxE,KACZA,EAAYA,EAAUh0B,YAGvB,MAAMm1B,EAAgBx6B,KAAKyqC,oBAAqBpR,GAEhD,GAAKmB,EACJ,OAAOA,EAIT,MAAMxK,EAAahwB,KAAK0qC,uBAAwB9U,GAE1C+U,EAAa,GAEnB,IAAM,IAAIptC,EAAI,EAAGA,EAAIq4B,EAAa1G,WAAY3xB,IAAM,CAEnD,MAAM8oC,EAAWzQ,EAAaM,WAAY34B,GACpCgsC,EAAYvpC,KAAK4qC,eAAgBvE,GAElCkD,GACJoB,EAAW1nC,KAAMsmC,GAInB,OAAO,IAAI,GAAeoB,EAAY,CAAEha,SAAUX,IAUnD,eAAgBqW,GACf,MAAMwE,EAAY7qC,KAAKy2B,kBAAmB4P,EAASxI,eAAgBwI,EAASja,aACtE0e,EAAU9qC,KAAKy2B,kBAAmB4P,EAASvI,aAAcuI,EAAS9Z,WAExE,OAAKse,GAAaC,EACV,IAAI,GAAWD,EAAWC,GAG3B,KAkBR,kBAAmB1U,EAAWE,GAC7B,GAAKt2B,KAAKgoC,cAAe5R,EAAWp2B,KAAKmoC,iBACxC,OAAOnoC,KAAKy2B,kBAAmBL,EAAU/wB,WAAYyN,GAASsjB,IAI/D,MAAM0E,EAAc96B,KAAKunC,aAAcnR,GAEvC,GAAK0E,IAAiBA,EAAY36B,GAAI,cAAiB26B,EAAY36B,GAAI,eACtE,OAAO,GAAagsB,cAAe2O,GAGpC,GAAK,GAAQ1E,GAAc,CAC1B,GAAKoI,GAAgBpI,GACpB,OAAOp2B,KAAKy2B,kBAAmBL,EAAU/wB,WAAYyN,GAASsjB,IAG/D,MAAMwT,EAAa5pC,KAAK+qC,0BAA2B3U,GACnD,IAAI9pB,EAASgqB,EAEb,OAAMsT,GAIDtL,GAAkBlI,KACtB9pB,GVjiBgC,EUkiBhCA,EAASA,EAAS,EAAI,EAAIA,GAGpB,IAAI,GAAcs9B,EAAYt9B,IAR7B,KAYR,GAAmB,IAAdgqB,EAAkB,CACtB,MAAMsT,EAAa5pC,KAAKunC,aAAcnR,GAEtC,GAAKwT,EACJ,OAAO,IAAI,GAAcA,EAAY,OAEhC,CACN,MAAMC,EAAYzT,EAAU5xB,WAAY8xB,EAAY,GAC9C0U,EAAa,GAAQnB,GAC1B7pC,KAAK+qC,0BAA2BlB,GAChC7pC,KAAKunC,aAAcsC,GAGpB,GAAKmB,GAAcA,EAAWjuB,OAC7B,OAAO,IAAI,GAAciuB,EAAWjuB,OAAQiuB,EAAWtoC,MAAQ,GAIjE,OAAO,KAiBT,aAAcuoC,GAGb,OAFoBjrC,KAAKgqC,mBAAoBiB,IAEvBjrC,KAAKuoC,kBAAkBnqC,IAAK6sC,GAwBnD,0BAA2BxM,GAC1B,GAAKD,GAAgBC,GACpB,OAAO,KAIR,MAAMsL,EAAc/pC,KAAKgqC,mBAAoBvL,GAE7C,GAAKsL,EACJ,OAAOA,EAGR,MAAM5b,EAAkBsQ,EAAQtQ,gBAGhC,GAAKA,EAAkB,CACtB,IAAQnuB,KAAKkrC,UAAW/c,GAEvB,OAAO,KAGR,MAAM2M,EAAc96B,KAAKunC,aAAcpZ,GAEvC,GAAK2M,EAAc,CAIlB,OAHoBA,EAAY5M,uBAGJ,GACpB4M,EAAY5M,YAEZ,UAKL,CACJ,MAAM4M,EAAc96B,KAAKunC,aAAc9I,EAAQp5B,YAE/C,GAAKy1B,EAAc,CAClB,MAAM91B,EAAa81B,EAAY5d,SAAU,GAGzC,OAAKlY,aAAsB,GACnBA,EAEA,MAKV,OAAO,KAaR,aAAcmmC,GACb,OAAOnrC,KAAKwoC,kBAAkBpqC,IAAK+sC,GAkBpC,yBAA0BrH,GACzB,MAAM3V,EAAkB2V,EAAS3V,gBAGjC,OAAKA,GAAmBnuB,KAAKwhC,aAAcrT,GACnCnuB,KAAKwhC,aAAcrT,GAAkBD,aAIvCC,GAAmB2V,EAAS/mB,QAAU/c,KAAKwhC,aAAcsC,EAAS/mB,QAChE/c,KAAKwhC,aAAcsC,EAAS/mB,QAASvY,WAAY,GAGlD,KAQR,MAAO4mC,GACN,MAAMC,EAAcrrC,KAAKwhC,aAAc4J,GAEvC,GAAKC,GAAeA,EAAYvV,cAAcwR,gBAAkB+D,EAAc,CAE7E,MAAM,QAAEC,EAAO,QAAEC,GAAYxkC,GAAO5J,OAC9BquC,EAAkB,GAIxBC,GAAwBJ,EAAa94B,IACpC,MAAM,WAAEm5B,EAAU,UAAEC,GAAcp5B,EAElCi5B,EAAgBvoC,KAAM,CAAEyoC,EAAYC,MAGrCN,EAAYxb,QAMZ4b,GAAwBJ,EAAa94B,IACpC,MAAQm5B,EAAYC,GAAcH,EAAgB/e,QAElDla,EAAKm5B,WAAaA,EAClBn5B,EAAKo5B,UAAYA,IAKlB5kC,GAAO5J,OAAOyuC,SAAUN,EAASC,IAUnC,UAAWh5B,GACV,OAAOA,GAAQA,EAAKpM,UAAY86B,KAAK0F,aAStC,mBAAoBp0B,GACnB,OAAOA,GAAQA,EAAKpM,UAAY86B,KAAK4K,uBAStC,UAAWt5B,GACV,OAAOA,GAAQA,EAAKpM,UAAY86B,KAAK4G,aAkBtC,cAAetJ,GACd,MAA6B,MAAxBv+B,KAAKmoC,gBACF5J,EAAQuN,YAAa5D,MAKJ,OAApB3J,EAAQsI,UAAoBkF,GAAgBxN,EAASv+B,KAAKqoC,gBAA4D,IAAzC9J,EAAQl5B,WAAWb,WAAWzC,SAsclH,SAA4Bw8B,EAAS8J,GAGpC,OAFe,GAAQ9J,IAA6B,KAAhBA,EAAQ5+B,MAE3BosC,GAAgBxN,EAAS8J,IAA4D,IAAzC9J,EAAQl5B,WAAWb,WAAWzC,OArcnFiqC,CAAmBzN,EAASv+B,KAAKqoC,eASzC,uBAAwBje,GACvB,GAAKA,EAAUqD,YACd,OAAO,EAKR,MAAMwB,EAAQjuB,SAASslC,cAEvBrX,EAAMya,SAAUtf,EAAU8c,WAAY9c,EAAU6hB,cAChDhd,EAAM0a,OAAQvf,EAAUiM,UAAWjM,EAAUmM,aAE7C,MAAM5F,EAAW1B,EAAMkH,UAIvB,OAFAlH,EAAMid,SAECvb,EAUR,mBAAoB4N,GACnB,MAAMjhB,EAAYE,GAAc+gB,GAKhC,IAFAjhB,EAAUlU,MAEFkU,EAAUvb,QAAS,CAC1B,MAAMw8B,EAAUjhB,EAAUlU,MACpBm8B,EAAWvlC,KAAKuoC,kBAAkBnqC,IAAKmgC,GAE7C,GAAKgH,IAAcA,EAASplC,GAAI,cAAiBolC,EAASplC,GAAI,eAC7D,OAAOolC,EAIT,OAAO,KAeR,sBAAuB3P,GACtB,OAAO51B,KAAKmsC,+BAAgCvW,EAAasR,WAAYtR,EAAaqW,eACjFjsC,KAAKmsC,+BAAgCvW,EAAaS,UAAWT,EAAaW,aAgB5E,0BAA2B9X,GAC1Bze,KAAK0oC,0BAA0B95B,IAAK6P,GAWrC,+BAAgC2X,EAAW9pB,GAE1C,GAAK,GAAQ8pB,IAAekI,GAAkBlI,IAAe9pB,EV14B3B,EU44BjC,OAAO,EAGR,GAAKtM,KAAKkrC,UAAW9U,IAAekI,GAAkBlI,EAAU5xB,WAAY8H,IAE3E,OAAO,EAGR,MAAMs9B,EAAa5pC,KAAKunC,aAAcnR,GAKtC,OAAKwT,IAAgBA,EAAWzpC,GAAI,eAAiBypC,EAAWzpC,GAAI,cAyBrE,yBAA0BoS,GACzB,IAAI5S,EAAO4S,EAAK5S,KAIhB,GAAK4S,EAAKiL,eAAe2b,KAAMpc,GAAU/c,KAAKooC,YAAYhvB,SAAU2D,EAAOjf,OAC1E,OAAO6B,EAKR,GAAyB,KAApBA,EAAKwjB,OAAQ,GAAa,CAC9B,MAAMipB,EAAWpsC,KAAKqsC,yBAA0B95B,GAAM,KAC5B65B,GAAYpsC,KAAKssC,mBAAoBF,KAEpCA,IAC1BzsC,EAAO,IAAWA,EAAK0S,OAAQ,IAajC,GAAuC,KAAlC1S,EAAKwjB,OAAQxjB,EAAKoC,OAAS,GAAa,CAC5C,MAAMwqC,EAAWvsC,KAAKqsC,yBAA0B95B,GAAM,GAEf,KAAlC5S,EAAKwjB,OAAQxjB,EAAKoC,OAAS,IAAewqC,GAAyC,KAA7BA,EAAS5sC,KAAKwjB,OAAQ,KAChFxjB,EAAOA,EAAK0S,OAAQ,EAAG1S,EAAKoC,OAAS,GAAM,KAK7C,OAAOpC,EAAKuK,QAAS,QAAS,MAU/B,mBAAoBqI,GACnB,GAAKA,EAAKiL,eAAe2b,KAAMpc,GAAU/c,KAAKooC,YAAYhvB,SAAU2D,EAAOjf,OAC1E,OAAO,EAGR,MAAM6B,EAAOK,KAAKipC,yBAA0B12B,GAE5C,MAAyC,KAAlC5S,EAAKwjB,OAAQxjB,EAAKoC,OAAS,GAmBnC,wBAAyBwQ,GACxB,IAAI5S,EAAO4S,EAAK5S,KAEhB,GAAK6sC,GAAqBj6B,EAAMvS,KAAKooC,aACpC,OAAO1J,GAAsBnsB,GAO9B5S,EAAOA,EAAKuK,QAAS,iBAAkB,KAEvC,MAAMkiC,EAAWpsC,KAAKysC,0BAA2Bl6B,GAAM,GACjDg6B,EAAWvsC,KAAKysC,0BAA2Bl6B,GAAM,GAEjDm6B,EAAiB1sC,KAAK2sC,4BAA6Bp6B,EAAM65B,GACzDQ,EAAkB5sC,KAAK6sC,6BAA8Bt6B,EAAMg6B,GAyCjE,OArCKG,IACJ/sC,EAAOA,EAAKuK,QAAS,KAAM,KAIvB0iC,IACJjtC,EAAOA,EAAKuK,QAAS,KAAM,KAO5BvK,EAAO++B,GAAsB,IAAIoO,KAAMntC,IASvCA,EAAOA,EAAKuK,QAAS,WAAY,OAG5B,oBAAoBC,KAAMxK,KAAW4sC,GAAcA,EAAS5sC,MAAqC,KAA7B4sC,EAAS5sC,KAAKwjB,OAAQ,MAC9FxjB,EAAOA,EAAKuK,QAAS,UAAW,MAK5BwiC,IACJ/sC,EAAOA,EAAKuK,QAAS,UAAW,MAK1BvK,EAWR,4BAA6B4S,EAAM65B,GAClC,OAAMA,MAID,GAAWA,KAKXpsC,KAAK2oC,+BAA+Bj/B,IAAK6I,EAAK4b,kBAI5C,cAAchkB,KAAMiiC,EAASzsC,KAAKwjB,OAAQipB,EAASzsC,KAAKoC,OAAS,KAWzE,6BAA8BwQ,EAAMg6B,GACnC,OAAKA,IAIGjO,GAAkB/rB,GAY3B,yBAA0BA,EAAMw6B,GAC/B,MAAMpgB,EAAa,IAAI,GAAgB,CACtChC,cAAeoiB,EAAU,GAAalhB,aAActZ,GAAS,GAAa4Z,cAAe5Z,GACzFqY,UAAWmiB,EAAU,UAAY,aAGlC,IAAM,MAAMvuC,KAASmuB,EAAa,CAGjC,GAAKnuB,EAAM6D,KAAKlC,GAAI,oBACnB,OAAO,KAGH,GAAK3B,EAAM6D,KAAKlC,GAAI,UAAW,MACnC,OAAO,KAGH,GAAK3B,EAAM6D,KAAKlC,GAAI,cACxB,OAAO3B,EAAM6D,KAIf,OAAO,KAwBR,0BAA2BkQ,EAAMw6B,GAChC,IAAMx6B,EAAKlN,WACV,OAAO,KAGR,MAAMulB,EAAYmiB,EAAU,WAAa,eACnC/rC,EAAWuR,EAAKujB,cAChBkX,EAAgBxvB,GAAcjL,GAAQ,GAEtCoa,EAAa3rB,EAASisC,iBAAkBD,EAAeE,WAAWC,UAAYD,WAAWE,aAAc,CAC5GC,WAAY96B,GACN,GAAQA,IAIQ,MAAhBA,EAAKs0B,QAHFqG,WAAWI,cAOZJ,WAAWK,cAIpB5gB,EAAW6gB,YAAcj7B,EAEzB,MAAMk7B,EAAe9gB,EAAY/B,KAEjC,GAAsB,OAAjB6iB,EAAwB,CAC5B,MAAMC,ECjuCM,SAA4BC,EAAOC,GACjD,MAAMrwB,EAAaC,GAAcmwB,GAC3BlwB,EAAaD,GAAcowB,GAEjC,IAAIrwC,EAAI,EAGR,KAAQggB,EAAYhgB,IAAOkgB,EAAYlgB,IAAOggB,EAAYhgB,IACzDA,IAGD,OAAa,IAANA,EAAU,KAAOggB,EAAYhgB,EAAI,GDstC1B0wB,CAAmB1b,EAAMk7B,GAKrC,GACCC,IACClB,GAAqBj6B,EAAMvS,KAAKqoC,cAAeqF,KAC/ClB,GAAqBiB,EAAcztC,KAAKqoC,cAAeqF,GAGxD,OAAOD,EAIT,OAAO,MAWT,SAASjB,GAAqBj6B,EAAM5L,EAAOknC,GAC1C,IAAIC,EAAUtwB,GAAcjL,GAM5B,OAJKs7B,IACJC,EAAUA,EAAQrmC,MAAOqmC,EAAQh7B,QAAS+6B,GAAmB,IAGvDC,EAAQ3U,KAAMpc,GAAUA,EAAO8pB,SAAWlgC,EAAMyS,SAAU2D,EAAO8pB,QAAQpU,gBAQjF,SAASgZ,GAAwBl5B,EAAMrB,GACtC,KAAQqB,GAAQA,GAAQxL,GAAO/F,UAC9BkQ,EAAUqB,GACVA,EAAOA,EAAKlN,WAoBd,SAAS0mC,GAAgBxN,EAAS8J,GACjC,MAAMtrB,EAASwhB,EAAQl5B,WAEvB,OAAO0X,GAAUA,EAAO8pB,SAAWwB,EAAcjvB,SAAU2D,EAAO8pB,QAAQpU,eEvyC5D,SAASsb,GAAUprC,GACjC,MAAMqrC,EAAoB/vC,OAAOkB,UAAUuG,SAAS2N,MAAO1Q,GAG3D,MAA0B,mBAArBqrC,GAKqB,mBAArBA,EC6FS,OAhFS,GAAQ,GAAI,GAAc,CAiBjD,SAAUz8B,KAAY08B,GAGrB,GAAKlN,GAAQxvB,IAAaw8B,GAAUx8B,GAAY,CAC/C,MAAM28B,EAAQluC,KAAKmuC,iBAAkB58B,IAAa,IAAI,GAAcA,GAEpE28B,EAAME,UAAWH,GAEjB18B,EAAU28B,EAIX,GAAa/8B,SAASzT,KAAMsC,KAAMuR,KAAY08B,IAkB/C,cAAe18B,EAASN,EAAOC,GAE9B,GAAK6vB,GAAQxvB,IAAaw8B,GAAUx8B,GAAY,CAC/C,MAAM28B,EAAQluC,KAAKmuC,iBAAkB58B,GAGrC,IAAM28B,EACL,OAGD38B,EAAU28B,EAIX,GAAa58B,cAAc5T,KAAMsC,KAAMuR,EAASN,EAAOC,GAElDK,aAAmB,IACvBA,EAAQ26B,OAAQj7B,IAWlB,iBAAkBsB,GACjB,O3FqVqC87B,E2FrVPruC,K3FqVyBsuC,E2FrVnBC,GAAYh8B,G3FsV5C87B,EAAkBt9B,KAAkBs9B,EAAkBt9B,IAAgBu9B,GACnED,EAAkBt9B,IAAgBu9B,GAAsB/8B,QAGzD,KALD,IAAgC88B,EAAkBC,K2FjTzD,MAAM,GAKL,YAAa/7B,GAEZX,GAAe5R,KAAMuuC,GAAYh8B,IAGjCvS,KAAKwuC,SAAWj8B,GA2GlB,SAASg8B,GAAYh8B,GACpB,OAAOA,EAAM,qBAAyBA,EAAM,mBAAsB,MAxGnE,GAAQ,GAAapT,UAAW,GAAc,CAuB7C,OAAQ8R,EAAOC,EAAUhP,EAAU,IAGlC,GAAKlC,KAAKyuC,eAAiBzuC,KAAKyuC,cAAex9B,GAC9C,OAGD,MAAMy9B,EAAkB,CACvBC,UAAWzsC,EAAQ0sC,WACnBC,UAAW3sC,EAAQ4sC,YAGdC,EAAc/uC,KAAKgvC,mBAAoB/9B,EAAOy9B,GAGpD1uC,KAAKwuC,SAASS,iBAAkBh+B,EAAO89B,EAAaL,GAE9C1uC,KAAKyuC,gBACVzuC,KAAKyuC,cAAgB,IAKtBzuC,KAAKyuC,cAAex9B,GAAU89B,GAS/B,OAAQ99B,GACP,IAAIe,GAMChS,KAAKyuC,cAAex9B,KAAgBe,EAAShS,KAAKkT,QAASjC,KAAce,EAAOF,UAAU/P,QAC9F/B,KAAKyuC,cAAex9B,GAAQi+B,kBAkB9B,mBAAoBj+B,EAAO/O,GAC1B,MAAM6sC,EAAcI,IACnBnvC,KAAKqU,KAAMpD,EAAOk+B,IAWnB,OALAJ,EAAYG,eAAiB,KAC5BlvC,KAAKwuC,SAASY,oBAAqBn+B,EAAO89B,EAAa7sC,UAChDlC,KAAKyuC,cAAex9B,IAGrB89B,KC7OM,MAAMM,GAMpB,YAAa3Z,GAOZ11B,KAAK01B,KAAOA,EAQZ11B,KAAKgB,SAAW00B,EAAK10B,SAQrBhB,KAAKsvC,WAAY,EAalB,SACCtvC,KAAKsvC,WAAY,EASlB,UACCtvC,KAAKsvC,WAAY,EAMlB,UACCtvC,KAAKuvC,UACLvvC,KAAKsR,gBAeN,iCAAkCukB,GAKjC,OAJKA,GAAoC,IAAvBA,EAAU1vB,WAC3B0vB,EAAYA,EAAUxwB,eAGjBwwB,GAAoC,IAAvBA,EAAU1vB,WAItB0vB,EAAU2Z,QAAS,yDAY5Bh7B,GAAK66B,GAAU,ICnGA,OALf,SAAqB7wC,GAEnB,OADAwB,KAAK+I,SAASU,IAAIjL,EAbC,6BAcZwB,MCFM,OAJf,SAAqBxB,GACnB,OAAOwB,KAAK+I,SAASW,IAAIlL,ICE3B,SAASixC,GAASpjC,GAChB,IAAI3J,GAAS,EACTX,EAAmB,MAAVsK,EAAiB,EAAIA,EAAOtK,OAGzC,IADA/B,KAAK+I,SAAW,IAAI,KACXrG,EAAQX,GACf/B,KAAK4O,IAAIvC,EAAO3J,IAKpB+sC,GAAStwC,UAAUyP,IAAM6gC,GAAStwC,UAAU8D,KAAO,GACnDwsC,GAAStwC,UAAUuK,IAAM,GAEV,UCJA,OAZf,SAAmBR,EAAO8C,GAIxB,IAHA,IAAItJ,GAAS,EACTX,EAAkB,MAATmH,EAAgB,EAAIA,EAAMnH,SAE9BW,EAAQX,GACf,GAAIiK,EAAU9C,EAAMxG,GAAQA,EAAOwG,GACjC,OAAO,EAGX,OAAO,GCPM,OAJf,SAAkBiX,EAAOrhB,GACvB,OAAOqhB,EAAMzW,IAAI5K,ICyEJ,OA7Df,SAAqBoK,EAAOD,EAAOqF,EAASxD,EAAY4kC,EAAWpvC,GACjE,IAAIqvC,EAjBqB,EAiBTrhC,EACZshC,EAAY1mC,EAAMnH,OAClB8tC,EAAY5mC,EAAMlH,OAEtB,GAAI6tC,GAAaC,KAAeF,GAAaE,EAAYD,GACvD,OAAO,EAGT,IAAIlhC,EAAUpO,EAAMlC,IAAI8K,GACxB,GAAIwF,GAAWpO,EAAMlC,IAAI6K,GACvB,OAAOyF,GAAWzF,EAEpB,IAAIvG,GAAS,EACTZ,GAAS,EACTguC,EA9BuB,EA8BfxhC,EAAoC,IAAI,QAAWhI,EAM/D,IAJAhG,EAAMmJ,IAAIP,EAAOD,GACjB3I,EAAMmJ,IAAIR,EAAOC,KAGRxG,EAAQktC,GAAW,CAC1B,IAAIG,EAAW7mC,EAAMxG,GACjBstC,EAAW/mC,EAAMvG,GAErB,GAAIoI,EACF,IAAImlC,EAAWN,EACX7kC,EAAWklC,EAAUD,EAAUrtC,EAAOuG,EAAOC,EAAO5I,GACpDwK,EAAWilC,EAAUC,EAAUttC,EAAOwG,EAAOD,EAAO3I,GAE1D,QAAiBgG,IAAb2pC,EAAwB,CAC1B,GAAIA,EACF,SAEFnuC,GAAS,EACT,MAGF,GAAIguC,GACF,IAAK,GAAU7mC,GAAO,SAAS+mC,EAAUE,GACnC,IAAK,GAASJ,EAAMI,KACfH,IAAaC,GAAYN,EAAUK,EAAUC,EAAU1hC,EAASxD,EAAYxK,IAC/E,OAAOwvC,EAAK7sC,KAAKitC,MAEjB,CACNpuC,GAAS,EACT,YAEG,GACDiuC,IAAaC,IACXN,EAAUK,EAAUC,EAAU1hC,EAASxD,EAAYxK,GACpD,CACLwB,GAAS,EACT,OAKJ,OAFAxB,EAAc,OAAE4I,GAChB5I,EAAc,OAAE2I,GACTnH,GC9DM,OAVf,SAAoBuI,GAClB,IAAI3H,GAAS,EACTZ,EAASqH,MAAMkB,EAAIrB,MAKvB,OAHAqB,EAAI5G,SAAQ,SAASjF,EAAOM,GAC1BgD,IAASY,GAAS,CAAC5D,EAAKN,MAEnBsD,GCGM,OAVf,SAAoB2H,GAClB,IAAI/G,GAAS,EACTZ,EAASqH,MAAMM,EAAIT,MAKvB,OAHAS,EAAIhG,SAAQ,SAASjF,GACnBsD,IAASY,GAASlE,KAEbsD,GCYL,GAAc,EAAS,EAAO3C,eAAYmH,EAC1C,GAAgB,GAAc,GAAYuH,aAAUvH,EAoFzC,OAjEf,SAAoBrH,EAAQgK,EAAOb,EAAKkG,EAASxD,EAAY4kC,EAAWpvC,GACtE,OAAQ8H,GACN,IAzBc,oBA0BZ,GAAKnJ,EAAOoO,YAAcpE,EAAMoE,YAC3BpO,EAAOsO,YAActE,EAAMsE,WAC9B,OAAO,EAETtO,EAASA,EAAOsI,OAChB0B,EAAQA,EAAM1B,OAEhB,IAlCiB,uBAmCf,QAAKtI,EAAOoO,YAAcpE,EAAMoE,aAC3BqiC,EAAU,IAAI,GAAWzwC,GAAS,IAAI,GAAWgK,KAKxD,IAnDU,mBAoDV,IAnDU,gBAoDV,IAjDY,kBAoDV,OAAO,GAAIhK,GAASgK,GAEtB,IAxDW,iBAyDT,OAAOhK,EAAOnB,MAAQmL,EAAMnL,MAAQmB,EAAOoB,SAAW4I,EAAM5I,QAE9D,IAxDY,kBAyDZ,IAvDY,kBA2DV,OAAOpB,GAAWgK,EAAQ,GAE5B,IAjES,eAkEP,IAAIknC,EAAU,GAEhB,IAjES,eAkEP,IAAIR,EA5EiB,EA4ELrhC,EAGhB,GAFA6hC,IAAYA,EAAU,IAElBlxC,EAAO+J,MAAQC,EAAMD,OAAS2mC,EAChC,OAAO,EAGT,IAAIjhC,EAAUpO,EAAMlC,IAAIa,GACxB,GAAIyP,EACF,OAAOA,GAAWzF,EAEpBqF,GAtFuB,EAyFvBhO,EAAMmJ,IAAIxK,EAAQgK,GAClB,IAAInH,EAAS,GAAYquC,EAAQlxC,GAASkxC,EAAQlnC,GAAQqF,EAASxD,EAAY4kC,EAAWpvC,GAE1F,OADAA,EAAc,OAAErB,GACT6C,EAET,IAnFY,kBAoFV,GAAI,GACF,OAAO,GAAcpE,KAAKuB,IAAW,GAAcvB,KAAKuL,GAG9D,OAAO,GCnGL,GAHchL,OAAOkB,UAGQC,eA+ElB,OAhEf,SAAsBH,EAAQgK,EAAOqF,EAASxD,EAAY4kC,EAAWpvC,GACnE,IAAIqvC,EAtBqB,EAsBTrhC,EACZ8hC,EAAW,GAAWnxC,GACtBoxC,EAAYD,EAASruC,OAIzB,GAAIsuC,GAHW,GAAWpnC,GACDlH,SAEM4tC,EAC7B,OAAO,EAGT,IADA,IAAIjtC,EAAQ2tC,EACL3tC,KAAS,CACd,IAAI5D,EAAMsxC,EAAS1tC,GACnB,KAAMitC,EAAY7wC,KAAOmK,EAAQ,GAAevL,KAAKuL,EAAOnK,IAC1D,OAAO,EAIX,IAAI4P,EAAUpO,EAAMlC,IAAIa,GACxB,GAAIyP,GAAWpO,EAAMlC,IAAI6K,GACvB,OAAOyF,GAAWzF,EAEpB,IAAInH,GAAS,EACbxB,EAAMmJ,IAAIxK,EAAQgK,GAClB3I,EAAMmJ,IAAIR,EAAOhK,GAGjB,IADA,IAAIqxC,EAAWX,IACNjtC,EAAQ2tC,GAAW,CAE1B,IAAI1lC,EAAW1L,EADfH,EAAMsxC,EAAS1tC,IAEXstC,EAAW/mC,EAAMnK,GAErB,GAAIgM,EACF,IAAImlC,EAAWN,EACX7kC,EAAWklC,EAAUrlC,EAAU7L,EAAKmK,EAAOhK,EAAQqB,GACnDwK,EAAWH,EAAUqlC,EAAUlxC,EAAKG,EAAQgK,EAAO3I,GAGzD,UAAmBgG,IAAb2pC,EACGtlC,IAAaqlC,GAAYN,EAAU/kC,EAAUqlC,EAAU1hC,EAASxD,EAAYxK,GAC7E2vC,GACD,CACLnuC,GAAS,EACT,MAEFwuC,IAAaA,EAAkB,eAAPxxC,GAE1B,GAAIgD,IAAWwuC,EAAU,CACvB,IAAIC,EAAUtxC,EAAOyI,YACjB8oC,EAAUvnC,EAAMvB,YAGhB6oC,GAAWC,KACV,gBAAiBvxC,MAAU,gBAAiBgK,IACzB,mBAAXsnC,GAAyBA,aAAmBA,GACjC,mBAAXC,GAAyBA,aAAmBA,IACvD1uC,GAAS,GAKb,OAFAxB,EAAc,OAAErB,GAChBqB,EAAc,OAAE2I,GACTnH,GChEL,GAHc7D,OAAOkB,UAGQC,eA6DlB,OA7Cf,SAAyBH,EAAQgK,EAAOqF,EAASxD,EAAY4kC,EAAWpvC,GACtE,IAAImwC,EAAW,GAAQxxC,GACnByxC,EAAW,GAAQznC,GACnB0nC,EAASF,EA1BA,iBA0BsB,GAAOxxC,GACtC2xC,EAASF,EA3BA,iBA2BsB,GAAOznC,GAKtC4nC,EA/BU,oBA4BdF,EA9BY,sBA8BHA,EA5BK,kBA4B2BA,GAIrCG,EAhCU,oBA6BdF,EA/BY,sBA+BHA,EA7BK,kBA6B2BA,GAIrCG,EAAYJ,GAAUC,EAE1B,GAAIG,GAAa,OAAAxqC,GAAA,GAAStH,GAAS,CACjC,IAAK,OAAAsH,GAAA,GAAS0C,GACZ,OAAO,EAETwnC,GAAW,EACXI,GAAW,EAEb,GAAIE,IAAcF,EAEhB,OADAvwC,IAAUA,EAAQ,IAAI,IACdmwC,GAAY,GAAaxxC,GAC7B,GAAYA,EAAQgK,EAAOqF,EAASxD,EAAY4kC,EAAWpvC,GAC3D,GAAWrB,EAAQgK,EAAO0nC,EAAQriC,EAASxD,EAAY4kC,EAAWpvC,GAExE,KArDyB,EAqDnBgO,GAAiC,CACrC,IAAI0iC,EAAeH,GAAY,GAAenzC,KAAKuB,EAAQ,eACvDgyC,EAAeH,GAAY,GAAepzC,KAAKuL,EAAO,eAE1D,GAAI+nC,GAAgBC,EAAc,CAChC,IAAIC,EAAeF,EAAe/xC,EAAOT,QAAUS,EAC/CkyC,EAAeF,EAAehoC,EAAMzK,QAAUyK,EAGlD,OADA3I,IAAUA,EAAQ,IAAI,IACfovC,EAAUwB,EAAcC,EAAc7iC,EAASxD,EAAYxK,IAGtE,QAAKywC,IAGLzwC,IAAUA,EAAQ,IAAI,IACf,GAAarB,EAAQgK,EAAOqF,EAASxD,EAAY4kC,EAAWpvC,KCpDtD,OAVf,SAAS8wC,EAAY5yC,EAAOyK,EAAOqF,EAASxD,EAAYxK,GACtD,OAAI9B,IAAUyK,IAGD,MAATzK,GAA0B,MAATyK,IAAmB,EAAazK,KAAW,EAAayK,GACpEzK,GAAUA,GAASyK,GAAUA,EAE/B,GAAgBzK,EAAOyK,EAAOqF,EAASxD,EAAYsmC,EAAa9wC,KCgB1D,OANf,SAAqB9B,EAAOyK,EAAO6B,GAEjC,IAAIhJ,GADJgJ,EAAkC,mBAAdA,EAA2BA,OAAaxE,GAClCwE,EAAWtM,EAAOyK,QAAS3C,EACrD,YAAkBA,IAAXxE,EAAuB,GAAYtD,EAAOyK,OAAO3C,EAAWwE,KAAgBhJ,GCLtE,MAAM,WAAyButC,GAC7C,YAAa3Z,GACZ91B,MAAO81B,GAQP11B,KAAKgP,QAAU,CACd+1B,WAAW,EACXsM,eAAe,EACfC,uBAAuB,EACvBC,SAAS,GAQVvxC,KAAK21B,aAAeD,EAAKC,aAOzB31B,KAAKwxC,SAAW9b,EAAK+b,UAQrBzxC,KAAK0xC,aAAe,GAQpB1xC,KAAK2xC,kBAAoB,IAAIx0C,OAAOy0C,iBAAkB5xC,KAAK6xC,aAAa9yC,KAAMiB,OAO/E,QACCA,KAAK6xC,aAAc7xC,KAAK2xC,kBAAkBG,eAM3C,QAASvc,GACRv1B,KAAK0xC,aAAazuC,KAAMsyB,GAEnBv1B,KAAKsvC,WACTtvC,KAAK2xC,kBAAkBI,QAASxc,EAAYv1B,KAAKgP,SAOnD,SACCpP,MAAMoyC,SAEN,IAAM,MAAMzc,KAAcv1B,KAAK0xC,aAC9B1xC,KAAK2xC,kBAAkBI,QAASxc,EAAYv1B,KAAKgP,SAOnD,UACCpP,MAAM2vC,UAENvvC,KAAK2xC,kBAAkBM,aAMxB,UACCryC,MAAMsa,UAENla,KAAK2xC,kBAAkBM,aASxB,aAAcC,GAEb,GAA6B,IAAxBA,EAAanwC,OACjB,OAGD,MAAM4zB,EAAe31B,KAAK21B,aAGpBwc,EAAe,IAAIr+B,IACnBs+B,EAAkB,IAAI/5B,IAI5B,IAAM,MAAMg6B,KAAYH,EACvB,GAAuB,cAAlBG,EAASpyC,KAAuB,CACpC,MAAM2e,EAAU+W,EAAa4R,aAAc8K,EAASjxC,QAGpD,GAAKwd,IAAaA,EAAQze,GAAI,cAAiBye,EAAQze,GAAI,eAC1D,SAGIye,IAAY5e,KAAKsyC,mBAAoBD,IACzCD,EAAgBxjC,IAAKgQ,GAMxB,IAAM,MAAMyzB,KAAYH,EAAe,CACtC,MAAMtzB,EAAU+W,EAAa4R,aAAc8K,EAASjxC,QAGpD,KAAKwd,IAAaA,EAAQze,GAAI,eAAiBye,EAAQze,GAAI,gBAIpC,kBAAlBkyC,EAASpyC,KAA2B,CACxC,MAAMsyC,EAAO5c,EAAaoV,0BAA2BsH,EAASjxC,QAEzDmxC,IAASH,EAAgB1oC,IAAK6oC,EAAKx1B,QAGvCo1B,EAAa1oC,IAAK8oC,EAAM,CACvBtyC,KAAM,OACNuyC,QAASD,EAAK5yC,KACd8yC,QAAS/T,GAAsB2T,EAASjxC,QACxCmR,KAAMggC,KAMGA,GAAQjU,GAAkB+T,EAASjxC,SAC7CgxC,EAAgBxjC,IAAK+mB,EAAa4R,aAAc8K,EAASjxC,OAAOiE,cASnE,MAAMqtC,EAAgB,GAEtB,IAAM,MAAMC,KAAeR,EAAa9lC,SACvCrM,KAAKwxC,SAASoB,WAAY,OAAQD,EAAYpgC,MAC9CmgC,EAAczvC,KAAM0vC,GAGrB,IAAM,MAAM7X,KAAesX,EAAkB,CAC5C,MAAM7c,EAAaI,EAAa6L,aAAc1G,GACxC+X,EAAe1pC,MAAMiK,KAAM0nB,EAAYpU,eACvCosB,EAAkB3pC,MAAMiK,KAAMuiB,EAAa4U,kBAAmBhV,EAAY,CAAEkN,cAAc,KAI1F,GAAaoQ,EAAcC,EAAiBC,KACjD/yC,KAAKwxC,SAASoB,WAAY,WAAY9X,GAEtC4X,EAAczvC,KAAM,CACnBhD,KAAM,WACN+yC,YAAaH,EACbI,YAAaH,EACbvgC,KAAMuoB,KAOT,MAAMlF,EAAesc,EAAc,GAAI9wC,OAAO00B,cAAcE,eAE5D,IAAIwE,EAAgB,KAEpB,GAAK5E,GAAgBA,EAAasR,WAAa,CAM9C,MAAMgM,EAAsBvd,EAAac,kBAAmBb,EAAasR,WAAYtR,EAAaqW,cAC5FkH,EAAqBxd,EAAac,kBAAmBb,EAAaS,UAAWT,EAAaW,aAG3F2c,GAAuBC,IAC3B3Y,EAAgB,IAAI,GAAe0Y,GACnC1Y,EAAc5I,SAAUuhB,IAa1B,SAASJ,EAAWK,EAAQC,GAE3B,IAAKlqC,MAAMgC,QAASioC,GAKpB,OAAKA,IAAWC,MAIND,EAAOjzC,GAAI,WAAakzC,EAAOlzC,GAAI,WACrCizC,EAAOzzC,OAAS0zC,EAAO1zC,KApB3B+yC,EAAc3wC,SAClB/B,KAAKgB,SAASqT,KAAM,YAAaq+B,EAAelY,GAIhDx6B,KAAK01B,KAAK4d,eAgCZ,mBAAoBjB,GACnB,IAAIkB,EAAY,KAShB,OAN8B,OAAzBlB,EAASnkB,aAAyD,IAAjCmkB,EAASmB,aAAazxC,QAA8C,GAA9BswC,EAASoB,WAAW1xC,SAC/FwxC,EAAYvzC,KAAK21B,aAAaiP,UAAWyN,EAASoB,WAAY,GAAK,CAClEhR,cAAc,KAIT8Q,GAAaA,EAAUpzC,GAAI,UAAW,OCtRhC,MAAM,GAMpB,YAAau1B,EAAMge,EAAUC,GAO5B3zC,KAAK01B,KAAOA,EAQZ11B,KAAKgB,SAAW00B,EAAK10B,SAQrBhB,KAAK0zC,SAAWA,EAQhB1zC,KAAK61B,UAAY6d,EAAStyC,OAE1B,GAAQpB,KAAM2zC,GASf,aACC,OAAO3zC,KAAK01B,KAAKC,aAAa4R,aAAcvnC,KAAK61B,WAMlD,iBACC71B,KAAK0zC,SAASE,iBAMf,kBACC5zC,KAAK0zC,SAASG,mBC3CD,MAAM,WAAyBxE,GAqB7C,YAAa3Z,GACZ91B,MAAO81B,GAQP11B,KAAK4uC,YAAa,EAMnB,QAASrZ,IACkC,iBAArBv1B,KAAK8zC,aAA2B,CAAE9zC,KAAK8zC,cAAiB9zC,KAAK8zC,cAE5ErwC,QAASxD,IACdD,KAAKmR,SAAUokB,EAAYt1B,EAAM,CAAE+S,EAAW0gC,KACxC1zC,KAAKsvC,YAActvC,KAAK+zC,iCAAkCL,EAAStyC,SACvEpB,KAAKg0C,WAAYN,IAEhB,CAAE9E,WAAY5uC,KAAK4uC,eAaxB,KAAMqF,EAAWP,EAAUC,GACrB3zC,KAAKsvC,WACTtvC,KAAKgB,SAASqT,KAAM4/B,EAAW,IAAI,GAAcj0C,KAAK01B,KAAMge,EAAUC,KC5E1D,MAAM,WAAoB,GACxC,YAAaje,GACZ91B,MAAO81B,GAEP11B,KAAK8zC,aAAe,CAAE,UAAW,SAGlC,WAAY3E,GACXnvC,KAAKqU,KAAM86B,EAAOlvC,KAAMkvC,EAAQ,CAC/B5a,QAAS4a,EAAO5a,QAEhBC,OAAQ2a,EAAO3a,OACfC,QAAS0a,EAAO1a,SAAW0a,EAAO+E,QAClCxf,SAAUya,EAAOza,SAEjB,gBACC,OAAOJ,GAASt0B,UCjBpB,IAIe,GAJL,WACR,OAAO,IAAK6hB,KAAKC,OCZfqyB,GAAS,aAGTC,GAAa,qBAGbC,GAAa,aAGbC,GAAY,cAGZC,GAAeC,SA8CJ,OArBf,SAAkBh2C,GAChB,GAAoB,iBAATA,EACT,OAAOA,EAET,GAAI,GAASA,GACX,OA7CM,IA+CR,GAAI,EAASA,GAAQ,CACnB,IAAIyK,EAAgC,mBAAjBzK,EAAMqP,QAAwBrP,EAAMqP,UAAYrP,EACnEA,EAAQ,EAASyK,GAAUA,EAAQ,GAAMA,EAE3C,GAAoB,iBAATzK,EACT,OAAiB,IAAVA,EAAcA,GAASA,EAEhCA,EAAQA,EAAM0L,QAAQiqC,GAAQ,IAC9B,IAAIM,EAAWJ,GAAWlqC,KAAK3L,GAC/B,OAAQi2C,GAAYH,GAAUnqC,KAAK3L,GAC/B+1C,GAAa/1C,EAAMiJ,MAAM,GAAIgtC,EAAW,EAAI,GAC3CL,GAAWjqC,KAAK3L,GA1Db,KA0D6BA,GCtDnC,GAAY4R,KAAKsR,IACjBgzB,GAAYtkC,KAAK0M,IAqLN,OA7Hf,SAAkBxU,EAAMqsC,EAAMzyC,GAC5B,IAAI0yC,EACAC,EACAC,EACAhzC,EACAizC,EACAC,EACAC,EAAiB,EACjBC,GAAU,EACVC,GAAS,EACTC,GAAW,EAEf,GAAmB,mBAAR9sC,EACT,MAAM,IAAI2X,UAzEQ,uBAmFpB,SAASo1B,EAAWC,GAClB,IAAIjkC,EAAOujC,EACPpzB,EAAUqzB,EAKd,OAHAD,EAAWC,OAAWvuC,EACtB2uC,EAAiBK,EACjBxzC,EAASwG,EAAK+K,MAAMmO,EAASnQ,GAI/B,SAASkkC,EAAYD,GAMnB,OAJAL,EAAiBK,EAEjBP,EAAUS,WAAWC,EAAcd,GAE5BO,EAAUG,EAAWC,GAAQxzC,EAatC,SAAS4zC,EAAaJ,GACpB,IAAIK,EAAoBL,EAAON,EAM/B,YAAyB1uC,IAAjB0uC,GAA+BW,GAAqBhB,GACzDgB,EAAoB,GAAOR,GANJG,EAAOL,GAM8BH,EAGjE,SAASW,IACP,IAAIH,EAAO,KACX,GAAII,EAAaJ,GACf,OAAOM,EAAaN,GAGtBP,EAAUS,WAAWC,EA3BvB,SAAuBH,GACrB,IAEIO,EAAclB,GAFMW,EAAON,GAI/B,OAAOG,EACHT,GAAUmB,EAAaf,GAJDQ,EAAOL,IAK7BY,EAoB+BC,CAAcR,IAGnD,SAASM,EAAaN,GAKpB,OAJAP,OAAUzuC,EAIN8uC,GAAYR,EACPS,EAAWC,IAEpBV,EAAWC,OAAWvuC,EACfxE,GAeT,SAASi0C,IACP,IAAIT,EAAO,KACPU,EAAaN,EAAaJ,GAM9B,GAJAV,EAAW1pC,UACX2pC,EAAW70C,KACXg1C,EAAeM,EAEXU,EAAY,CACd,QAAgB1vC,IAAZyuC,EACF,OAAOQ,EAAYP,GAErB,GAAIG,EAIF,OAFAc,aAAalB,GACbA,EAAUS,WAAWC,EAAcd,GAC5BU,EAAWL,GAMtB,YAHgB1uC,IAAZyuC,IACFA,EAAUS,WAAWC,EAAcd,IAE9B7yC,EAIT,OA3GA6yC,EAAO,GAASA,IAAS,EACrB,EAASzyC,KACXgzC,IAAYhzC,EAAQgzC,QAEpBJ,GADAK,EAAS,YAAajzC,GACH,GAAU,GAASA,EAAQ4yC,UAAY,EAAGH,GAAQG,EACrEM,EAAW,aAAclzC,IAAYA,EAAQkzC,SAAWA,GAoG1DW,EAAUG,OApCV,gBACkB5vC,IAAZyuC,GACFkB,aAAalB,GAEfE,EAAiB,EACjBL,EAAWI,EAAeH,EAAWE,OAAUzuC,GAgCjDyvC,EAAUI,MA7BV,WACE,YAAmB7vC,IAAZyuC,EAAwBjzC,EAAS8zC,EAAa,OA6BhDG,GCpKM,MAAM,WAA8B1G,GAMlD,YAAa3Z,GACZ91B,MAAO81B,GASP11B,KAAKo2C,kCAAoC,GAAUz2C,GAAQK,KAAKgB,SAASqT,KAAM,sBAAuB1U,GAAQ,KAM/G,UACC,MAAMqB,EAAWhB,KAAKgB,SAEtBA,EAASkoB,GAAI,UAAW,CAAElW,EAAWrT,KAClBqB,EAASopB,UAEZuF,QAAUqF,GAAgBr1B,EAAK40B,UAAav0B,KAAKsvC,YAE/D3vC,EAAKi0C,iBAEL5zC,KAAKq2C,qBAAsB12C,EAAK40B,WAE/B,CAAE9jB,SAAU,WAMhB,UACC7Q,MAAMsa,UAENla,KAAKo2C,kCAAkCF,SAgBxC,qBAAsB3hB,GACrB,MAAMnK,EAAYpqB,KAAKgB,SAASopB,UAC1BksB,EAAe,IAAI,GAAelsB,EAAU8F,YAAa,CAAES,SAAUvG,EAAU4F,WAAYS,MAAM,IAGlG8D,GAAWlB,GAASC,WAAaiB,GAAWlB,GAASE,SACzD+iB,EAAarwB,MAAOqwB,EAAa9kB,oBAI7B+C,GAAWlB,GAASG,YAAce,GAAWlB,GAASI,WAC1D6iB,EAAarwB,MAAOqwB,EAAa7kB,mBAGlC,MAAM9xB,EAAO,CACZ42C,aAAcnsB,EACdksB,eACA1gB,aAAc,MAIf51B,KAAKgB,SAASqT,KAAM,kBAAmB1U,GAMvCK,KAAKo2C,kCAAmCz2C,IClF3B,MAAM,WAA0B0vC,GAC9C,YAAa3Z,GACZ91B,MAAO81B,GAWP11B,KAAKw2C,iBAAmB9gB,EAAK+gB,YAAa,IAU1Cz2C,KAAKoqB,UAAYpqB,KAAKgB,SAASopB,UAU/BpqB,KAAK21B,aAAeD,EAAKC,aASzB31B,KAAK02C,WAAa,IAAI9N,QAStB5oC,KAAKo2C,kCAAoC,GAAUz2C,GAAQK,KAAKgB,SAASqT,KAAM,sBAAuB1U,GAAQ,KAE9GK,KAAK22C,2BAA6BC,YAAa,IAAM52C,KAAK62C,qBAAsB,KAQhF72C,KAAK82C,iBAAmB,EAMzB,QAASvhB,GACR,MAAMF,EAAcE,EAAWO,cAG1B91B,KAAK02C,WAAWhtC,IAAK2rB,KAI1Br1B,KAAKmR,SAAUkkB,EAAa,kBAAmB,CAAEve,EAAK48B,KACrD1zC,KAAK+2C,uBAAwBrD,EAAUre,KAGxCr1B,KAAK02C,WAAW9nC,IAAKymB,IAMtB,UACCz1B,MAAMsa,UAEN88B,cAAeh3C,KAAK22C,4BACpB32C,KAAKo2C,kCAAkCF,SAYxC,uBAAwBxC,EAAUre,GACjC,IAAMr1B,KAAKsvC,UACV,OAGD,MAAM1Z,EAAeP,EAAYU,YAAYC,eAE7C,GAAKh2B,KAAK+zC,iCAAkCne,EAAasR,YACxD,OAIDlnC,KAAKw2C,iBAAiBL,QAItB,MAAMc,EAAmBj3C,KAAK21B,aAAasR,mBAAoBrR,GAM/D,GAAoC,GAA/BqhB,EAAiB/nB,YAQtB,GAFAlvB,KAAK01B,KAAKwhB,iBAAkB,IAEvBl3C,KAAKoqB,UAAUkC,QAAS2qB,IAAsBj3C,KAAK21B,aAAaoR,sBAAuBnR,MAOrF51B,KAAK82C,iBAAmB,IAW/B,GAAK92C,KAAKoqB,UAAUuH,UAAWslB,GAG9Bj3C,KAAK01B,KAAK4d,kBACJ,CACN,MAAM3zC,EAAO,CACZ42C,aAAcv2C,KAAKoqB,UACnBksB,aAAcW,EACdrhB,gBAID51B,KAAKgB,SAASqT,KAAM,kBAAmB1U,GAMvCK,KAAKo2C,kCAAmCz2C,SA3CxCK,KAAK01B,KAAKwhB,iBAAkB,EAoD9B,qBACCl3C,KAAK82C,iBAAmB,GCrLX,MAAM,WAAsB,GAC1C,YAAaphB,GACZ91B,MAAO81B,GAEP11B,KAAK8zC,aAAe,CAAE,QAAS,QAC/B9zC,KAAK4uC,YAAa,EAClB,MAAM5tC,EAAWhB,KAAKgB,SAEtBA,EAASkoB,GAAI,QAAS,KACrBloB,EAASmpB,WAAY,EAOrBnqB,KAAKm3C,iBAAmB3B,WAAY,IAAM9f,EAAK4d,cAAe,MAG/DtyC,EAASkoB,GAAI,OAAQ,CAAEpS,EAAKnX,KAC3B,MAAMy3C,EAAmBp2C,EAASopB,UAAUC,gBAElB,OAArB+sB,GAA6BA,IAAqBz3C,EAAKyB,SAC3DJ,EAASmpB,WAAY,EAGrBuL,EAAK4d,iBAYR,WAAYI,GACX1zC,KAAKqU,KAAMq/B,EAASzzC,KAAMyzC,GAM3B,UACM1zC,KAAKm3C,kBACTlB,aAAcj2C,KAAKm3C,kBAGpBv3C,MAAMsa,WCrDO,MAAM,WAA4B,GAChD,YAAawb,GACZ91B,MAAO81B,GAEP11B,KAAK8zC,aAAe,CAAE,mBAAoB,oBAAqB,kBAC/D,MAAM9yC,EAAWhB,KAAKgB,SAEtBA,EAASkoB,GAAI,mBAAoB,KAChCloB,EAASq2C,aAAc,IAGxBr2C,EAASkoB,GAAI,iBAAkB,KAC9BloB,EAASq2C,aAAc,IAIzB,WAAY3D,GACX1zC,KAAKqU,KAAMq/B,EAASzzC,KAAMyzC,ICnBb,MAAM,WAAsB,GAC1C,YAAahe,GACZ91B,MAAO81B,GAEP11B,KAAK8zC,aAAe,CAAE,eAGvB,WAAYJ,GACX1zC,KAAKqU,KAAMq/B,EAASzzC,KAAMyzC,ICXb,SAAS4D,GAAS30C,GAChC,MAAiD,kBAA1C1E,OAAOkB,UAAUuG,SAAS2N,MAAO1Q,GCA1B,SAAS40C,GAAiB34B,GAExC,MAAMxb,EAAQwb,EAAQkX,cAAcC,YAAYyhB,iBAAkB54B,GAElE,MAAO,CACNknB,IAAK0O,SAAUpxC,EAAMq0C,eAAgB,IACrCC,MAAOlD,SAAUpxC,EAAMu0C,iBAAkB,IACzCC,OAAQpD,SAAUpxC,EAAMy0C,kBAAmB,IAC3C9R,KAAMyO,SAAUpxC,EAAM00C,gBAAiB,KCTzC,MAAMC,GAAiB,CAAE,MAAO,QAAS,SAAU,OAAQ,QAAS,UAOrD,MAAM,GA4BpB,YAAantC,GACZ,MAAMotC,EAAgBV,GAAS1sC,GAgB/B,GAPA3M,OAAOC,eAAgB8B,KAAM,UAAW,CAEvCxB,MAAOoM,EAAOqtC,SAAWrtC,EACzBstC,UAAU,EACV/5C,YAAY,IAGR,GAAWyM,IAAYotC,EAY3B,GAAKA,EAAgB,CACpB,MAAMG,EAAa,GAAKC,iBAAkBxtC,GAC1CytC,GAAoBr4C,KAAM,GAAKs4C,gBAAiBH,SAEhDE,GAAoBr4C,KAAM4K,EAAO2tC,8BAE5B,GAAKxK,GAAUnjC,GAAW,CAChC,MAAM,WAAE4tC,EAAU,YAAEC,GAAgB7tC,EAEpCytC,GAAoBr4C,KAAM,CACzB8lC,IAAK,EACL4R,MAAOc,EACPZ,OAAQa,EACR1S,KAAM,EACNC,MAAOwS,EACPE,OAAQD,SAGTJ,GAAoBr4C,KAAM4K,GAmD5B,QACC,OAAO,IAAI,GAAM5K,MAUlB,OAAQ6gC,EAAGD,GAMV,OALA5gC,KAAK8lC,IAAMlF,EACX5gC,KAAK03C,MAAQ7W,EAAI7gC,KAAKgmC,MACtBhmC,KAAK43C,OAAShX,EAAI5gC,KAAK04C,OACvB14C,KAAK+lC,KAAOlF,EAEL7gC,KAUR,OAAQ6gC,EAAGD,GAMV,OALA5gC,KAAK8lC,KAAOlF,EACZ5gC,KAAK03C,OAAS7W,EACd7gC,KAAK+lC,MAAQlF,EACb7gC,KAAK43C,QAAUhX,EAER5gC,KASR,gBAAiB24C,GAChB,MAAMC,EAAO,CACZ9S,IAAK11B,KAAKsR,IAAK1hB,KAAK8lC,IAAK6S,EAAY7S,KACrC4R,MAAOtnC,KAAK0M,IAAK9c,KAAK03C,MAAOiB,EAAYjB,OACzCE,OAAQxnC,KAAK0M,IAAK9c,KAAK43C,OAAQe,EAAYf,QAC3C7R,KAAM31B,KAAKsR,IAAK1hB,KAAK+lC,KAAM4S,EAAY5S,OAMxC,OAHA6S,EAAK5S,MAAQ4S,EAAKlB,MAAQkB,EAAK7S,KAC/B6S,EAAKF,OAASE,EAAKhB,OAASgB,EAAK9S,IAE5B8S,EAAK5S,MAAQ,GAAK4S,EAAKF,OAAS,EAC7B,KAEA,IAAI,GAAME,GAUnB,oBAAqBD,GACpB,MAAMC,EAAO54C,KAAK64C,gBAAiBF,GAEnC,OAAKC,EACGA,EAAKE,UAEL,EAST,UACC,OAAO94C,KAAKgmC,MAAQhmC,KAAK04C,OAa1B,aACC,MAAM9tC,EAAS5K,KAAKi4C,QACpB,IAAIc,EAAc/4C,KAAK0rB,QAGvB,IAAMstB,GAAQpuC,GAAW,CACxB,IAAImS,EAASnS,EAAOvF,YAAcuF,EAAOquC,wBAGzC,KAAQl8B,IAAWi8B,GAAQj8B,IAAW,CACrC,MAAMm8B,EAAa,IAAI,GAAMn8B,GACvBo8B,EAAmBJ,EAAYF,gBAAiBK,GAEtD,IAAKC,EAOJ,OAAO,KANFA,EAAiBL,UAAYC,EAAYD,YAE7CC,EAAcI,GAOhBp8B,EAASA,EAAO1X,YAIlB,OAAO0zC,EAWR,QAASJ,GACR,IAAM,MAAMS,KAAQrB,GACnB,GAAK/3C,KAAMo5C,KAAWT,EAAaS,GAClC,OAAO,EAIT,OAAO,EASR,SAAUT,GACT,MAAMU,EAAgBr5C,KAAK64C,gBAAiBF,GAE5C,SAAWU,IAAiBA,EAAc/sB,QAASqsB,IAWpD,8BACC,MAAM/tC,EAAS5K,KAAKi4C,QACpB,IAAIqB,EAAgBC,EAAiB3uB,EAErC,GAAKmjB,GAAUnjC,GACd0uC,EAAiB1uC,EAAO4tC,WAAa5tC,EAAO5J,SAASw4C,gBAAgBC,YACrEF,EAAkB3uC,EAAO6tC,YAAc7tC,EAAO5J,SAASw4C,gBAAgBE,aACvE9uB,EAAYhgB,EAAO4sC,iBAAkB5sC,EAAO5J,SAASw4C,iBAAkB5uB,cACjE,CACN,MAAM+uB,EAAepC,GAAiBv3C,KAAKi4C,SAE3CqB,EAAiB1uC,EAAOgvC,YAAchvC,EAAO6uC,YAAcE,EAAa5T,KAAO4T,EAAajC,MAC5F6B,EAAkB3uC,EAAOivC,aAAejvC,EAAO8uC,aAAeC,EAAa7T,IAAM6T,EAAa/B,OAC9FhtB,EAAYhgB,EAAOkrB,cAAcC,YAAYyhB,iBAAkB5sC,GAASggB,UAExE5qB,KAAK+lC,MAAQ4T,EAAa5T,KAC1B/lC,KAAK8lC,KAAO6T,EAAa7T,IACzB9lC,KAAK03C,OAASiC,EAAajC,MAC3B13C,KAAK43C,QAAU+B,EAAa/B,OAC5B53C,KAAKgmC,MAAQhmC,KAAK03C,MAAQ13C,KAAK+lC,KAC/B/lC,KAAK04C,OAAS14C,KAAK43C,OAAS53C,KAAK8lC,IAclC,OAXA9lC,KAAKgmC,OAASsT,EAEK,QAAd1uB,EACJ5qB,KAAK03C,OAAS4B,EAEdt5C,KAAK+lC,MAAQuT,EAGdt5C,KAAK04C,QAAUa,EACfv5C,KAAK43C,QAAU2B,EAERv5C,KASR,wBAAyBivB,GACxB,MAAM6qB,EAAQ,GAERC,EAAc5wC,MAAMiK,KAAM6b,EAAM+qB,kBAEtC,GAAKD,EAAYh4C,OAChB,IAAM,MAAM62C,KAAQmB,EACnBD,EAAM72C,KAAM,IAAI,GAAM21C,QAOnB,CACJ,IAAI/a,EAAiB5O,EAAM4O,eAEtB,GAAQA,KACZA,EAAiBA,EAAex4B,YAGjC,MAAMuzC,EAAO,IAAI,GAAM/a,EAAe0a,yBACtCK,EAAKlB,MAAQkB,EAAK7S,KAClB6S,EAAK5S,MAAQ,EAEb8T,EAAM72C,KAAM21C,GAGb,OAAOkB,EASR,uBAAwBA,GACvB,MAAMG,EAAmB,CACxBlU,KAAM7qB,OAAOkhB,kBACb0J,IAAK5qB,OAAOkhB,kBACZsb,MAAOx8B,OAAOg/B,kBACdtC,OAAQ18B,OAAOg/B,mBAEhB,IAAIC,EAAiB,EAErB,IAAM,MAAMvB,KAAQkB,EACnBK,IAEAF,EAAiBlU,KAAO31B,KAAK0M,IAAKm9B,EAAiBlU,KAAM6S,EAAK7S,MAC9DkU,EAAiBnU,IAAM11B,KAAK0M,IAAKm9B,EAAiBnU,IAAK8S,EAAK9S,KAC5DmU,EAAiBvC,MAAQtnC,KAAKsR,IAAKu4B,EAAiBvC,MAAOkB,EAAKlB,OAChEuC,EAAiBrC,OAASxnC,KAAKsR,IAAKu4B,EAAiBrC,OAAQgB,EAAKhB,QAGnE,OAAuB,GAAlBuC,EACG,MAGRF,EAAiBjU,MAAQiU,EAAiBvC,MAAQuC,EAAiBlU,KACnEkU,EAAiBvB,OAASuB,EAAiBrC,OAASqC,EAAiBnU,IAE9D,IAAI,GAAMmU,KASnB,SAAS5B,GAAoBO,EAAMhuC,GAClC,IAAM,MAAMvL,KAAK04C,GAChBa,EAAMv5C,GAAMuL,EAAQvL,GAStB,SAAS25C,GAAQoB,GAChB,QAAM,GAAWA,IAIVA,IAAmBA,EAAetkB,cAAcukB,KC/ZjD,SAASC,IAA4B,OAAEl5C,EAAM,eAAEm5C,EAAiB,IACtE,MAAMC,EAAeC,GAAWr5C,GAChC,IAAIs5C,EAAgBF,EAChBG,EAAe,KAGnB,KAAQD,GAAgB,CACvB,IAAIE,EASHA,EAAwBC,GADpBH,GAAiBF,EACqBp5C,EAEAu5C,GAI3CG,GAA2BF,EAAuB,IAM1CG,GAAyB35C,EAAQs5C,IAKzC,MAAMM,EAAaD,GAAyB35C,EAAQs5C,GAIpD,GAFAO,GAAwBP,EAAeM,EAAYT,GAE9CG,EAAc39B,QAAU29B,GAY5B,GAPAC,EAAeD,EAAcQ,aAC7BR,EAAgBA,EAAc39B,QAMxB49B,EACL,YAGDD,EAAgB,MAmEnB,SAASO,GAAwB99C,EAAQy7C,EAAM2B,GAC9C,MAAMY,EAAwBvC,EAAKltB,QAAQ0vB,OAAQ,EAAGb,GAChDc,EAAsBzC,EAAKltB,QAAQ0vB,OAAQ,GAAIb,GAC/Ce,EAAe,IAAI,GAAMn+C,GAASo+C,8BAIxC,IAFc,CAAEF,EAAqBF,GAEzBjxB,MAAO0uB,GAAQ0C,EAAanU,SAAUyR,IAAW,CAC5D,IAAI,QAAEtN,EAAO,QAAEC,GAAYpuC,EAEtBq+C,GAASH,EAAqBC,GAClC/P,GAAW+P,EAAaxV,IAAM8S,EAAK9S,IAAMyU,EAC9BkB,GAASN,EAAuBG,KAC3C/P,GAAWqN,EAAKhB,OAAS0D,EAAa1D,OAAS2C,GAK3CmB,GAAU9C,EAAM0C,GACpBhQ,GAAWgQ,EAAavV,KAAO6S,EAAK7S,KAAOwU,EAChCoB,GAAW/C,EAAM0C,KAC5BhQ,GAAWsN,EAAKlB,MAAQ4D,EAAa5D,MAAQ6C,GAG9Cp9C,EAAOyuC,SAAUN,EAASC,IAS5B,SAASuP,GAA2B/9B,EAAQ6+B,GAC3C,MAAMC,EAAepB,GAAW19B,GAChC,IAAIm8B,EAAY8B,EAEhB,KAAQj+B,GAAU8+B,EAAa76C,SAASq5C,MACvCW,EAAaY,IACb1C,EAAa,IAAI,GAAMn8B,GAASw+B,8BAE1BrC,EAAW/R,SAAU6T,KACrBQ,GAASR,EAAY9B,GACzBn8B,EAAO4uB,WAAauN,EAAWpT,IAAMkV,EAAWlV,IACrC2V,GAAST,EAAY9B,KAChCn8B,EAAO4uB,WAAaqP,EAAWpD,OAASsB,EAAWtB,QAG/C8D,GAAUV,EAAY9B,GAC1Bn8B,EAAO2uB,YAAcwN,EAAWnT,KAAOiV,EAAWjV,KACvC4V,GAAWX,EAAY9B,KAClCn8B,EAAO2uB,YAAcsP,EAAWtD,MAAQwB,EAAWxB,QAIrD36B,EAASA,EAAO1X,WASlB,SAASo2C,GAASK,EAAWC,GAC5B,OAAOD,EAAUlE,OAASmE,EAAWnE,OAQtC,SAAS4D,GAASM,EAAWC,GAC5B,OAAOD,EAAUhW,IAAMiW,EAAWjW,IAQnC,SAAS4V,GAAUI,EAAWC,GAC7B,OAAOD,EAAU/V,KAAOgW,EAAWhW,KAQpC,SAAS4V,GAAWG,EAAWC,GAC9B,OAAOD,EAAUpE,MAAQqE,EAAWrE,MAQrC,SAAS+C,GAAWL,GACnB,OAAK9C,GAAS8C,GACNA,EAAevc,eAAe/H,cAAcC,YAE5CqkB,EAAetkB,cAAcC,YAStC,SAAS8kB,GAAkBT,GAC1B,GAAK9C,GAAS8C,GAAmB,CAChC,IAAIr9B,EAASq9B,EAAenB,wBAO5B,OAJK,GAAQl8B,KACZA,EAASA,EAAO1X,YAGV0X,EAEP,OAAOq9B,EAAe/0C,WAWxB,SAAS01C,GAAyB35C,EAAQ46C,GACzC,MAAMxB,EAAeC,GAAWr5C,GAC1Bw3C,EAAO,IAAI,GAAMx3C,GAEvB,GAAKo5C,IAAiBwB,EACrB,OAAOpD,EACD,CACN,IAAI8B,EAAgBF,EAEpB,KAAQE,GAAiBsB,GAAiB,CACzC,MAAMC,EAAQvB,EAAcQ,aACtBgB,EAAY,IAAI,GAAMD,GAAQV,8BAEpC3C,EAAKwC,OAAQc,EAAUnW,KAAMmW,EAAUpW,KAEvC4U,EAAgBA,EAAc39B,QAIhC,OAAO67B,EAxMR36C,OAAO4nC,OAvFO,GAuFQ,CACrByU,8BACA6B,4BAZM,SAAsC/6C,GAG5C05C,GAFqBD,GAAkBz5C,GAEE,IACjC,IAAI,GAAMA,OC/BJ,MAAM,GAIpB,YAAa4kB,GAOZhmB,KAAKgB,SAAW,IAAI,GAAUglB,GAU9BhmB,KAAK21B,aAAe,IAAI,GAAc31B,KAAKgB,UAQ3ChB,KAAKo8C,SAAW,IAAItoC,IAQpB9T,KAAKyJ,IAAK,yBAAyB,GAQnCzJ,KAAKyJ,IAAK,mBAAmB,GAQ7BzJ,KAAKyxC,UAAY,IAAI,GAAUzxC,KAAK21B,aAAc31B,KAAKgB,SAASopB,WAChEpqB,KAAKyxC,UAAU1yC,KAAM,aAAc6U,GAAI5T,KAAKgB,UAW5ChB,KAAKq8C,0BAA4B,IAAI/mC,QAQrCtV,KAAKs8C,WAAa,IAAIxoC,IAQtB9T,KAAKu8C,gBAAiB,EAQtBv8C,KAAKw8C,uBAAwB,EAQ7Bx8C,KAAKy8C,oBAAqB,EAS1Bz8C,KAAK08C,kCAAmC,EAQxC18C,KAAK28C,QAAU,IAAI,GAAgB38C,KAAKgB,UAGxChB,KAAK48C,YAAa,IAClB58C,KAAK48C,YAAa,IAClB58C,KAAK48C,YAAa,IAClB58C,KAAK48C,YAAa,IAClB58C,KAAK48C,YAAa,IAClB58C,KAAK48C,YAAa,IAEb,GAAI/pB,WACR7yB,KAAK48C,YAAa,IAIG58C,K5C5DlBgB,SAASkoB,GAAI,UAAWyV,I4C6D5BlJ,GAAyBz1B,MAGzBA,KAAKkpB,GAAI,SAAU,KAClBlpB,KAAK68C,UAGL78C,KAAKgB,SAASqT,KAAM,iBAGpBrU,KAAK08C,kCAAmC,IAIzC18C,KAAKmR,SAAUnR,KAAKgB,SAASopB,UAAW,SAAU,KACjDpqB,KAAK08C,kCAAmC,IAiB1C,cAAehX,EAAS5nC,EAAO,QAC9B,MAAMg/C,EAAW98C,KAAKgB,SAAS+7C,QAASj/C,GAGxCg/C,EAASE,MAAQtX,EAAQmB,QAAQpU,cAEjC,MAAMwqB,EAA2B,GASjC,IAAM,MAAM,KAAEn/C,EAAI,MAAEU,KAAW2K,MAAMiK,KAAMsyB,EAAQpiC,YAClD25C,EAA0Bn/C,GAASU,EAMrB,UAATV,EACJkC,KAAK28C,QAAQhgB,SAAUn+B,EAAM+Q,MAAO,KAAOutC,GAE3C98C,KAAK28C,QAAQj5C,aAAc5F,EAAMU,EAAOs+C,GAI1C98C,KAAKq8C,0BAA0B5yC,IAAKi8B,EAASuX,GAE7C,MAAMC,EAAiC,KACtCl9C,KAAK28C,QAAQj5C,aAAc,mBAAoBo5C,EAASK,WAAYL,GAE/DA,EAASK,WACbn9C,KAAK28C,QAAQhgB,SAAU,eAAgBmgB,GAEvC98C,KAAK28C,QAAQ9f,YAAa,eAAgBigB,IAK5CI,IAEAl9C,KAAKo8C,SAAS3yC,IAAK3L,EAAM4nC,GACzB1lC,KAAK21B,aAAa2N,aAAcoC,EAASoX,GACzC98C,KAAKyxC,UAAUmB,WAAY,WAAYkK,GACvC98C,KAAKyxC,UAAUmB,WAAY,aAAckK,GACzC98C,KAAKyxC,UAAUvQ,aAAatyB,IAAK82B,EAAQ5P,eAEzCgnB,EAAS5zB,GAAI,kBAAmB,CAAEpS,EAAKvE,IAAUvS,KAAKyxC,UAAUmB,WAAY,WAAYrgC,IACxFuqC,EAAS5zB,GAAI,oBAAqB,CAAEpS,EAAKvE,IAAUvS,KAAKyxC,UAAUmB,WAAY,aAAcrgC,IAC5FuqC,EAAS5zB,GAAI,cAAe,CAAEpS,EAAKvE,IAAUvS,KAAKyxC,UAAUmB,WAAY,OAAQrgC,IAChFuqC,EAAS5zB,GAAI,oBAAqB,IAAMlpB,KAAKo9C,OAAQF,IAErDJ,EAAS5zB,GAAI,SAAU,KACtBlpB,KAAK08C,kCAAmC,IAGzC,IAAM,MAAMW,KAAYr9C,KAAKs8C,WAAWjwC,SACvCgxC,EAAStL,QAASrM,EAAS5nC,GAU7B,cAAeA,GACd,MAAM4nC,EAAU1lC,KAAKo8C,SAASh+C,IAAKN,GAGnCqL,MAAMiK,KAAMsyB,EAAQpiC,YAAaG,QAAS,EAAI3F,UAAY4nC,EAAQ9gC,gBAAiB9G,IAEnF,MAAMm/C,EAA2Bj9C,KAAKq8C,0BAA0Bj+C,IAAKsnC,GAGrE,IAAM,MAAMvmB,KAAa89B,EACxBvX,EAAQhiC,aAAcyb,EAAW89B,EAA0B99B,IAG5Dnf,KAAKo8C,SAASroC,OAAQjW,GACtBkC,KAAK21B,aAAa0N,iBAAkBqC,GASrC,WAAY5nC,EAAO,QAClB,OAAOkC,KAAKo8C,SAASh+C,IAAKN,GAgB3B,YAAauxC,GACZ,IAAIgO,EAAWr9C,KAAKs8C,WAAWl+C,IAAKixC,GAEpC,GAAKgO,EACJ,OAAOA,EAGRA,EAAW,IAAIhO,EAAUrvC,MAEzBA,KAAKs8C,WAAW7yC,IAAK4lC,EAAUgO,GAE/B,IAAM,MAAQv/C,EAAMy3B,KAAgBv1B,KAAKo8C,SACxCiB,EAAStL,QAASxc,EAAYz3B,GAK/B,OAFAu/C,EAASrL,SAEFqL,EASR,YAAahO,GACZ,OAAOrvC,KAAKs8C,WAAWl+C,IAAKixC,GAM7B,mBACC,IAAM,MAAMgO,KAAYr9C,KAAKs8C,WAAWjwC,SACvCgxC,EAAS9N,UAOX,kBACC,IAAM,MAAM8N,KAAYr9C,KAAKs8C,WAAWjwC,SACvCgxC,EAASrL,SAQX,uBACC,MAAM/iB,EAAQjvB,KAAKgB,SAASopB,UAAUmF,gBAEjCN,GACJqrB,GAA4B,CAC3Bl5C,OAAQpB,KAAK21B,aAAa2nB,eAAgBruB,GAC1CsrB,eAAgB,KASnB,QACC,IAAMv6C,KAAKgB,SAASmpB,UAAY,CAC/B,MAAMqC,EAAWxsB,KAAKgB,SAASopB,UAAUC,gBAEpCmC,IACJxsB,KAAK21B,aAAa9F,MAAOrD,GACzBxsB,KAAKszC,gBAwCR,OAAQpiC,GACP,GAAKlR,KAAKu9C,uBAAyBv9C,KAAKw8C,sBAYvC,MAAM,IAAI,KACT,0BACAx8C,MAIF,IAEC,GAAKA,KAAKu8C,eACT,OAAOrrC,EAAUlR,KAAK28C,SAKvB38C,KAAKu8C,gBAAiB,EACtB,MAAMiB,EAAiBtsC,EAAUlR,KAAK28C,SActC,OAbA38C,KAAKu8C,gBAAiB,GAKhBv8C,KAAKy8C,oBAAsBz8C,KAAK08C,mCACrC18C,KAAKw8C,uBAAwB,EAC7Bx8C,KAAKgB,SAASy8C,gBAAiBz9C,KAAK28C,SACpC38C,KAAKw8C,uBAAwB,EAE7Bx8C,KAAKqU,KAAM,WAGLmpC,EACN,MAAQt9C,GAGT,KAAcyT,uBAAwBzT,EAAKF,OAc7C,cACCA,KAAK08C,kCAAmC,EACxC18C,KAAKo9C,OAAQ,QAMd,UACC,IAAM,MAAMC,KAAYr9C,KAAKs8C,WAAWjwC,SACvCgxC,EAASnjC,UAGVla,KAAKgB,SAASkZ,UAEdla,KAAKsR,gBAoBN,iBAAkByb,EAAgBzgB,GACjC,OAAO,GAASwe,UAAWiC,EAAgBzgB,GAS5C,oBAAqBjK,GACpB,OAAO,GAASwpB,aAAcxpB,GAS/B,qBAAsBA,GACrB,OAAO,GAAS8pB,cAAe9pB,GAYhC,YAAawe,EAAOC,GACnB,OAAO,IAAI,GAAOD,EAAOC,GAS1B,cAAeze,GACd,OAAO,GAAMwuB,UAAWxuB,GAUzB,cAAeuc,GACd,OAAO,GAAMgS,UAAWhS,GA+DzB,gBAAiB+P,EAAYC,EAAe1sB,GAC3C,OAAO,IAAI,GAAWysB,EAAYC,EAAe1sB,GAUlD,kBAAmBw7C,GAClB19C,KAAKy8C,mBAAqBiB,EAEb,GAARA,GAEJ19C,KAAKo9C,OAAQ,QAUf,UACCp9C,KAAKu9C,uBAAwB,EAC7Bv9C,KAAK29C,mBACL39C,KAAKyxC,UAAUja,SACfx3B,KAAK49C,kBACL59C,KAAKu9C,uBAAwB,GAqB/B/oC,GAAK,GAAM,IC9pBI,MAAM,GASpB,YAAagR,GASZxlB,KAAK+c,OAAS,KAQd/c,KAAKylB,OAASnH,GAAOkH,GAYtB,YACC,IAAIxI,EAEJ,IAAMhd,KAAK+c,OACV,OAAO,KAGR,GAAqD,QAA9CC,EAAMhd,KAAK+c,OAAOE,cAAejd,OACvC,MAAM,IAAI,KAAe,iCAAkCA,MAG5D,OAAOgd,EAaR,kBACC,IAAIA,EAEJ,IAAMhd,KAAK+c,OACV,OAAO,KAGR,GAA2D,QAApDC,EAAMhd,KAAK+c,OAAO8gC,oBAAqB79C,OAC7C,MAAM,IAAI,KAAe,iCAAkCA,MAG5D,OAAOgd,EAYR,iBACC,OAAO,EAWR,gBACC,OAAMhd,KAAK+c,OAIJ/c,KAAKosB,YAAcpsB,KAAKwuB,WAHvB,KAYT,kBACC,MAAM9rB,EAAQ1C,KAAK0C,MAEnB,OAAmB,OAAVA,GAAkB1C,KAAK+c,OAAOG,SAAUxa,EAAQ,IAAS,KASnE,sBACC,MAAMA,EAAQ1C,KAAK0C,MAEnB,OAAmB,OAAVA,GAAkB1C,KAAK+c,OAAOG,SAAUxa,EAAQ,IAAS,KAUnE,WACC,IAAI7F,EAAOmD,KAEX,KAAQnD,EAAKkgB,QACZlgB,EAAOA,EAAKkgB,OAGb,OAAOlgB,EAQR,aACC,OAAOmD,KAAKnD,KAAKsD,GAAI,eAmBtB,UACC,MAAM0P,EAAO,GACb,IAAI0C,EAAOvS,KAEX,KAAQuS,EAAKwK,QACZlN,EAAKsN,QAAS5K,EAAK6Z,aACnB7Z,EAAOA,EAAKwK,OAGb,OAAOlN,EAYR,aAAc3N,EAAU,CAAEkb,aAAa,EAAOC,aAAa,IAC1D,MAAMC,EAAY,GAClB,IAAIP,EAAS7a,EAAQkb,YAAcpd,KAAOA,KAAK+c,OAE/C,KAAQA,GACPO,EAAWpb,EAAQmb,YAAc,OAAS,WAAaN,GACvDA,EAASA,EAAOA,OAGjB,OAAOO,EAaR,kBAAmB/K,EAAMrQ,EAAU,IAClC,MAAMqb,EAAavd,KAAKwd,aAActb,GAChCub,EAAalL,EAAKiL,aAActb,GAEtC,IAAI3E,EAAI,EAER,KAAQggB,EAAYhgB,IAAOkgB,EAAYlgB,IAAOggB,EAAYhgB,IACzDA,IAGD,OAAa,IAANA,EAAU,KAAOggB,EAAYhgB,EAAI,GAUzC,SAAUgV,GAET,GAAKvS,MAAQuS,EACZ,OAAO,EAIR,GAAKvS,KAAKnD,OAAS0V,EAAK1V,KACvB,OAAO,EAGR,MAAM6gB,EAAW1d,KAAK2d,UAChBC,EAAWrL,EAAKoL,UAEhB7b,EAAS4a,GAAegB,EAAUE,GAExC,OAAS9b,GACR,IAAK,SACJ,OAAO,EAER,IAAK,YACJ,OAAO,EAER,QACC,OAAO4b,EAAU5b,GAAW8b,EAAU9b,IAWzC,QAASyQ,GAER,OAAKvS,MAAQuS,IAKRvS,KAAKnD,OAAS0V,EAAK1V,OAKhBmD,KAAK6d,SAAUtL,IASxB,aAAczT,GACb,OAAOkB,KAAKylB,OAAO/b,IAAK5K,GASzB,aAAcA,GACb,OAAOkB,KAAKylB,OAAOrnB,IAAKU,GAWzB,gBACC,OAAOkB,KAAKylB,OAAOnc,UAQpB,mBACC,OAAOtJ,KAAKylB,OAAOjiB,OAQpB,SACC,MAAMwa,EAAO,GAYb,OARKhe,KAAKylB,OAAOzc,OAChBgV,EAAK1a,WAAa6F,MAAMiK,KAAMpT,KAAKylB,QAASpO,OAAQ,CAAEvV,EAAQ0iC,KAC7D1iC,EAAQ0iC,EAAM,IAAQA,EAAM,GAErB1iC,GACL,KAGGkc,EA8CR,GAAI/d,GACH,MAAgB,SAATA,GAA4B,eAATA,EAS3B,SACC,OAAO,IAAI,GAAMD,KAAKylB,QASvB,UACCzlB,KAAK+c,OAAOe,gBAAiB9d,KAAK0C,OAWnC,cAAe5D,EAAKN,GACnBwB,KAAKylB,OAAOhc,IAAK3K,EAAKN,GAUvB,iBAAkBgnB,GACjBxlB,KAAKylB,OAASnH,GAAOkH,GAWtB,iBAAkB1mB,GACjB,OAAOkB,KAAKylB,OAAO1R,OAAQjV,GAS5B,mBACCkB,KAAKylB,OAAOlc,SCxdC,MAAM,WAAa,GAWjC,YAAa5J,EAAM6lB,GAClB5lB,MAAO4lB,GAQPxlB,KAAKy9B,MAAQ99B,GAAQ,GAMtB,iBACC,OAAOK,KAAKL,KAAKoC,OASlB,WACC,OAAO/B,KAAKy9B,MAsBb,GAAIx9B,GACH,MAAgB,UAATA,GAA6B,gBAATA,GAEjB,SAATA,GAA4B,eAATA,GAEV,SAATA,GAA4B,eAATA,EAQrB,SACC,MAAM+d,EAAOpe,MAAMk+C,SAInB,OAFA9/B,EAAKre,KAAOK,KAAKL,KAEVqe,EASR,SACC,OAAO,IAAI,GAAMhe,KAAKL,KAAMK,KAAK+6B,iBASlC,gBAAiB/c,GAChB,OAAO,IAAI,GAAMA,EAAKre,KAAMqe,EAAK1a,aCjFpB,MAAM,GAWpB,YAAa6a,EAAUC,EAAcrc,GASpC,GAFA/B,KAAKme,SAAWA,EAEXC,EAAe,GAAKA,EAAeD,EAASqQ,WAMhD,MAAM,IAAI,KAAe,qCAAsCxuB,MAGhE,GAAK+B,EAAS,GAAKqc,EAAerc,EAASoc,EAASqQ,WAMnD,MAAM,IAAI,KAAe,+BAAgCxuB,MAS1DA,KAAKL,KAAOwe,EAASxe,KAAK0e,UAAWD,EAAcA,EAAerc,GAQlE/B,KAAKoe,aAAeA,EAUrB,kBACC,OAAqC,OAA9Bpe,KAAKme,SAASiO,YAAuBpsB,KAAKme,SAASiO,YAAcpsB,KAAKoe,aAAe,KAU7F,iBACC,OAAOpe,KAAKL,KAAKoC,OAUlB,gBACC,OAA4B,OAArB/B,KAAKosB,YAAuBpsB,KAAKosB,YAAcpsB,KAAKwuB,WAAa,KAczE,gBACC,OAAOxuB,KAAKwuB,aAAexuB,KAAKme,SAASqQ,WAS1C,aACC,OAAOxuB,KAAKme,SAASpB,OAStB,WACC,OAAO/c,KAAKme,SAASthB,KAoBtB,GAAIoD,GACH,MAAgB,eAATA,GAAkC,qBAATA,GAEtB,cAATA,GAAiC,oBAATA,EAS1B,UACC,MAAM4P,EAAO7P,KAAKme,SAASR,UAM3B,OAJK9N,EAAK9N,OAAS,IAClB8N,EAAMA,EAAK9N,OAAS,IAAO/B,KAAKoe,cAG1BvO,EAYR,aAAc3N,EAAU,CAAEkb,aAAa,EAAOC,aAAa,IAC1D,MAAMC,EAAY,GAClB,IAAIP,EAAS7a,EAAQkb,YAAcpd,KAAOA,KAAK+c,OAE/C,KAAQA,GACPO,EAAWpb,EAAQmb,YAAc,OAAS,WAAaN,GACvDA,EAASA,EAAOA,OAGjB,OAAOO,EASR,aAAcxe,GACb,OAAOkB,KAAKme,SAASe,aAAcpgB,GASpC,aAAcA,GACb,OAAOkB,KAAKme,SAASiB,aAActgB,GAWpC,gBACC,OAAOkB,KAAKme,SAAS4c,gBAQtB,mBACC,OAAO/6B,KAAKme,SAASqX,oBCtPR,MAAM,GAOpB,YAAazO,GAOZ/mB,KAAK+9C,OAAS,GAETh3B,GACJ/mB,KAAKg+C,aAAc,EAAGj3B,GAWxB,CAAEzoB,OAAOiW,YACR,OAAOvU,KAAK+9C,OAAQz/C,OAAOiW,YAS5B,aACC,OAAOvU,KAAK+9C,OAAOh8C,OASpB,gBACC,OAAO/B,KAAK+9C,OAAO1mC,OAAQ,CAAEyd,EAAKviB,IAAUuiB,EAAMviB,EAAKic,WAAY,GASpE,QAAS9rB,GACR,OAAO1C,KAAK+9C,OAAQr7C,IAAW,KAShC,aAAc6P,GACb,MAAM7P,EAAQ1C,KAAK+9C,OAAOjrC,QAASP,GAEnC,OAAiB,GAAV7P,EAAc,KAAOA,EAU7B,mBAAoB6P,GACnB,MAAM7P,EAAQ1C,KAAKi+C,aAAc1rC,GAEjC,OAAiB,OAAV7P,EAAiB,KAAO1C,KAAK+9C,OAAOt2C,MAAO,EAAG/E,GAAQ2U,OAAQ,CAAEyd,EAAKviB,IAAUuiB,EAAMviB,EAAKic,WAAY,GAY9G,cAAe9rB,GACd,GAAKA,GAAS1C,KAAK+9C,OAAOh8C,OACzB,OAAO/B,KAAKk+C,UAGb,MAAM3rC,EAAOvS,KAAK+9C,OAAQr7C,GAE1B,IAAM6P,EAML,MAAM,IAAI,KAAe,qCAAsCvS,MAGhE,OAAOA,KAAKm+C,mBAAoB5rC,GAYjC,cAAejG,GACd,IAAI8xC,EAAc,EAElB,IAAM,MAAM7rC,KAAQvS,KAAK+9C,OAAS,CACjC,GAAKzxC,GAAU8xC,GAAe9xC,EAAS8xC,EAAc7rC,EAAKic,WACzD,OAAOxuB,KAAKi+C,aAAc1rC,GAG3B6rC,GAAe7rC,EAAKic,WAGrB,GAAK4vB,GAAe9xC,EAQnB,MAAM,IAAI,KAAe,sCACxBtM,KACA,CACCsM,SACA+xC,SAAUr+C,OAKb,OAAOA,KAAK+B,OAUb,aAAcW,EAAOqkB,GAEpB,IAAM,MAAMxU,KAAQwU,EACnB,KAAQxU,aAAgB,IAMvB,MAAM,IAAI,KAAe,sCAAuCvS,MAIlEA,KAAK+9C,OAAOj4C,OAAQpD,EAAO,KAAMqkB,GAWlC,aAAcu3B,EAAYr3B,EAAU,GACnC,OAAOjnB,KAAK+9C,OAAOj4C,OAAQw4C,EAAYr3B,GASxC,SACC,OAAOjnB,KAAK+9C,OAAO1zC,IAAKkI,GAAQA,EAAKurC,WC7LxB,MAAM,WAAgB,GAapC,YAAahgD,EAAM0nB,EAAO1d,GACzBlI,MAAO4lB,GAQPxlB,KAAKlC,KAAOA,EAQZkC,KAAK2lB,UAAY,IAAI,GAEhB7d,GACJ9H,KAAK4lB,aAAc,EAAG9d,GAUxB,iBACC,OAAO9H,KAAK2lB,UAAU5jB,OASvB,gBACC,OAAO/B,KAAK2lB,UAAUu4B,UASvB,cACC,OAA2B,IAApBl+C,KAAK8mB,WA2Bb,GAAI7mB,EAAMnC,EAAO,MAChB,OAAMA,EAMCA,IAASkC,KAAKlC,OAAmB,YAATmC,GAA+B,kBAATA,GALpC,YAATA,GAA+B,kBAATA,GAEnB,SAATA,GAA4B,eAATA,EAYtB,SAAUyC,GACT,OAAO1C,KAAK2lB,UAAU44B,QAAS77C,GAQhC,cACC,OAAO1C,KAAK2lB,UAAWrnB,OAAOiW,YAS/B,cAAehC,GACd,OAAOvS,KAAK2lB,UAAUs4B,aAAc1rC,GAWrC,oBAAqBA,GACpB,OAAOvS,KAAK2lB,UAAUw4B,mBAAoB5rC,GAoB3C,cAAejG,GACd,OAAOtM,KAAK2lB,UAAU64B,cAAelyC,GActC,cAAemyC,GACd,IAAIlsC,EAAOvS,KAEX,IAAM,MAAM0C,KAAS+7C,EACpBlsC,EAAOA,EAAK2K,SAAU3K,EAAKisC,cAAe97C,IAG3C,OAAO6P,EAWR,aAAcmsC,EAAYx8C,EAAU,CAAEkb,aAAa,IAClD,IAAIL,EAAS7a,EAAQkb,YAAcpd,KAAOA,KAAK+c,OAE/C,KAAQA,GAAS,CAChB,GAAKA,EAAOjf,OAAS4gD,EACpB,OAAO3hC,EAGRA,EAASA,EAAOA,OAGjB,OAAO,KAQR,SACC,MAAMiB,EAAOpe,MAAMk+C,SAInB,GAFA9/B,EAAKlgB,KAAOkC,KAAKlC,KAEZkC,KAAK2lB,UAAU5jB,OAAS,EAAI,CAChCic,EAAKlW,SAAW,GAEhB,IAAM,MAAMyK,KAAQvS,KAAK2lB,UACxB3H,EAAKlW,SAAS7E,KAAMsP,EAAKurC,UAI3B,OAAO9/B,EAWR,OAAQuI,GAAO,GACd,MAAMze,EAAWye,EAAOpd,MAAMiK,KAAMpT,KAAK2lB,WAAYtb,IAAKkI,GAAQA,EAAKoU,QAAQ,IAAW,KAE1F,OAAO,IAAI,GAAS3mB,KAAKlC,KAAMkC,KAAK+6B,gBAAiBjzB,GAUtD,aAAcif,GACb/mB,KAAK4lB,aAAc5lB,KAAK8mB,WAAYC,GAYrC,aAAcrkB,EAAOiT,GACpB,MAAMoR,EA+HR,SAAoBA,GAEnB,GAAqB,iBAATA,EACX,MAAO,CAAE,IAAI,GAAMA,IAGdzS,GAAYyS,KACjBA,EAAQ,CAAEA,IAIX,OAAO5d,MAAMiK,KAAM2T,GACjB1c,IAAKkI,GACe,iBAARA,EACJ,IAAI,GAAMA,GAGbA,aAAgB,GACb,IAAI,GAAMA,EAAK5S,KAAM4S,EAAKwoB,iBAG3BxoB,GApJM,CAAWoD,GAEzB,IAAM,MAAMpD,KAAQwU,EAEE,OAAhBxU,EAAKwK,QACTxK,EAAK2D,UAGN3D,EAAKwK,OAAS/c,KAGfA,KAAK2lB,UAAUq4B,aAAct7C,EAAOqkB,GAarC,gBAAiBrkB,EAAOukB,EAAU,GACjC,MAAMF,EAAQ/mB,KAAK2lB,UAAUg5B,aAAcj8C,EAAOukB,GAElD,IAAM,MAAM1U,KAAQwU,EACnBxU,EAAKwK,OAAS,KAGf,OAAOgK,EAUR,gBAAiB/I,GAChB,IAAIlW,EAAW,KAEf,GAAKkW,EAAKlW,SAAW,CACpBA,EAAW,GAEX,IAAM,MAAM2e,KAASzI,EAAKlW,SACpB2e,EAAM3oB,KAEVgK,EAAS7E,KAAM,GAAQ27C,SAAUn4B,IAGjC3e,EAAS7E,KAAM,GAAK27C,SAAUn4B,IAKjC,OAAO,IAAI,GAASzI,EAAKlgB,KAAMkgB,EAAK1a,WAAYwE,IClUnC,MAAM,GAmBpB,YAAa5F,EAAU,IACtB,IAAMA,EAAQwoB,aAAexoB,EAAQyoB,cAMpC,MAAM,IAAI,KACT,sCACA,MAIF,MAAMC,EAAY1oB,EAAQ0oB,WAAa,UAEvC,GAAkB,WAAbA,GAAuC,YAAbA,EAM9B,MAAM,IAAI,KAAe,sCAAuC1oB,EAAS,CAAE0oB,cAS5E5qB,KAAK4qB,UAAYA,EAajB5qB,KAAK0qB,WAAaxoB,EAAQwoB,YAAc,KAWnCxoB,EAAQyoB,cACZ3qB,KAAK6qB,SAAW3oB,EAAQyoB,cAAce,QAEtC1rB,KAAK6qB,SAAW,GAASC,UAAW9qB,KAAK0qB,WAA8B,YAAlB1qB,KAAK4qB,UAA0B,MAAQ,UAI7F5qB,KAAK6qB,SAASg0B,WAAa,SAS3B7+C,KAAK+qB,mBAAqB7oB,EAAQ6oB,iBASlC/qB,KAAKgrB,UAAY9oB,EAAQ8oB,QAWzBhrB,KAAKirB,mBAAqB/oB,EAAQ+oB,iBAQlCjrB,KAAKkrB,qBAAuBlrB,KAAK0qB,WAAa1qB,KAAK0qB,WAAW7J,MAAM9D,OAAS,KAQ7E/c,KAAKmrB,mBAAqBnrB,KAAK0qB,WAAa1qB,KAAK0qB,WAAW5J,IAAI/D,OAAS,KASzE/c,KAAK8+C,eAAiB9+C,KAAK6qB,SAAS9N,OAQrC,CAAEze,OAAOiW,YACR,OAAOvU,KAeR,KAAMorB,GACL,IAAIC,EAAM7sB,EAAO8sB,EAAcyzB,EAE/B,GACCzzB,EAAetrB,KAAK6qB,SACpBk0B,EAAoB/+C,KAAK8+C,iBAErBzzB,OAAM7sB,SAAUwB,KAAKurB,eACfF,GAAQD,EAAM5sB,IAEnB6sB,IACLrrB,KAAK6qB,SAAWS,EAChBtrB,KAAK8+C,eAAiBC,GASxB,OACC,MAAuB,WAAlB/+C,KAAK4qB,UACF5qB,KAAKwrB,QAELxrB,KAAKyrB,YAYd,QACC,MAAME,EAAmB3rB,KAAK6qB,SACxBA,EAAW7qB,KAAK6qB,SAASa,QACzB3O,EAAS/c,KAAK8+C,eAGpB,GAAuB,OAAlB/hC,EAAOA,QAAmB8N,EAASve,SAAWyQ,EAAOmhC,UACzD,MAAO,CAAE7yB,MAAM,GAIhB,GAAKtO,IAAW/c,KAAKmrB,oBAAsBN,EAASve,QAAUtM,KAAK0qB,WAAW5J,IAAIxU,OACjF,MAAO,CAAE+e,MAAM,GAKhB,MAAMoN,EAAiB5N,EAAS9N,OAC1BiiC,EAAqBC,GAAuBp0B,EAAU4N,GACtDlmB,EAAOysC,GAA0CE,GAAsBr0B,EAAU4N,EAAgBumB,GAEvG,GAAKzsC,aAAgB,GAWpB,OAVMvS,KAAKgrB,QAKVH,EAASve,UAHTue,EAAShb,KAAK5M,KAAM,GACpBjD,KAAK8+C,eAAiBvsC,GAKvBvS,KAAK6qB,SAAWA,EAETs0B,GAAmB,eAAgB5sC,EAAMoZ,EAAkBd,EAAU,GACtE,GAAKtY,aAAgB,GAAO,CAClC,IAAIwZ,EAEJ,GAAK/rB,KAAK+qB,iBACTgB,EAAkB,MACZ,CACN,IAAIzf,EAASiG,EAAKga,UAEbvsB,KAAKmrB,oBAAsBpO,GAAU/c,KAAK0qB,WAAW5J,IAAIxU,OAASA,IACtEA,EAAStM,KAAK0qB,WAAW5J,IAAIxU,QAG9Byf,EAAkBzf,EAASue,EAASve,OAGrC,MAAM8yC,EAAmBv0B,EAASve,OAASiG,EAAK6Z,YAC1C/pB,EAAO,IAAI,GAAWkQ,EAAM6sC,EAAkBrzB,GAKpD,OAHAlB,EAASve,QAAUyf,EACnB/rB,KAAK6qB,SAAWA,EAETs0B,GAAmB,OAAQ98C,EAAMspB,EAAkBd,EAAUkB,GAQpE,OALAlB,EAAShb,KAAKzG,MACdyhB,EAASve,SACTtM,KAAK6qB,SAAWA,EAChB7qB,KAAK8+C,eAAiB/hC,EAAOA,OAExB/c,KAAKirB,iBACFjrB,KAAKwrB,QAEL2zB,GAAmB,aAAcpiC,EAAQ4O,EAAkBd,GAarE,YACC,MAAMc,EAAmB3rB,KAAK6qB,SACxBA,EAAW7qB,KAAK6qB,SAASa,QACzB3O,EAAS/c,KAAK8+C,eAGpB,GAAuB,OAAlB/hC,EAAOA,QAAuC,IAApB8N,EAASve,OACvC,MAAO,CAAE+e,MAAM,GAIhB,GAAKtO,GAAU/c,KAAKkrB,sBAAwBL,EAASve,QAAUtM,KAAK0qB,WAAW7J,MAAMvU,OACpF,MAAO,CAAE+e,MAAM,GAKhB,MAAMoN,EAAiB5N,EAAS9N,OAC1BiiC,EAAqBC,GAAuBp0B,EAAU4N,GACtDlmB,EAAOysC,GAA0CK,GAAuBx0B,EAAU4N,EAAgBumB,GAExG,GAAKzsC,aAAgB,GAGpB,OAFAsY,EAASve,SAEHtM,KAAKgrB,SAWVhrB,KAAK6qB,SAAWA,EAETs0B,GAAmB,eAAgB5sC,EAAMoZ,EAAkBd,EAAU,KAZ5EA,EAAShb,KAAK5M,KAAMsP,EAAK2rC,WACzBl+C,KAAK6qB,SAAWA,EAChB7qB,KAAK8+C,eAAiBvsC,EAEjBvS,KAAKirB,iBACFjrB,KAAKyrB,YAEL0zB,GAAmB,aAAc5sC,EAAMoZ,EAAkBd,IAO5D,GAAKtY,aAAgB,GAAO,CAClC,IAAIwZ,EAEJ,GAAK/rB,KAAK+qB,iBACTgB,EAAkB,MACZ,CACN,IAAIzf,EAASiG,EAAK6Z,YAEbpsB,KAAKkrB,sBAAwBnO,GAAU/c,KAAK0qB,WAAW7J,MAAMvU,OAASA,IAC1EA,EAAStM,KAAK0qB,WAAW7J,MAAMvU,QAGhCyf,EAAkBlB,EAASve,OAASA,EAGrC,MAAM8yC,EAAmBv0B,EAASve,OAASiG,EAAK6Z,YAC1C/pB,EAAO,IAAI,GAAWkQ,EAAM6sC,EAAmBrzB,EAAiBA,GAKtE,OAHAlB,EAASve,QAAUyf,EACnB/rB,KAAK6qB,SAAWA,EAETs0B,GAAmB,OAAQ98C,EAAMspB,EAAkBd,EAAUkB,GAOpE,OAJAlB,EAAShb,KAAKzG,MACdpJ,KAAK6qB,SAAWA,EAChB7qB,KAAK8+C,eAAiB/hC,EAAOA,OAEtBoiC,GAAmB,eAAgBpiC,EAAQ4O,EAAkBd,EAAU,IAKjF,SAASs0B,GAAmBl/C,EAAMoC,EAAMspB,EAAkBU,EAActqB,GACvE,MAAO,CACNspB,MAAM,EACN7sB,MAAO,CACNyB,OACAoC,OACAspB,mBACAU,eACAtqB,WC7UY,MAAM,GASpB,YAAalF,EAAMgT,EAAMgvC,EAAa,UACrC,IAAMhiD,EAAKsD,GAAI,aAAgBtD,EAAKsD,GAAI,oBAQvC,MAAM,IAAI,KACT,8BACAtD,GAIF,KAAQgT,aAAgB1G,QAA2B,IAAhB0G,EAAK9N,OAOvC,MAAM,IAAI,KACT,uCACAlF,EACA,CAAEgT,SAKChT,EAAKsD,GAAI,eACb0P,EAAOA,EAAKpI,SAEZoI,EAAO,IAAKhT,EAAK8gB,aAAc9N,GAC/BhT,EAAOA,EAAKA,MAUbmD,KAAKnD,KAAOA,EAgCZmD,KAAK6P,KAAOA,EAOZ7P,KAAK6+C,WAAaA,EASnB,aACC,OAAO7+C,KAAK6P,KAAM7P,KAAK6P,KAAK9N,OAAS,GAGtC,WAAYu9C,GACXt/C,KAAK6P,KAAM7P,KAAK6P,KAAK9N,OAAS,GAAMu9C,EAerC,aACC,IAAIviC,EAAS/c,KAAKnD,KAElB,IAAM,IAAIU,EAAI,EAAGA,EAAIyC,KAAK6P,KAAK9N,OAAS,EAAGxE,IAG1C,GAFAwf,EAASA,EAAOG,SAAUH,EAAOyhC,cAAex+C,KAAK6P,KAAMtS,MAErDwf,EAgBL,MAAM,IAAI,KAAe,gCAAiC/c,KAAM,CAAE6qB,SAAU7qB,OAI9E,GAAK+c,EAAO5c,GAAI,SACf,MAAM,IAAI,KAAe,gCAAiCH,KAAM,CAAE6qB,SAAU7qB,OAG7E,OAAO+c,EAWR,YACC,OAAO/c,KAAK+c,OAAOyhC,cAAex+C,KAAKsM,QAUxC,eACC,OAAO2yC,GAAuBj/C,KAAMA,KAAK+c,QAS1C,gBAEC,MAAMA,EAAS/c,KAAK+c,OAEpB,OAAOmiC,GAAsBl/C,KAAM+c,EAAQkiC,GAAuBj/C,KAAM+c,IASzE,iBAEC,MAAMA,EAAS/c,KAAK+c,OAEpB,OAAOsiC,GAAuBr/C,KAAM+c,EAAQkiC,GAAuBj/C,KAAM+c,IAS1E,gBACC,OAAuB,IAAhB/c,KAAKsM,OASb,cACC,OAAOtM,KAAKsM,QAAUtM,KAAK+c,OAAOmhC,UAWnC,YAAatxB,GACZ,GAAK5sB,KAAKnD,MAAQ+vB,EAAc/vB,KAC/B,MAAO,YAGR,MAAMiF,EAAS4a,GAAe1c,KAAK6P,KAAM+c,EAAc/c,MAEvD,OAAS/N,GACR,IAAK,OACJ,MAAO,OAER,IAAK,SACJ,MAAO,SAER,IAAK,YACJ,MAAO,QAER,QACC,OAAO9B,KAAK6P,KAAM/N,GAAW8qB,EAAc/c,KAAM/N,GAAW,SAAW,SAyB1E,wBAAyBspB,EAAMlpB,EAAU,IACxCA,EAAQyoB,cAAgB3qB,KAExB,MAAM2sB,EAAa,IAAI,GAAYzqB,GAGnC,OAFAyqB,EAAWvB,KAAMA,GAEVuB,EAAW9B,SAWnB,gBACC,OAAO7qB,KAAK6P,KAAKpI,MAAO,GAAI,GAQ7B,eACC,MAAMsV,EAAS/c,KAAK+c,OAEpB,OAAKA,EAAO5c,GAAI,oBACR,CAAE4c,GAEFA,EAAOS,aAAc,CAAEJ,aAAa,IAU7C,aAAcshC,GACb,MAAM3hC,EAAS/c,KAAK+c,OAEpB,OAAKA,EAAO5c,GAAI,WACR4c,EAAO6mB,aAAc8a,EAAY,CAAEthC,aAAa,IAGjD,KAYR,cAAeyN,GACd,GAAK7qB,KAAKnD,MAAQguB,EAAShuB,KAC1B,MAAO,GAIR,MAAMgiC,EAAMniB,GAAe1c,KAAK6P,KAAMgb,EAAShb,MAEzC0vC,EAAyB,iBAAP1gB,EAAoBzuB,KAAK0M,IAAK9c,KAAK6P,KAAK9N,OAAQ8oB,EAAShb,KAAK9N,QAAW88B,EAEjG,OAAO7+B,KAAK6P,KAAKpI,MAAO,EAAG83C,GAU5B,kBAAmB10B,GAClB,MAAMtN,EAAavd,KAAKwd,eAClBC,EAAaoN,EAASrN,eAE5B,IAAIjgB,EAAI,EAER,KAAQggB,EAAYhgB,IAAOkgB,EAAYlgB,IAAOggB,EAAYhgB,IACzDA,IAGD,OAAa,IAANA,EAAU,KAAOggB,EAAYhgB,EAAI,GAYzC,aAAckvB,GACb,MAAMC,EAAU1sB,KAAK0rB,QAEfpf,EAASogB,EAAQpgB,OAASmgB,EAGhC,OAFAC,EAAQpgB,OAASA,EAAS,EAAI,EAAIA,EAE3BogB,EAYR,QAASE,GACR,MAA4C,SAArC5sB,KAAK6sB,YAAaD,GAoC1B,SAAUA,GACT,MAA4C,UAArC5sB,KAAK6sB,YAAaD,GAW1B,QAASA,GACR,MAA4C,QAArC5sB,KAAK6sB,YAAaD,GAW1B,WAAYA,GACX,IAAImZ,EAAO,KACP2R,EAAQ,KAGZ,OAFgB13C,KAAK6sB,YAAaD,IAGjC,IAAK,OACJ,OAAO,EAER,IAAK,SACJmZ,EAAO,GAASjb,UAAW9qB,MAC3B03C,EAAQ,GAAS5sB,UAAW8B,GAC5B,MAED,IAAK,QACJmZ,EAAO,GAASjb,UAAW8B,GAC3B8qB,EAAQ,GAAS5sB,UAAW9qB,MAC5B,MAED,QACC,OAAO,EAIT,IAAIw/C,EAAazZ,EAAKhpB,OAEtB,KAAQgpB,EAAKl2B,KAAK9N,OAAS21C,EAAM7nC,KAAK9N,QAAS,CAC9C,GAAKgkC,EAAKzZ,QAASorB,GAClB,OAAO,EAGR,GAAK3R,EAAKl2B,KAAK9N,OAAS21C,EAAM7nC,KAAK9N,OAAS,CAC3C,GAAKgkC,EAAKz5B,SAAWkzC,EAAWtB,UAC/B,OAAO,EAGRnY,EAAKl2B,KAAOk2B,EAAKl2B,KAAKpI,MAAO,GAAI,GACjC+3C,EAAaA,EAAWziC,OACxBgpB,EAAKz5B,aACC,CACN,GAAsB,IAAjBorC,EAAMprC,OACV,OAAO,EAGRorC,EAAM7nC,KAAO6nC,EAAM7nC,KAAKpI,MAAO,GAAI,KAmBtC,GAAIxH,GACH,MAAgB,aAATA,GAAgC,mBAATA,EAW/B,gBAAiB4qB,GAChB,GAAK7qB,KAAKnD,OAASguB,EAAShuB,KAC3B,OAAO,EAMR,MAAyD,QAAlD6f,GAHgB1c,KAAKy/C,gBACN50B,EAAS40B,iBAkBhC,0BAA2BC,GAC1B,IAAI59C,EAEJ,OAAS49C,EAAUz/C,MAClB,IAAK,SACJ6B,EAAS9B,KAAK2/C,iCAAkCD,GAChD,MACD,IAAK,OACL,IAAK,SACL,IAAK,WACJ59C,EAAS9B,KAAK4/C,+BAAgCF,GAC9C,MACD,IAAK,QACJ59C,EAAS9B,KAAK6/C,gCAAiCH,GAC/C,MACD,IAAK,QACJ59C,EAAS9B,KAAK8/C,gCAAiCJ,GAC/C,MACD,QACC59C,EAAS,GAASgpB,UAAW9qB,MAI/B,OAAO8B,EAUR,iCAAkC49C,GACjC,OAAO1/C,KAAK+/C,2BAA4BL,EAAU70B,SAAU60B,EAAUz4B,SAUvE,+BAAgCy4B,GAC/B,OAAO1/C,KAAKggD,sBAAuBN,EAAUO,eAAgBP,EAAUpnB,eAAgBonB,EAAUz4B,SAUlG,gCAAiCy4B,GAChC,MAAMQ,EAAaR,EAAUQ,WAK7B,OAHoBA,EAAWvyB,iBAAkB3tB,OAC9CkgD,EAAWr/B,MAAMyL,QAAStsB,OAA6B,UAAnBA,KAAK6+C,WAGpC7+C,KAAKmgD,aAAcT,EAAUU,cAAeV,EAAUW,oBAExDX,EAAUY,kBACPtgD,KAAKggD,sBAAuBN,EAAUY,kBAAmBZ,EAAUnmB,kBAAmB,GAEtFv5B,KAAK+/C,2BAA4BL,EAAUnmB,kBAAmB,GAYxE,gCAAiCmmB,GAChC,MAAMQ,EAAaR,EAAUQ,WAG7B,IAAIljC,EAeJ,OAjBoBkjC,EAAWvyB,iBAAkB3tB,OAAUkgD,EAAWr/B,MAAMyL,QAAStsB,OAKpFgd,EAAMhd,KAAKmgD,aAAcT,EAAUO,eAAgBP,EAAUpnB,gBAExDonB,EAAUO,eAAepiC,SAAU6hC,EAAUpnB,kBAEjDtb,EAAMA,EAAIujC,0BAA2Bb,EAAUc,iBAAkB,KAGlExjC,EADWhd,KAAKssB,QAASozB,EAAUc,kBAC7B,GAAS11B,UAAW40B,EAAUc,kBAE9BxgD,KAAKggD,sBAAuBN,EAAUc,iBAAkBd,EAAUY,kBAAmB,GAGrFtjC,EAYR,0BAA2ByjC,EAAgBx5B,GAC1C,MAAMy5B,EAAc,GAAS51B,UAAW9qB,MAGxC,GAAKA,KAAKnD,MAAQ4jD,EAAe5jD,KAChC,OAAO6jD,EAGR,GAA8E,QAAzEhkC,GAAe+jC,EAAehB,gBAAiBz/C,KAAKy/C,kBAExD,GAAKgB,EAAen0C,OAAStM,KAAKsM,OAAS,CAE1C,GAAKm0C,EAAen0C,OAAS2a,EAAUjnB,KAAKsM,OAE3C,OAAO,KAGPo0C,EAAYp0C,QAAU2a,QAGlB,GAA8E,UAAzEvK,GAAe+jC,EAAehB,gBAAiBz/C,KAAKy/C,iBAAgC,CAE/F,MAAMliD,EAAIkjD,EAAe5wC,KAAK9N,OAAS,EAEvC,GAAK0+C,EAAen0C,QAAUtM,KAAK6P,KAAMtS,GAAM,CAE9C,GAAKkjD,EAAen0C,OAAS2a,EAAUjnB,KAAK6P,KAAMtS,GAGjD,OAAO,KAGPmjD,EAAY7wC,KAAMtS,IAAO0pB,GAK5B,OAAOy5B,EAWR,2BAA4BC,EAAgB15B,GAC3C,MAAMy5B,EAAc,GAAS51B,UAAW9qB,MAGxC,GAAKA,KAAKnD,MAAQ8jD,EAAe9jD,KAChC,OAAO6jD,EAGR,GAA8E,QAAzEhkC,GAAeikC,EAAelB,gBAAiBz/C,KAAKy/C,kBAEnDkB,EAAer0C,OAAStM,KAAKsM,QAAYq0C,EAAer0C,QAAUtM,KAAKsM,QAA6B,cAAnBtM,KAAK6+C,cAG1F6B,EAAYp0C,QAAU2a,QAEjB,GAA8E,UAAzEvK,GAAeikC,EAAelB,gBAAiBz/C,KAAKy/C,iBAAgC,CAE/F,MAAMliD,EAAIojD,EAAe9wC,KAAK9N,OAAS,EAElC4+C,EAAer0C,QAAUtM,KAAK6P,KAAMtS,KAGxCmjD,EAAY7wC,KAAMtS,IAAO0pB,GAI3B,OAAOy5B,EAYR,sBAAuBT,EAAgB3nB,EAAgBrR,GAItD,GAFAqR,EAAiBA,EAAeioB,0BAA2BN,EAAgBh5B,GAEtEg5B,EAAe3zB,QAASgM,GAE5B,OAAO,GAASxN,UAAW9qB,MAI5B,MAAM0gD,EAAc1gD,KAAKugD,0BAA2BN,EAAgBh5B,GAMpE,OAJgC,OAAhBy5B,GACbT,EAAe3zB,QAAStsB,OAA6B,UAAnBA,KAAK6+C,YACvCoB,EAAe3xB,aAAcrH,GAAUqF,QAAStsB,OAA6B,cAAnBA,KAAK6+C,WAK1D7+C,KAAKmgD,aAAcF,EAAgB3nB,GAKnCooB,EAAYX,2BAA4BznB,EAAgBrR,GA+BjE,aAAcrc,EAAQxJ,GACrB,MAAM7D,EAAIqN,EAAOiF,KAAK9N,OAAS,EAGzB6+C,EAAW,GAAS91B,UAAW1pB,GAYrC,OAXAw/C,EAAS/B,WAAa7+C,KAAK6+C,WAK3B+B,EAASt0C,OAASs0C,EAASt0C,OAAStM,KAAK6P,KAAMtS,GAAMqN,EAAO0B,OAI5Ds0C,EAAS/wC,KAAO,IAAK+wC,EAAS/wC,QAAS7P,KAAK6P,KAAKpI,MAAOlK,EAAI,IAErDqjD,EAMR,SACC,MAAO,CACN/jD,KAAMmD,KAAKnD,KAAKihD,SAChBjuC,KAAM1G,MAAMiK,KAAMpT,KAAK6P,MACvBgvC,WAAY7+C,KAAK6+C,YASnB,QACC,OAAO,IAAI7+C,KAAK0H,YAAa1H,KAAKnD,KAAMmD,KAAK6P,KAAM7P,KAAK6+C,YAuBzD,iBAAkB9xB,EAAgBzgB,EAAQuyC,EAAa,UACtD,GAAK9xB,aAA0B,GAC9B,OAAO,IAAI,GAAUA,EAAelwB,KAAMkwB,EAAeld,KAAMkd,EAAe8xB,YACxE,CACN,MAAMtsC,EAAOwa,EAEb,GAAe,OAAVzgB,EACJA,EAASiG,EAAK2rC,cACR,IAAe,UAAV5xC,EACX,OAAOtM,KAAKmsB,cAAe5Z,EAAMssC,GAC3B,GAAe,SAAVvyC,EACX,OAAOtM,KAAK6rB,aAActZ,EAAMssC,GAC1B,GAAgB,IAAXvyC,IAAiBA,EAO5B,MAAM,IAAI,KAAe,yCAA0C,CAAEtM,KAAM+sB,IAG5E,IAAMxa,EAAKpS,GAAI,aAAgBoS,EAAKpS,GAAI,oBAMvC,MAAM,IAAI,KACT,kCACA,CAAEH,KAAM+sB,IAIV,MAAMld,EAAO0C,EAAKoL,UAIlB,OAFA9N,EAAK5M,KAAMqJ,GAEJ,IAAItM,KAAMuS,EAAK1V,KAAMgT,EAAMgvC,IAYpC,oBAAqBx8C,EAAMw8C,GAC1B,IAAMx8C,EAAK0a,OAOV,MAAM,IAAI,KACT,4BACA,CAAE/c,KAAMqC,GACR,CAAExF,KAAMwF,IAIV,OAAOrC,KAAK8qB,UAAWzoB,EAAK0a,OAAQ1a,EAAKkqB,UAAWsyB,GAWrD,qBAAsBx8C,EAAMw8C,GAC3B,IAAMx8C,EAAK0a,OAOV,MAAM,IAAI,KACT,6BACA1a,EACA,CAAExF,KAAMwF,IAIV,OAAOrC,KAAK8qB,UAAWzoB,EAAK0a,OAAQ1a,EAAK+pB,YAAayyB,GAUvD,gBAAiB7gC,EAAMopB,GACtB,GAAmB,eAAdppB,EAAKnhB,KAAwB,CACjC,MAAMmgB,EAAM,IAAI,GAAUoqB,EAAIyZ,UAAW7iC,EAAKnO,MAG9C,OAFAmN,EAAI6hC,WAAa7gC,EAAK6gC,WAEf7hC,EAGR,IAAMoqB,EAAI2V,QAAS/+B,EAAKnhB,MAOvB,MAAM,IAAI,KACT,kCACAuqC,EACA,CAAE7c,SAAUvM,EAAKnhB,OAInB,OAAO,IAAI,GAAUuqC,EAAI2V,QAAS/+B,EAAKnhB,MAAQmhB,EAAKnO,KAAMmO,EAAK6gC,aAmE1D,SAASI,GAAuBp0B,EAAU4N,GAChD,MAAMlmB,EAAOkmB,EAAevb,SAAUub,EAAe+lB,cAAe3zB,EAASve,SAE7E,OAAKiG,GAAQA,EAAKpS,GAAI,UAAaoS,EAAK6Z,YAAcvB,EAASve,OACvDiG,EAGD,KA4BD,SAAS2sC,GAAsBr0B,EAAU4N,EAAgBta,GAC/D,OAAkB,OAAbA,EACG,KAGDsa,EAAevb,SAAUub,EAAe+lB,cAAe3zB,EAASve,SAmBjE,SAAS+yC,GAAuBx0B,EAAU4N,EAAgBta,GAChE,OAAkB,OAAbA,EACG,KAGDsa,EAAevb,SAAUub,EAAe+lB,cAAe3zB,EAASve,QAAW,GCnnCpE,MAAM,GAOpB,YAAauU,EAAOC,EAAM,MAOzB9gB,KAAK6gB,MAAQ,GAASiK,UAAWjK,GAQjC7gB,KAAK8gB,IAAMA,EAAM,GAASgK,UAAWhK,GAAQ,GAASgK,UAAWjK,GAIjE7gB,KAAK6gB,MAAMg+B,WAAa7+C,KAAKytB,YAAc,SAAW,SACtDztB,KAAK8gB,IAAI+9B,WAAa7+C,KAAKytB,YAAc,SAAW,aAiBrD,EAAInvB,OAAOiW,kBACH,IAAI,GAAY,CAAEmW,WAAY1qB,KAAMirB,kBAAkB,IAS9D,kBACC,OAAOjrB,KAAK6gB,MAAMyL,QAAStsB,KAAK8gB,KASjC,aAIC,MAA0D,QAAnDpE,GAHiB1c,KAAK6gB,MAAM4+B,gBACbz/C,KAAK8gB,IAAI2+B,iBAUhC,WACC,OAAOz/C,KAAK6gB,MAAMhkB,KAUnB,iBAAkBguB,GACjB,OAAOA,EAASqC,QAASltB,KAAK6gB,QAAWgK,EAAShN,SAAU7d,KAAK8gB,KAYlE,cAAeyM,EAAYC,GAAQ,GAC7BD,EAAWE,cACfD,GAAQ,GAGT,MAAME,EAAgB1tB,KAAK2tB,iBAAkBJ,EAAW1M,QAAa2M,GAASxtB,KAAK6gB,MAAMyL,QAASiB,EAAW1M,OACvG+M,EAAc5tB,KAAK2tB,iBAAkBJ,EAAWzM,MAAW0M,GAASxtB,KAAK8gB,IAAIwL,QAASiB,EAAWzM,KAEvG,OAAO4M,GAAiBE,EAQzB,aAAcvrB,GACb,MAAM2a,EAAM,GAASmP,cAAe9pB,GAEpC,OAAOrC,KAAK2tB,iBAAkB3Q,IAAShd,KAAK6gB,MAAMyL,QAAStP,GAiB5D,GAAI/c,GACH,MAAgB,UAATA,GAA6B,gBAATA,EAS5B,QAASstB,GACR,OAAOvtB,KAAK6gB,MAAMyL,QAASiB,EAAW1M,QAAW7gB,KAAK8gB,IAAIwL,QAASiB,EAAWzM,KAS/E,eAAgByM,GACf,OAAOvtB,KAAK6gB,MAAMhD,SAAU0P,EAAWzM,MAAS9gB,KAAK8gB,IAAIoM,QAASK,EAAW1M,OA4B9E,cAAe0M,GACd,MAAMM,EAAS,GAqBf,OAnBK7tB,KAAK8tB,eAAgBP,IAGpBvtB,KAAK2tB,iBAAkBJ,EAAW1M,QAGtCgN,EAAO5qB,KAAM,IAAI,GAAOjD,KAAK6gB,MAAO0M,EAAW1M,QAG3C7gB,KAAK2tB,iBAAkBJ,EAAWzM,MAGtC+M,EAAO5qB,KAAM,IAAI,GAAOsqB,EAAWzM,IAAK9gB,KAAK8gB,OAI9C+M,EAAO5qB,KAAM,IAAI,GAAOjD,KAAK6gB,MAAO7gB,KAAK8gB,MAGnC+M,EAsBR,gBAAiBN,GAChB,GAAKvtB,KAAK8tB,eAAgBP,GAAe,CAGxC,IAAIQ,EAAmB/tB,KAAK6gB,MACxBmN,EAAiBhuB,KAAK8gB,IAc1B,OAZK9gB,KAAK2tB,iBAAkBJ,EAAW1M,SAGtCkN,EAAmBR,EAAW1M,OAG1B7gB,KAAK2tB,iBAAkBJ,EAAWzM,OAGtCkN,EAAiBT,EAAWzM,KAGtB,IAAI,GAAOiN,EAAkBC,GAIrC,OAAO,KA+BR,UAAWT,EAAYC,GAAQ,GAC9B,IAAIszB,EAAa9gD,KAAK8tB,eAAgBP,GAUtC,GARMuzB,IAEJA,EADI9gD,KAAK6gB,MAAMhD,SAAU0P,EAAW1M,OACvB2M,EAAQxtB,KAAK8gB,IAAIigC,WAAYxzB,EAAW1M,OAAU7gB,KAAK8gB,IAAIwL,QAASiB,EAAW1M,OAE/E2M,EAAQD,EAAWzM,IAAIigC,WAAY/gD,KAAK6gB,OAAU0M,EAAWzM,IAAIwL,QAAStsB,KAAK6gB,SAIxFigC,EACL,OAAO,KAGR,IAAIn2B,EAAgB3qB,KAAK6gB,MACrB4Y,EAAcz5B,KAAK8gB,IAUvB,OARKyM,EAAW1M,MAAMhD,SAAU8M,KAC/BA,EAAgB4C,EAAW1M,OAGvB0M,EAAWzM,IAAIoM,QAASuM,KAC5BA,EAAclM,EAAWzM,KAGnB,IAAI,GAAO6J,EAAe8O,GA0ClC,uBACC,MAAM5L,EAAS,GACT0xB,EAASv/C,KAAK6gB,MAAMmgC,cAAehhD,KAAK8gB,KAAM/e,OAE9Cib,EAAM,GAAS8N,UAAW9qB,KAAK6gB,OACrC,IAAIogC,EAAYjkC,EAAID,OAGpB,KAAQC,EAAInN,KAAK9N,OAASw9C,EAAS,GAAI,CACtC,MAAMt4B,EAAUg6B,EAAU/C,UAAYlhC,EAAI1Q,OAEzB,IAAZ2a,GACJ4G,EAAO5qB,KAAM,IAAI,GAAO+Z,EAAKA,EAAIsR,aAAcrH,KAGhDjK,EAAInN,KAAOmN,EAAInN,KAAKpI,MAAO,GAAI,GAC/BuV,EAAI1Q,SACJ20C,EAAYA,EAAUlkC,OAIvB,KAAQC,EAAInN,KAAK9N,QAAU/B,KAAK8gB,IAAIjR,KAAK9N,QAAS,CACjD,MAAMuK,EAAStM,KAAK8gB,IAAIjR,KAAMmN,EAAInN,KAAK9N,OAAS,GAC1CklB,EAAU3a,EAAS0Q,EAAI1Q,OAEZ,IAAZ2a,GACJ4G,EAAO5qB,KAAM,IAAI,GAAO+Z,EAAKA,EAAIsR,aAAcrH,KAGhDjK,EAAI1Q,OAASA,EACb0Q,EAAInN,KAAK5M,KAAM,GAGhB,OAAO4qB,EAsBR,UAAW3rB,EAAU,IAGpB,OAFAA,EAAQwoB,WAAa1qB,KAEd,IAAI,GAAYkC,GAiBxB,UAAYA,EAAU,IACrBA,EAAQwoB,WAAa1qB,KACrBkC,EAAQ+oB,kBAAmB,EAE3B,MAAM0B,EAAa,IAAI,GAAYzqB,GAEnC,IAAM,MAAM1D,KAASmuB,QACdnuB,EAAM6D,KAiBd,cAAgBH,EAAU,IACzBA,EAAQwoB,WAAa1qB,KAErB,MAAM2sB,EAAa,IAAI,GAAYzqB,SAE7ByqB,EAAW9B,SAEjB,IAAM,MAAMrsB,KAASmuB,QACdnuB,EAAM6tB,aAcd,0BAA2BqzB,GAC1B,OAASA,EAAUz/C,MAClB,IAAK,SACJ,OAAOD,KAAK2/C,iCAAkCD,GAC/C,IAAK,OACL,IAAK,SACL,IAAK,WACJ,OAAO1/C,KAAK4/C,+BAAgCF,GAC7C,IAAK,QACJ,MAAO,CAAE1/C,KAAK6/C,gCAAiCH,IAChD,IAAK,QACJ,MAAO,CAAE1/C,KAAK8/C,gCAAiCJ,IAGjD,MAAO,CAAE,IAAI,GAAO1/C,KAAK6gB,MAAO7gB,KAAK8gB,MAUtC,2BAA4BogC,GAC3B,MAAMrzB,EAAS,CAAE,IAAI,GAAO7tB,KAAK6gB,MAAO7gB,KAAK8gB,MAE7C,IAAM,MAAM4+B,KAAawB,EACxB,IAAM,IAAI3jD,EAAI,EAAGA,EAAIswB,EAAO9rB,OAAQxE,IAAM,CACzC,MAAMuE,EAAS+rB,EAAQtwB,GAAI4jD,0BAA2BzB,GAEtD7xB,EAAO/nB,OAAQvI,EAAG,KAAMuE,GACxBvE,GAAKuE,EAAOC,OAAS,EAQvB,IAAM,IAAIxE,EAAI,EAAGA,EAAIswB,EAAO9rB,OAAQxE,IAAM,CACzC,MAAM0xB,EAAQpB,EAAQtwB,GAEtB,IAAM,IAAI6jD,EAAI7jD,EAAI,EAAG6jD,EAAIvzB,EAAO9rB,OAAQq/C,IAAM,CAC7C,MAAM71B,EAAOsC,EAAQuzB,IAEhBnyB,EAAMoyB,cAAe91B,IAAUA,EAAK81B,cAAepyB,IAAWA,EAAM3C,QAASf,KACjFsC,EAAO/nB,OAAQs7C,EAAG,IAKrB,OAAOvzB,EASR,oBACC,OAAO7tB,KAAK6gB,MAAMoN,kBAAmBjuB,KAAK8gB,KAU3C,sBACC,GAAK9gB,KAAKytB,YACT,OAAO,KAGR,MAAMN,EAAiBntB,KAAK6gB,MAAMuM,UAC5BC,EAAgBrtB,KAAK8gB,IAAIwM,WAE/B,OAAKH,GAAkBA,EAAehtB,GAAI,YAAegtB,IAAmBE,EACpEF,EAGD,KAQR,SACC,MAAO,CACNtM,MAAO7gB,KAAK6gB,MAAMi9B,SAClBh9B,IAAK9gB,KAAK8gB,IAAIg9B,UAShB,QACC,OAAO,IAAI99C,KAAK0H,YAAa1H,KAAK6gB,MAAO7gB,KAAK8gB,KAY/C,iCAAkC4+B,EAAW4B,GAAS,GACrD,OAAOthD,KAAK+/C,2BAA4BL,EAAU70B,SAAU60B,EAAUz4B,QAASq6B,GAYhF,+BAAgC5B,EAAW4B,GAAS,GACnD,MAAMrB,EAAiBP,EAAUO,eAC3Bh5B,EAAUy4B,EAAUz4B,QACpBqR,EAAiBonB,EAAUpnB,eAEjC,OAAOt4B,KAAKggD,sBAAuBC,EAAgB3nB,EAAgBrR,EAASq6B,GAY7E,gCAAiC5B,GAChC,MAAM7+B,EAAQ7gB,KAAK6gB,MAAMg/B,gCAAiCH,GAC1D,IAAI5+B,EAAM9gB,KAAK8gB,IAAI++B,gCAAiCH,GAapD,OAXK1/C,KAAK8gB,IAAIwL,QAASozB,EAAUnmB,qBAChCzY,EAAM9gB,KAAK8gB,IAAIwN,aAAc,IAIzBzN,EAAMhkB,MAAQikB,EAAIjkB,OAGtBikB,EAAM9gB,KAAK8gB,IAAIwN,cAAe,IAGxB,IAAI,GAAOzN,EAAOC,GAY1B,gCAAiC4+B,GAYhC,GAAK1/C,KAAK6gB,MAAMyL,QAASozB,EAAUpnB,iBAAoBt4B,KAAK8gB,IAAIwL,QAASozB,EAAUc,kBAClF,OAAO,IAAI,GAAOxgD,KAAK6gB,OAGxB,IAAIA,EAAQ7gB,KAAK6gB,MAAMi/B,gCAAiCJ,GACpD5+B,EAAM9gB,KAAK8gB,IAAIg/B,gCAAiCJ,GASpD,OAPK7+B,EAAMhkB,MAAQikB,EAAIjkB,OAItBikB,EAAM9gB,KAAK8gB,IAAIwN,cAAe,IAG1BzN,EAAMqM,QAASpM,IA2Bd4+B,EAAUO,eAAepiC,SAAU6hC,EAAUpnB,iBAEjDzX,EAAQ,GAASiK,UAAWhK,GAC5BD,EAAMvU,OAAS,IAETozC,EAAUc,iBAAiBl0B,QAASzL,KAEzCC,EAAM4+B,EAAUc,kBAIjB3/B,EAAQ6+B,EAAUpnB,gBAGZ,IAAI,GAAOzX,EAAOC,IAGnB,IAAI,GAAOD,EAAOC,GAiC1B,2BAA4B6/B,EAAgB15B,EAASq6B,GAAS,GAC7D,GAAKA,GAAUthD,KAAK2tB,iBAAkBgzB,GAKrC,MAAO,CACN,IAAI,GAAO3gD,KAAK6gB,MAAO8/B,GACvB,IAAI,GACHA,EAAeryB,aAAcrH,GAC7BjnB,KAAK8gB,IAAIi/B,2BAA4BY,EAAgB15B,KAGjD,CACN,MAAMgI,EAAQ,IAAI,GAAOjvB,KAAK6gB,MAAO7gB,KAAK8gB,KAK1C,OAHAmO,EAAMpO,MAAQoO,EAAMpO,MAAMk/B,2BAA4BY,EAAgB15B,GACtEgI,EAAMnO,IAAMmO,EAAMnO,IAAIi/B,2BAA4BY,EAAgB15B,GAE3D,CAAEgI,IAeX,sBAAuBgxB,EAAgB3nB,EAAgBrR,EAASq6B,GAAS,GAExE,GAAKthD,KAAKytB,YAAc,CACvB,MAAM8zB,EAASvhD,KAAK6gB,MAAMm/B,sBAAuBC,EAAgB3nB,EAAgBrR,GAEjF,MAAO,CAAE,IAAI,GAAOs6B,IAerB,MAAMC,EAAY,GAAM/yB,4BAA6BwxB,EAAgBh5B,GAC/D05B,EAAiBroB,EAAeioB,0BAA2BN,EAAgBh5B,GAEjF,GAAKjnB,KAAK2tB,iBAAkB2K,KAAqBgpB,IAC3CE,EAAU7zB,iBAAkB3tB,KAAK6gB,QAAW2gC,EAAU7zB,iBAAkB3tB,KAAK8gB,MAAQ,CACzF,MAAMD,EAAQ7gB,KAAK6gB,MAAMm/B,sBAAuBC,EAAgB3nB,EAAgBrR,GAC1EnG,EAAM9gB,KAAK8gB,IAAIk/B,sBAAuBC,EAAgB3nB,EAAgBrR,GAE5E,MAAO,CAAE,IAAI,GAAOpG,EAAOC,IAK7B,IAAIhf,EAEJ,MAAM2/C,EAAgBzhD,KAAK0hD,cAAeF,GAC1C,IAAIG,EAAa,KAEjB,MAAMC,EAAS5hD,KAAK64C,gBAAiB2I,GAsBrC,GApB6B,GAAxBC,EAAc1/C,OAElB4/C,EAAa,IAAI,GAChBF,EAAe,GAAI5gC,MAAM0/B,0BAA2BN,EAAgBh5B,GACpEw6B,EAAe,GAAI3gC,IAAIy/B,0BAA2BN,EAAgBh5B,IAEhC,GAAxBw6B,EAAc1/C,SAEzB4/C,EAAa,IAAI,GAChB3hD,KAAK6gB,MACL7gB,KAAK8gB,IAAIy/B,0BAA2BN,EAAgBh5B,KAKrDnlB,EADI6/C,EACKA,EAAW5B,2BAA4BY,EAAgB15B,EAAoB,OAAX26B,GAAmBN,GAEnF,GAGLM,EAAS,CACb,MAAMC,EAAoB,IAAI,GAC7BD,EAAO/gC,MAAMs/B,aAAcqB,EAAU3gC,MAAO8/B,GAC5CiB,EAAO9gC,IAAIq/B,aAAcqB,EAAU3gC,MAAO8/B,IAGrB,GAAjB7+C,EAAOC,OACXD,EAAOgE,OAAQ,EAAG,EAAG+7C,GAErB//C,EAAOmB,KAAM4+C,GAIf,OAAO//C,EAeR,0BAA2B2+C,EAAgBx5B,GAC1C,IAAI66B,EAAW9hD,KAAK6gB,MAAM0/B,0BAA2BE,EAAgBx5B,GACjE86B,EAAS/hD,KAAK8gB,IAAIy/B,0BAA2BE,EAAgBx5B,GAEjE,OAAiB,MAAZ66B,GAA8B,MAAVC,EACjB,MAGS,MAAZD,IACJA,EAAWrB,GAGG,MAAVsB,IACJA,EAAStB,GAGH,IAAI,GAAOqB,EAAUC,IAY7B,mCAAoCl3B,EAAU4B,GAC7C,MAAM5L,EAAQgK,EACR/J,EAAM+J,EAASyD,aAAc7B,GAEnC,OAAOA,EAAQ,EAAI,IAAIzsB,KAAM6gB,EAAOC,GAAQ,IAAI9gB,KAAM8gB,EAAKD,GAW5D,iBAAkBjC,GACjB,OAAO,IAAI5e,KAAM,GAAS8qB,UAAWlM,EAAS,GAAK,GAASkM,UAAWlM,EAASA,EAAQs/B,YAUzF,iBAAkB77C,GACjB,OAAOrC,KAAKyuB,4BAA6B,GAAStC,cAAe9pB,GAAQA,EAAKmsB,YAkB/E,yBAA0BX,GACzB,GAAuB,IAAlBA,EAAO9rB,OAOX,MAAM,IAAI,KACT,uCACA,MAEK,GAAsB,GAAjB8rB,EAAO9rB,OAClB,OAAO8rB,EAAQ,GAAInC,QAMpB,MAAMs2B,EAAMn0B,EAAQ,GAGpBA,EAAO3J,KAAM,CAAEvH,EAAGC,IACVD,EAAEkE,MAAMqM,QAAStQ,EAAEiE,OAAU,GAAK,GAI1C,MAAMohC,EAAWp0B,EAAO/a,QAASkvC,GAK3BlgD,EAAS,IAAI9B,KAAMgiD,EAAInhC,MAAOmhC,EAAIlhC,KAIxC,GAAKmhC,EAAW,EACf,IAAM,IAAI1kD,EAAI0kD,EAAW,EACnBp0B,EAAQtwB,GAAIujB,IAAIwL,QAASxqB,EAAO+e,OADJtjB,IAEhCuE,EAAO+e,MAAQ,GAASiK,UAAW+C,EAAQtwB,GAAIsjB,OAUlD,IAAM,IAAItjB,EAAI0kD,EAAW,EAAG1kD,EAAIswB,EAAO9rB,QACjC8rB,EAAQtwB,GAAIsjB,MAAMyL,QAASxqB,EAAOgf,KADOvjB,IAE7CuE,EAAOgf,IAAM,GAASgK,UAAW+C,EAAQtwB,GAAIujB,KAO/C,OAAOhf,EAUR,gBAAiBkc,EAAMopB,GACtB,OAAO,IAAIpnC,KAAM,GAAS4+C,SAAU5gC,EAAK6C,MAAOumB,GAAO,GAASwX,SAAU5gC,EAAK8C,IAAKsmB,KCt+BvE,MAAM,GAIpB,cAOCpnC,KAAKkiD,oBAAsB,IAAI5sC,QAQ/BtV,KAAKmiD,oBAAsB,IAAI7sC,QAS/BtV,KAAKoiD,4BAA8B,IAAItuC,IAWvC9T,KAAKqiD,sBAAwB,IAAIvuC,IAUjC9T,KAAKsiD,sBAAwB,IAAIxuC,IASjC9T,KAAKuiD,oBAAsB,IAAIlqC,IAG/BrY,KAAKkpB,GAAI,sBAAuB,CAAEpS,EAAKnX,KACtC,GAAKA,EAAK62B,aACT,OAGD,MAAMgsB,EAAgBxiD,KAAKkiD,oBAAoB9jD,IAAKuB,EAAK8iD,cAAc1lC,QAEvEpd,EAAK62B,aAAex2B,KAAK0iD,eAAgBF,EAAe7iD,EAAK8iD,cAAcn2C,SACzE,CAAEmE,SAAU,QAGfzQ,KAAKkpB,GAAI,sBAAuB,CAAEpS,EAAKnX,KACtC,GAAKA,EAAK8iD,cACT,OAGD,MAAME,EAAY3iD,KAAK4iD,uBAAwBjjD,EAAK62B,cAC9CqsB,EAAc7iD,KAAKmiD,oBAAoB/jD,IAAKukD,GAC5CG,EAAc9iD,KAAK+iD,eAAgBpjD,EAAK62B,aAAazZ,OAAQpd,EAAK62B,aAAalqB,OAAQq2C,GAE7FhjD,EAAK8iD,cAAgB,GAAc33B,UAAW+3B,EAAaC,IACzD,CAAEryC,SAAU,QAYhB,aAAcuyC,EAAcloB,GAC3B96B,KAAKkiD,oBAAoBz4C,IAAKu5C,EAAcloB,GAC5C96B,KAAKmiD,oBAAoB14C,IAAKqxB,EAAakoB,GAc5C,kBAAmBloB,GAClB,MAAMkoB,EAAehjD,KAAKijD,eAAgBnoB,GAI1C,GAFA96B,KAAKmiD,oBAAoBpuC,OAAQ+mB,GAE5B96B,KAAKsiD,sBAAsB54C,IAAKoxB,GACpC,IAAM,MAAMooB,KAAcljD,KAAKsiD,sBAAsBlkD,IAAK08B,GACzD96B,KAAKuiD,oBAAoB3zC,IAAKs0C,GAI3BljD,KAAKkiD,oBAAoB9jD,IAAK4kD,IAAkBloB,GACpD96B,KAAKkiD,oBAAoBnuC,OAAQivC,GAenC,mBAAoBA,GACnB,MAAMloB,EAAc96B,KAAKmjD,cAAeH,GAExChjD,KAAKkiD,oBAAoBnuC,OAAQivC,GAE5BhjD,KAAKmiD,oBAAoB/jD,IAAK08B,IAAiBkoB,GACnDhjD,KAAKmiD,oBAAoBpuC,OAAQ+mB,GAWnC,oBAAqBlc,EAAS9gB,GAC7B,MAAMslD,EAAWpjD,KAAKqiD,sBAAsBjkD,IAAKN,IAAU,IAAIua,IAC/D+qC,EAASx0C,IAAKgQ,GAEd,MAAMnC,EAAQzc,KAAKsiD,sBAAsBlkD,IAAKwgB,IAAa,IAAIvG,IAC/DoE,EAAM7N,IAAK9Q,GAEXkC,KAAKqiD,sBAAsB54C,IAAK3L,EAAMslD,GACtCpjD,KAAKsiD,sBAAsB74C,IAAKmV,EAASnC,GAS1C,4BAA6BmC,EAAS9gB,GACrC,MAAMulD,EAAiBrjD,KAAKqiD,sBAAsBjkD,IAAKN,GAElDulD,IACJA,EAAetvC,OAAQ6K,GAEK,GAAvBykC,EAAer6C,MACnBhJ,KAAKqiD,sBAAsBtuC,OAAQjW,IAIrC,MAAMwlD,EAAiBtjD,KAAKsiD,sBAAsBlkD,IAAKwgB,GAElD0kC,IACJA,EAAevvC,OAAQjW,GAEK,GAAvBwlD,EAAet6C,MACnBhJ,KAAKsiD,sBAAsBvuC,OAAQ6K,IAWtC,0BACC,MAAM2kC,EAAcp6C,MAAMiK,KAAMpT,KAAKuiD,qBAIrC,OAFAviD,KAAKuiD,oBAAoBh5C,QAElBg6C,EAMR,gBACCvjD,KAAKkiD,oBAAsB,IAAI5sC,QAC/BtV,KAAKmiD,oBAAsB,IAAI7sC,QAC/BtV,KAAKqiD,sBAAwB,IAAIvuC,IACjC9T,KAAKsiD,sBAAwB,IAAIxuC,IACjC9T,KAAKuiD,oBAAsB,IAAIlqC,IAWhC,eAAgByiB,GACf,OAAO96B,KAAKmiD,oBAAoB/jD,IAAK08B,GAStC,cAAekoB,GACd,OAAOhjD,KAAKkiD,oBAAoB9jD,IAAK4kD,GAStC,aAAczZ,GACb,OAAO,IAAI,GAAYvpC,KAAKwjD,gBAAiBja,EAAU1oB,OAAS7gB,KAAKwjD,gBAAiBja,EAAUzoB,MASjG,YAAa2iC,GACZ,OAAO,IAAI,GAAWzjD,KAAK0jD,eAAgBD,EAAW5iC,OAAS7gB,KAAK0jD,eAAgBD,EAAW3iC,MAUhG,gBAAiB0V,GAChB,MAAM72B,EAAO,CACZ62B,eACAmtB,OAAQ3jD,MAKT,OAFAA,KAAKqU,KAAM,sBAAuB1U,GAE3BA,EAAK8iD,cAab,eAAgBA,EAAevgD,EAAU,CAAE0hD,WAAW,IACrD,MAAMjkD,EAAO,CACZ8iD,gBACAkB,OAAQ3jD,KACR4jD,UAAW1hD,EAAQ0hD,WAKpB,OAFA5jD,KAAKqU,KAAM,sBAAuB1U,GAE3BA,EAAK62B,aAUb,qBAAsB14B,GACrB,MAAM+lD,EAAgB7jD,KAAKqiD,sBAAsBjkD,IAAKN,GAEtD,IAAM+lD,EACL,OAAO,KAGR,MAAMT,EAAW,IAAI/qC,IAErB,IAAM,MAAMuG,KAAWilC,EACtB,GAAKjlC,EAAQze,GAAI,oBAChB,IAAM,MAAMurB,KAAS9M,EAAQklC,wBAC5BV,EAASx0C,IAAK8c,QAGf03B,EAASx0C,IAAKgQ,GAIhB,OAAOwkC,EAgCR,0BAA2BW,EAAiBC,GAC3ChkD,KAAKoiD,4BAA4B34C,IAAKs6C,EAAiBC,GAUxD,uBAAwBxtB,GACvB,IAAIzZ,EAASyZ,EAAazZ,OAE1B,MAAS/c,KAAKmiD,oBAAoBz4C,IAAKqT,IACtCA,EAASA,EAAOA,OAGjB,OAAOA,EAqBR,eAAgB6sB,EAAYqa,EAAYtB,GACvC,GAAKA,GAAa/Y,EAAa,CAK9B,OAH4B5pC,KAAK+iD,eAAgBnZ,EAAW7sB,OAAQ6sB,EAAWlnC,MAAOigD,GAC/D3iD,KAAK+iD,eAAgBnZ,EAAYqa,EAAYra,GAQrE,GAAKA,EAAWzpC,GAAI,SACnB,OAAO8jD,EAIR,IAAInB,EAAc,EAElB,IAAM,IAAIvlD,EAAI,EAAGA,EAAI0mD,EAAY1mD,IAChCulD,GAAe9iD,KAAKkkD,eAAgBta,EAAW1sB,SAAU3f,IAG1D,OAAOulD,EAyBR,eAAgBvd,GACf,GAAKvlC,KAAKoiD,4BAA4BhkD,IAAKmnC,EAASznC,MAAS,CAG5D,OAFiBkC,KAAKoiD,4BAA4BhkD,IAAKmnC,EAASznC,KAEzDoT,CAAUq0B,GACX,GAAKvlC,KAAKmiD,oBAAoBz4C,IAAK67B,GACzC,OAAO,EACD,GAAKA,EAASplC,GAAI,SACxB,OAAOolC,EAAS5lC,KAAKoC,OACf,GAAKwjC,EAASplC,GAAI,aACxB,OAAO,EACD,CACN,IAAIgkD,EAAM,EAEV,IAAM,MAAM19B,KAAS8e,EAAS7e,cAC7By9B,GAAOnkD,KAAKkkD,eAAgBz9B,GAG7B,OAAO09B,GA4BT,eAAgBva,EAAYwa,GAE3B,IAAI7e,EAEA8e,EAAa,EAEbvB,EAAc,EACdmB,EAAa,EAGjB,GAAKra,EAAWzpC,GAAI,SACnB,OAAO,IAAI,GAAcypC,EAAYwa,GAMtC,KAAQtB,EAAcsB,GACrB7e,EAAWqE,EAAW1sB,SAAU+mC,GAChCI,EAAarkD,KAAKkkD,eAAgB3e,GAClCud,GAAeuB,EACfJ,IAID,OAAKnB,GAAesB,EACZpkD,KAAKskD,4BAA6B,IAAI,GAAc1a,EAAYqa,IAMhEjkD,KAAK0iD,eAAgBnd,EAAU6e,GAAmBtB,EAAcuB,IAgBzE,4BAA6B7tB,GAG5B,MAAMlJ,EAAakJ,EAAalJ,WAC1BF,EAAYoJ,EAAapJ,UAE/B,OAAKE,aAAsB,GACnB,IAAI,GAAcA,EAAYA,EAAW3tB,KAAKoC,QAC1CqrB,aAAqB,GACzB,IAAI,GAAcA,EAAW,GAI9BoJ,GAwGThiB,GAAK,GAAQ,IC7lBE,MAAM,GAIpB,cAOCxU,KAAKukD,YAAc,IAAIzwC,IAavB9T,KAAKwkD,mBAAqB,IAAI1wC,IAiB/B,IAAKzR,EAAMpC,GACVA,EAAOwkD,GAA0BxkD,GAE5BoC,aAAgB,KACpBA,EAAOrC,KAAK0kD,uBAAwBriD,IAG/BrC,KAAKukD,YAAY76C,IAAKrH,IAC3BrC,KAAKukD,YAAY96C,IAAKpH,EAAM,IAAIyR,KAGjC9T,KAAKukD,YAAYnmD,IAAKiE,GAAOoH,IAAKxJ,GAAM,GAkBzC,QAASoC,EAAMpC,GAOd,OANAA,EAAOwkD,GAA0BxkD,GAE5BoC,aAAgB,KACpBA,EAAOrC,KAAK0kD,uBAAwBriD,MAGhCrC,KAAKmK,KAAM9H,EAAMpC,KACrBD,KAAKukD,YAAYnmD,IAAKiE,GAAOoH,IAAKxJ,GAAM,IAEjC,GAsBT,KAAMoC,EAAMpC,GACXA,EAAOwkD,GAA0BxkD,GAE5BoC,aAAgB,KACpBA,EAAOrC,KAAK0kD,uBAAwBriD,IAGrC,MAAMsiD,EAAkB3kD,KAAKukD,YAAYnmD,IAAKiE,GAE9C,QAAyBiE,IAApBq+C,EACJ,OAAO,KAGR,MAAMnmD,EAAQmmD,EAAgBvmD,IAAK6B,GAEnC,YAAeqG,IAAV9H,EACG,KAGDA,EAkBR,OAAQ6D,EAAMpC,GACbA,EAAOwkD,GAA0BxkD,GAE5BoC,aAAgB,KACpBA,EAAOrC,KAAK0kD,uBAAwBriD,IAGrC,MAAM8H,EAAOnK,KAAKmK,KAAM9H,EAAMpC,GAE9B,OAAc,IAATkK,GACJnK,KAAKukD,YAAYnmD,IAAKiE,GAAOoH,IAAKxJ,GAAM,IAEjC,IACa,IAATkK,GAIL,KAaR,uBAAwB8hB,GACvB,IAAI7f,EAAS,KAEb,MAAMw4C,EAAW5kD,KAAKwkD,mBAAmBpmD,IAAK6tB,EAAUG,aAExD,GAAKw4B,EAAW,CACf,MAAMC,EAASD,EAASxmD,IAAK6tB,EAAUM,WAElCs4B,IACJz4C,EAASy4C,EAAOzmD,IAAK6tB,EAAUlP,SAQjC,OAJM3Q,IACLA,EAASpM,KAAK8kD,uBAAwB74B,EAAUG,YAAaH,EAAUM,UAAWN,EAAUlP,SAGtF3Q,EAcR,uBAAwByU,EAAOC,EAAK/D,GACnC,MAAM3Q,EAAS9N,OAAQ,mBACvB,IAAIsmD,EAAUC,EAkBd,OAhBAD,EAAW5kD,KAAKwkD,mBAAmBpmD,IAAKyiB,GAElC+jC,IACLA,EAAW,IAAI9wC,IACf9T,KAAKwkD,mBAAmB/6C,IAAKoX,EAAO+jC,IAGrCC,EAASD,EAASxmD,IAAK0iB,GAEjB+jC,IACLA,EAAS,IAAI/wC,IACb8wC,EAASn7C,IAAKqX,EAAK+jC,IAGpBA,EAAOp7C,IAAKsT,EAAQ3Q,GAEbA,GAUT,SAASq4C,GAA0BxkD,GAClC,MAAMqP,EAAQrP,EAAKsP,MAAO,KAE1B,OAAOD,EAAMvN,OAAS,EAAIuN,EAAO,GAAM,IAAMA,EAAO,GAAMA,EAAO,GCpNnD,MAAM,GAQpB,YAAay1C,GAMZ/kD,KAAK+kD,cAAgB9mD,OAAO4nC,OAAQ,CAAEmf,WAAYhlD,MAAQ+kD,GAQ1D/kD,KAAKilD,2BAA6B,IAAInxC,IAUvC,eAAgBoxC,EAAQC,EAASnzB,GAEhC,IAAM,MAAMorB,KAAU8H,EAAOE,qBAC5BplD,KAAKqlD,oBAAqBjI,EAAOt/C,KAAMs/C,EAAOnuB,MAAO+C,GAGtD,MAAMszB,EAAUtlD,KAAKulD,qCAAsCL,GAG3D,IAAM,MAAM17C,KAAS87C,EACA,WAAf97C,EAAMvJ,KACVD,KAAKwlD,cAAe,GAAM/2B,4BAA6BjlB,EAAMqhB,SAAUrhB,EAAMzH,QAAUiwB,GAC7D,WAAfxoB,EAAMvJ,KACjBD,KAAKylD,cAAej8C,EAAMqhB,SAAUrhB,EAAMzH,OAAQyH,EAAM1L,KAAMk0B,GACpC,cAAfxoB,EAAMvJ,KACjBD,KAAK0lD,iBAAkBl8C,EAAMoV,QAASoT,GAGtChyB,KAAK2lD,iBAAkBn8C,EAAMylB,MAAOzlB,EAAMo8C,aAAcp8C,EAAMq8C,kBAAmBr8C,EAAMs8C,kBAAmB9zB,GAI5G,IAAM,MAAMkxB,KAAcljD,KAAK+kD,cAAcpB,OAAOoC,0BAA4B,CAC/E,MAAMC,EAAcb,EAAQ/mD,IAAK8kD,GAAa+C,WAE9CjmD,KAAKqlD,oBAAqBnC,EAAY8C,EAAah0B,GACnDhyB,KAAKkmD,iBAAkBhD,EAAY8C,EAAah0B,GAIjD,IAAM,MAAMorB,KAAU8H,EAAOiB,kBAC5BnmD,KAAKkmD,iBAAkB9I,EAAOt/C,KAAMs/C,EAAOnuB,MAAO+C,GAepD,cAAe/C,EAAO+C,GACrBhyB,KAAK+kD,cAAc/yB,OAASA,EAG5BhyB,KAAK+kD,cAAcqB,WAAapmD,KAAKqmD,wBAAyBp3B,GAG9D,IAAM,MAAMtvB,KAAQwJ,MAAMiK,KAAM6b,GAAQ5kB,IAAKi8C,IAC5CtmD,KAAKumD,6BAA8B5mD,GAGpCK,KAAKwmD,sBAWN,cAAe37B,EAAU9oB,EAAQjE,EAAMk0B,GACtChyB,KAAK+kD,cAAc/yB,OAASA,EAE5BhyB,KAAKqU,KAAM,UAAYvW,EAAM,CAAE+sB,WAAU9oB,UAAU/B,KAAK+kD,eAExD/kD,KAAKwmD,sBAeN,iBAAkBv3B,EAAOnwB,EAAK+oB,EAAU7c,EAAUgnB,GACjDhyB,KAAK+kD,cAAc/yB,OAASA,EAG5BhyB,KAAK+kD,cAAcqB,WAAapmD,KAAKymD,0BAA2Bx3B,EAAO,aAAcnwB,GAGrF,IAAM,MAAMN,KAASywB,EAAQ,CAC5B,MAEMtvB,EAAO,CACZ0C,KAHY7D,EAAM6D,KAIlB4sB,MAHiB,GAAMR,4BAA6BjwB,EAAMmtB,iBAAkBntB,EAAMuD,QAIlF6jD,aAAc9mD,EACd+mD,kBAAmBh+B,EACnBi+B,kBAAmB96C,GAGpBhL,KAAK0mD,aAAc,aAAc5nD,EAAQa,GAG1CK,KAAKwmD,sBAoBN,iBAAkB5nC,EAASoT,GAC1B,MAAM20B,EAAe,GAAM91B,UAAWjS,GAEtC5e,KAAK+kD,cAAc/yB,OAASA,EAG5BhyB,KAAK+kD,cAAcqB,WAAapmD,KAAKqmD,wBAAyBM,GAE9D,MAAMhD,EAAS3jD,KAAK+kD,cAAcpB,OAC5BiD,EAAcjD,EAAOR,cAAevkC,GAG1CoT,EAAO7tB,OAAQyiD,GAGf5mD,KAAKumD,6BAA8B,CAClClkD,KAAMuc,EACNqQ,MAAO03B,IAGR,MAAME,EAAuBlD,EAAOR,cAAevkC,GAGnD,IAAM,MAAMpgB,KAAS,GAAMoyB,UAAWhS,GAAY,CACjD,MAAM,KAAEvc,GAAS7D,EAEXk3B,EAAOoxB,GAA0BzkD,EAAMshD,GAGxCjuB,EAGCA,EAAK74B,OAASgqD,EAAqBhqD,MACvCm1B,EAAOuG,KACNvG,EAAO+0B,cAAerxB,GACtBiuB,EAAOD,eAAgB,GAASv3B,cAAe9pB,KAMjDrC,KAAKumD,6BAA8BD,GAAwB9nD,IAK7DmlD,EAAOqD,kBAAmBJ,GAE1B5mD,KAAKwmD,sBAeN,iBAAkBp8B,EAAW+6B,EAASnzB,GACrC,MAAMi1B,EAAqB99C,MAAMiK,KAAM+xC,EAAQ+B,qBAAsB98B,EAAUoH,qBAO/E,GALAxxB,KAAK+kD,cAAc/yB,OAASA,EAC5BhyB,KAAK+kD,cAAcqB,WAAapmD,KAAKmnD,2BAA4B/8B,EAAW68B,GAE5EjnD,KAAKqU,KAAM,YAAa,CAAE+V,aAAapqB,KAAK+kD,eAEtC36B,EAAUqD,YAAhB,CAIA,IAAM,MAAM25B,KAAUH,EAAqB,CAC1C,MAAMjB,EAAcoB,EAAOnB,WAE3B,IAAMoB,GAA+Bj9B,EAAUoH,mBAAoB41B,EAAQpnD,KAAK+kD,cAAcpB,QAC7F,SAGD,MAAMhkD,EAAO,CACZ0C,KAAM+nB,EACN84B,WAAYkE,EAAOtpD,KACnBkoD,eAGIhmD,KAAK+kD,cAAcqB,WAAWj8C,KAAMigB,EAAW,aAAeg9B,EAAOtpD,OACzEkC,KAAKqU,KAAM,aAAe+yC,EAAOtpD,KAAM6B,EAAMK,KAAK+kD,eAIpD,IAAM,MAAMjmD,KAAOsrB,EAAUoL,mBAAqB,CACjD,MAAM71B,EAAO,CACZ0C,KAAM+nB,EACN6E,MAAO7E,EAAUmF,gBACjBq2B,aAAc9mD,EACd+mD,kBAAmB,KACnBC,kBAAmB17B,EAAUhL,aAActgB,IAIvCkB,KAAK+kD,cAAcqB,WAAWj8C,KAAMigB,EAAW,aAAezqB,EAAKimD,eACvE5lD,KAAKqU,KAAM,aAAe1U,EAAKimD,aAAe,SAAUjmD,EAAMK,KAAK+kD,eAIrE/kD,KAAKwmD,uBAYN,iBAAkBtD,EAAY8C,EAAah0B,GAE1C,IAAMg0B,EAAYnpD,KAAKmE,UAAyC,cAA7BglD,EAAYnpD,KAAK0tB,SACnD,OAGDvqB,KAAK+kD,cAAc/yB,OAASA,EAG5B,MAAMjgB,EAAY,aAAemxC,EAK3BkD,EAAa,IAAI,GAUvB,GATAA,EAAWx3C,IAAKo3C,EAAaj0C,GAE7B/R,KAAK+kD,cAAcqB,WAAaA,EAEhCpmD,KAAKqU,KAAMtC,EAAW,CAAEmxC,aAAY8C,eAAehmD,KAAK+kD,eAKlDqB,EAAWj8C,KAAM67C,EAAaj0C,GAApC,CAOA/R,KAAK+kD,cAAcqB,WAAapmD,KAAKymD,0BAA2BT,EAAaj0C,GAE7E,IAAM,MAAM1P,KAAQ2jD,EAAYsB,WAAa,CAE5C,IAAMtnD,KAAK+kD,cAAcqB,WAAWj8C,KAAM9H,EAAM0P,GAC/C,SAGD,MAAMpS,EAAO,CAAE0C,OAAM4sB,MAAO,GAAM4B,UAAWxuB,GAAQ6gD,aAAY8C,eAEjEhmD,KAAKqU,KAAMtC,EAAWpS,EAAMK,KAAK+kD,eAGlC/kD,KAAKwmD,uBAWN,oBAAqBtD,EAAY8C,EAAah0B,GAEvCg0B,EAAYnpD,KAAKmE,UAAyC,cAA7BglD,EAAYnpD,KAAK0tB,WAIpDvqB,KAAK+kD,cAAc/yB,OAASA,EAE5BhyB,KAAKqU,KAAM,gBAAkB6uC,EAAY,CAAEA,aAAY8C,eAAehmD,KAAK+kD,eAE3E/kD,KAAKwmD,uBAkBN,6BAA8Be,EAAWx1C,GACxC/R,KAAKilD,2BAA2Bx7C,IAAKsI,EAAWw1C,GAWjD,wBAAyBt4B,GACxB,MAAMm3B,EAAa,IAAI,GAEvB,IAAM,MAAM5nD,KAASywB,EAAQ,CAC5B,MAAM5sB,EAAO7D,EAAM6D,KAEnB+jD,EAAWx3C,IAAKvM,EAAM,UAEtB,IAAM,MAAMvD,KAAOuD,EAAKmzB,mBACvB4wB,EAAWx3C,IAAKvM,EAAM,aAAevD,GAIvC,OAAOsnD,EAWR,0BAA2Bn3B,EAAOhvB,GACjC,MAAMmmD,EAAa,IAAI,GAEvB,IAAM,MAAM/jD,KAAQ4sB,EAAMq4B,WACzBlB,EAAWx3C,IAAKvM,EAAMpC,GAGvB,OAAOmmD,EAWR,2BAA4Bh8B,EAAW+6B,GACtC,MAAMiB,EAAa,IAAI,GAEvBA,EAAWx3C,IAAKwb,EAAW,aAE3B,IAAM,MAAMg9B,KAAUjC,EACrBiB,EAAWx3C,IAAKwb,EAAW,aAAeg9B,EAAOtpD,MAGlD,IAAM,MAAMgB,KAAOsrB,EAAUoL,mBAC5B4wB,EAAWx3C,IAAKwb,EAAW,aAAetrB,GAG3C,OAAOsnD,EAYR,aAAcnmD,EAAMN,GACbK,KAAK+kD,cAAcqB,WAAWj8C,KAAMxK,EAAK0C,KAAMpC,IAKrDD,KAAKqU,KAwRP,SAAuBpU,EAAMN,GAC5B,MAAM7B,EAAO6B,EAAK0C,KAAKvE,MAAQ,QAE/B,MAAO,GAAImC,KAAUnC,IA3RT0pD,CAAcvnD,EAAMN,GAAQA,EAAMK,KAAK+kD,eAQnD,6BACQ/kD,KAAK+kD,cAAc/yB,cACnBhyB,KAAK+kD,cAAcqB,WAW3B,6BAA8BzmD,GAC7BK,KAAK0mD,aAAc,SAAU/mD,GAK7B,IAAM,MAAMb,KAAOa,EAAK0C,KAAKmzB,mBAC5B71B,EAAKimD,aAAe9mD,EACpBa,EAAKkmD,kBAAoB,KACzBlmD,EAAKmmD,kBAAoBnmD,EAAK0C,KAAK+c,aAActgB,GAEjDkB,KAAK0mD,aAAc,aAAc5nD,EAAQa,GAiC3C,qCAAsCulD,GACrC,MAAMuC,EAAmB,IAAIpvC,IACvBqvC,EAAU,GAEhB,IAAM,MAAMl+C,KAAS07C,EAAOyC,aAAe,CAC1C,MAAM98B,EAAWrhB,EAAMqhB,UAAYrhB,EAAMylB,MAAMpO,MAEzC4X,EAAiB5N,EAAS9N,OAIhC,GAHiBkiC,GAAuBp0B,EAAU4N,GAGlC,CACfivB,EAAQzkD,KAAMuG,GAEd,SAGD,MAAMoV,EAAyB,cAAfpV,EAAMvJ,KAAuBi/C,GAAsBr0B,EAAU4N,EAAgB,MAASA,EAItG,GAAK7Z,EAAQze,GAAI,SAAY,CAC5BunD,EAAQzkD,KAAMuG,GAEd,SAGD,IAAIuI,EAQJ,GALCA,EADmB,cAAfvI,EAAMvJ,KACE,aAAcuJ,EAAMo8C,gBAAkBhnC,EAAQ9gB,OAE9C,GAAI0L,EAAMvJ,QAAUuJ,EAAM1L,OAGlCkC,KAAK4nD,yBAA0B71C,EAAW6M,EAAQ9gB,MAAS,CAC/D,GAAK2pD,EAAiB/9C,IAAKkV,GAE1B,SAGD6oC,EAAiB74C,IAAKgQ,GAGtB8oC,EAAQzkD,KAAM,CAAEhD,KAAM,YAAa2e,iBAEnC8oC,EAAQzkD,KAAMuG,GAIhB,OAAOk+C,EAcR,yBAA0B31C,EAAW81C,GACpC,OAAO7nD,KAAKilD,2BAA2B7mD,IAAK2T,KAAgB81C,GAqI9D,SAASR,GAA+B5E,EAAe2E,EAAQzD,GAC9D,MAAM10B,EAAQm4B,EAAOnB,WACf3oC,EAAYnU,MAAMiK,KAAMqvC,EAAcjlC,gBAC5CF,EAAUmP,QACVnP,EAAUwiB,UAUV,OAR0BxiB,EAAU6b,KAAMva,IACzC,GAAKqQ,EAAM64B,aAAclpC,GAAY,CAGpC,QAFoB+kC,EAAOR,cAAevkC,GAErB4L,kBAAmB,mBAa3C,SAAS87B,GAAwB9nD,GAIhC,MAAO,CACN6D,KAJY7D,EAAM6D,KAKlB4sB,MAJiB,GAAMR,4BAA6BjwB,EAAMmtB,iBAAkBntB,EAAMuD,SAQpF,SAAS+kD,GAA0BzkD,EAAMshD,GACxC,GAAKthD,EAAKlC,GAAI,aAAgB,CAC7B,MACMs4B,EADiBkrB,EAAOD,eAAgB,GAASv3B,cAAe9pB,IAChC0a,OAEtC,OAAO0b,EAAet4B,GAAI,SAAYs4B,EAAiB,KAGxD,OAAOkrB,EAAOR,cAAe9gD,GAlD9BmS,GAAK,GAAoB,ICnxBV,MAAM,GAoDpB,YAAama,EAAYC,EAAe1sB,GAOvClC,KAAK8uB,oBAAqB,EAQ1B9uB,KAAK6uB,QAAU,GAQf7uB,KAAKylB,OAAS,IAAI3R,IAEb6a,GACJ3uB,KAAKimB,MAAO0I,EAAYC,EAAe1sB,GAqBzC,aACC,GAAKlC,KAAK6uB,QAAQ9sB,OAAS,EAAI,CAC9B,MAAMktB,EAAQjvB,KAAK6uB,QAAS7uB,KAAK6uB,QAAQ9sB,OAAS,GAElD,OAAO/B,KAAK8uB,mBAAqBG,EAAMnO,IAAMmO,EAAMpO,MAGpD,OAAO,KAaR,YACC,GAAK7gB,KAAK6uB,QAAQ9sB,OAAS,EAAI,CAC9B,MAAMktB,EAAQjvB,KAAK6uB,QAAS7uB,KAAK6uB,QAAQ9sB,OAAS,GAElD,OAAO/B,KAAK8uB,mBAAqBG,EAAMpO,MAAQoO,EAAMnO,IAGtD,OAAO,KAUR,kBAGC,OAAgB,IAFD9gB,KAAK6uB,QAAQ9sB,QAGpB/B,KAAK6uB,QAAS,GAAIpB,YAY3B,iBACC,OAAOztB,KAAK6uB,QAAQ9sB,OASrB,iBACC,OAAQ/B,KAAKytB,aAAeztB,KAAK8uB,mBAWlC,QAASY,GACR,GAAK1vB,KAAKkvB,YAAcQ,EAAeR,WACtC,OAAO,EACD,GAAyB,IAApBlvB,KAAKkvB,WAChB,OAAO,EAGR,IAAMlvB,KAAKmvB,OAAO7C,QAASoD,EAAeP,UAAanvB,KAAK6vB,MAAMvD,QAASoD,EAAeG,OACzF,OAAO,EAGR,IAAM,MAAMC,KAAa9vB,KAAK6uB,QAAU,CACvC,IAAIkB,GAAQ,EAEZ,IAAM,MAAMxC,KAAcmC,EAAeb,QACxC,GAAKiB,EAAUxD,QAASiB,GAAe,CACtCwC,GAAQ,EACR,MAIF,IAAMA,EACL,OAAO,EAIT,OAAO,EAQR,aACC,IAAM,MAAMd,KAASjvB,KAAK6uB,cACnB,IAAI,GAAOI,EAAMpO,MAAOoO,EAAMnO,KActC,gBACC,IAAIsO,EAAQ,KAEZ,IAAM,MAAMH,KAASjvB,KAAK6uB,QACnBO,IAASH,EAAMpO,MAAMhD,SAAUuR,EAAMvO,SAC1CuO,EAAQH,GAIV,OAAOG,EAAQ,IAAI,GAAOA,EAAMvO,MAAOuO,EAAMtO,KAAQ,KAatD,eACC,IAAIuO,EAAO,KAEX,IAAM,MAAMJ,KAASjvB,KAAK6uB,QACnBQ,IAAQJ,EAAMnO,IAAIoM,QAASmC,EAAKvO,OACrCuO,EAAOJ,GAIT,OAAOI,EAAO,IAAI,GAAOA,EAAKxO,MAAOwO,EAAKvO,KAAQ,KAYnD,mBACC,MAAMsO,EAAQpvB,KAAKuvB,gBAEnB,OAAOH,EAAQA,EAAMvO,MAAM6K,QAAU,KAYtC,kBACC,MAAM8D,EAAYxvB,KAAKyvB,eAEvB,OAAOD,EAAYA,EAAU1O,IAAI4K,QAAU,KAsD5C,MAAOiD,EAAYC,EAAe1sB,GACjC,GAAoB,OAAfysB,EACJ3uB,KAAKuwB,WAAY,SACX,GAAK5B,aAAsB,GACjC3uB,KAAKuwB,WAAY5B,EAAWuB,YAAavB,EAAWqB,iBAC9C,GAAKrB,GAA6C,mBAAxBA,EAAWuB,UAG3ClwB,KAAKuwB,WAAY5B,EAAWuB,YAAavB,EAAWqB,iBAC9C,GAAKrB,aAAsB,GACjC3uB,KAAKuwB,WAAY,CAAE5B,KAAgBC,KAAmBA,EAAc+B,eAC9D,GAAKhC,aAAsB,GACjC3uB,KAAKuwB,WAAY,CAAE,IAAI,GAAO5B,UACxB,GAAKA,aAAsB,GAAO,CACxC,MAAMgC,IAAazuB,KAAaA,EAAQyuB,SACxC,IAAI1B,EAEJ,GAAsB,MAAjBL,EACJK,EAAQ,GAAM2B,UAAWjC,QACnB,GAAsB,MAAjBC,EACXK,EAAQ,GAAM4B,UAAWlC,OACnB,SAAuBroB,IAAlBsoB,EAQX,MAAM,IAAI,KAAe,kDAAmD,CAAE5uB,KAAM2uB,IAPpFM,EAAQ,IAAI,GAAO,GAASnE,UAAW6D,EAAYC,IAUpD5uB,KAAKuwB,WAAY,CAAEtB,GAAS0B,OACtB,KAAKrc,GAAYqa,GAgBvB,MAAM,IAAI,KAAe,uCAAwC,CAAE3uB,KAAM2uB,IAdzE3uB,KAAKuwB,WAAY5B,EAAYC,KAAmBA,EAAc+B,WA6BhE,WAAYK,EAAWC,GAAiB,GAIvC,MAAM82B,GAHN/2B,EAAY7nB,MAAMiK,KAAM4d,IAGMmI,KAAMwB,IACnC,KAAQA,aAAoB,IAY3B,MAAM,IAAI,KACT,uCACA,CAAE36B,KAAMgxB,IAIV,OAAOhxB,KAAK6uB,QAAQ3E,MAAO89B,IAClBA,EAAS17B,QAASqO,MAK5B,GAAK3J,EAAUjvB,SAAW/B,KAAK6uB,QAAQ9sB,QAAWgmD,EAAlD,CAIA/nD,KAAKioD,mBAEL,IAAM,MAAMh5B,KAAS+B,EACpBhxB,KAAKkxB,WAAYjC,GAGlBjvB,KAAK8uB,qBAAuBmC,EAE5BjxB,KAAKqU,KAAM,eAAgB,CAAE6zC,cAAc,KAc5C,SAAUn7B,EAAgBzgB,GACzB,GAAqB,OAAhBtM,KAAKmvB,OAMT,MAAM,IAAI,KAAe,qCAAsC,CAAEnvB,KAAM+sB,IAGxE,MAAM+D,EAAW,GAAShG,UAAWiC,EAAgBzgB,GAErD,GAA2C,QAAtCwkB,EAASjE,YAAa7sB,KAAK6vB,OAC/B,OAGD,MAAMV,EAASnvB,KAAKmvB,OAEfnvB,KAAK6uB,QAAQ9sB,QACjB/B,KAAKmoD,YAGiC,UAAlCr3B,EAASjE,YAAasC,IAC1BnvB,KAAKkxB,WAAY,IAAI,GAAOJ,EAAU3B,IACtCnvB,KAAK8uB,oBAAqB,IAE1B9uB,KAAKkxB,WAAY,IAAI,GAAO/B,EAAQ2B,IACpC9wB,KAAK8uB,oBAAqB,GAG3B9uB,KAAKqU,KAAM,eAAgB,CAAE6zC,cAAc,IAS5C,aAAcppD,GACb,OAAOkB,KAAKylB,OAAOrnB,IAAKU,GAWzB,gBACC,OAAOkB,KAAKylB,OAAOnc,UAQpB,mBACC,OAAOtJ,KAAKylB,OAAOjiB,OASpB,aAAc1E,GACb,OAAOkB,KAAKylB,OAAO/b,IAAK5K,GAYzB,gBAAiBA,GACXkB,KAAKkf,aAAcpgB,KACvBkB,KAAKylB,OAAO1R,OAAQjV,GAEpBkB,KAAKqU,KAAM,mBAAoB,CAAE+zC,cAAe,CAAEtpD,GAAOopD,cAAc,KAczE,aAAcppD,EAAKN,GACbwB,KAAKof,aAActgB,KAAUN,IACjCwB,KAAKylB,OAAOhc,IAAK3K,EAAKN,GAEtBwB,KAAKqU,KAAM,mBAAoB,CAAE+zC,cAAe,CAAEtpD,GAAOopD,cAAc,KAWzE,qBACC,OAAyB,IAApBloD,KAAKkvB,WACF,KAGDlvB,KAAKuvB,gBAAgBe,sBAiB7B,GAAIrwB,GACH,MAAgB,cAATA,GAAiC,oBAATA,EAgDhC,qBACC,MAAMooD,EAAU,IAAIzf,QAEpB,IAAM,MAAM3Z,KAASjvB,KAAKkwB,YAAc,CAEvC,MAAMo4B,EAAaC,GAAgBt5B,EAAMpO,MAAOwnC,GAE3CC,GAAcE,GAAmBF,EAAYr5B,WAC3Cq5B,GAGP,IAAM,MAAM9pD,KAASywB,EAAMgL,YAAc,CACxC,MAAMwuB,EAAQjqD,EAAM6D,KAED,cAAd7D,EAAMyB,MAAwByoD,GAAqBD,EAAOJ,EAASp5B,WACjEw5B,GAIR,MAAME,EAAWJ,GAAgBt5B,EAAMnO,IAAKunC,GAGvCM,IAAa15B,EAAMnO,IAAIigC,WAAY,GAASj2B,UAAW69B,EAAU,KAASH,GAAmBG,EAAU15B,WACrG05B,IAgBT,sBAAuB/pC,EAAU5e,KAAKmvB,OAAOtyB,MAC5C,MAAM+rD,EAAqB,GAAS99B,UAAWlM,EAAS,GAClDiqC,EAAmB,GAAS/9B,UAAWlM,EAAS,OAEtD,OAAOgqC,EAAmB7H,WAAY/gD,KAAKwxB,qBAC1Cq3B,EAAiB9H,WAAY/gD,KAAKyxB,mBAUpC,WAAYxC,GACXjvB,KAAK8oD,YAAa75B,GAClBjvB,KAAK6uB,QAAQ5rB,KAAM,IAAI,GAAOgsB,EAAMpO,MAAOoO,EAAMnO,MASlD,YAAamO,GACZ,IAAM,IAAI1xB,EAAI,EAAGA,EAAIyC,KAAK6uB,QAAQ9sB,OAAQxE,IACzC,GAAK0xB,EAAMnB,eAAgB9tB,KAAK6uB,QAAStxB,IAQxC,MAAM,IAAI,KACT,mCACA,CAAEyC,KAAMivB,GACR,CAAEmC,WAAYnC,EAAOoC,kBAAmBrxB,KAAK6uB,QAAStxB,KAY1D,mBACC,KAAQyC,KAAK6uB,QAAQ9sB,OAAS,GAC7B/B,KAAKmoD,YASP,YACCnoD,KAAK6uB,QAAQzlB,OAmCf,SAAS2/C,GAAkBnqC,EAASypC,GACnC,OAAKA,EAAQ3+C,IAAKkV,KAIlBypC,EAAQz5C,IAAKgQ,GAENA,EAAQ/hB,KAAKmE,SAASgoD,MAAMC,OAAOC,QAAStqC,IAAaA,EAAQ7B,QAIzE,SAAS2rC,GAAqB9pC,EAASypC,EAASp5B,GAC/C,OAAO85B,GAAkBnqC,EAASypC,IAAaG,GAAmB5pC,EAASqQ,GAM5E,SAASs5B,GAAgB19B,EAAUw9B,GAClC,MACMY,EADUp+B,EAAS9N,OACFlgB,KAAKmE,SAASgoD,MAAMC,OAErC3rC,EAAYuN,EAAS9N,OAAOS,aAAc,CAAEH,aAAa,EAAMD,aAAa,IAElF,IAAI+rC,GAAiB,EAErB,MAAMV,EAAQnrC,EAAUlH,KAAMwI,IAExBuqC,IAILA,EAAiBF,EAAOG,QAASxqC,IAEzBuqC,GAAkBJ,GAAkBnqC,EAASypC,KAOtD,OAFA/qC,EAAU7Z,QAASmb,GAAWypC,EAAQz5C,IAAKgQ,IAEpC6pC,EAOR,SAASD,GAAmBC,EAAOx5B,GAClC,MAAMo6B,EAgBP,SAA4B92C,GAC3B,MAAM02C,EAAS12C,EAAK1V,KAAKmE,SAASgoD,MAAMC,OAExC,IAAIlsC,EAASxK,EAAKwK,OAElB,KAAQA,GAAS,CAChB,GAAKksC,EAAOC,QAASnsC,GACpB,OAAOA,EAGRA,EAASA,EAAOA,QA1BGusC,CAAmBb,GAEvC,IAAMY,EACL,OAAO,EAMR,OAFwBp6B,EAAMoyB,cAAe,GAAMxwB,UAAWw4B,IAAe,GA5D9E70C,GAAK,GAAW,IC/wBD,MAAM,WAAkB,GAMtC,YAAaqM,EAAOC,GACnBlhB,MAAOihB,EAAOC,GAEdyoC,GAAiB7rD,KAAMsC,MAQxB,SACCA,KAAKsR,gBAmBN,GAAIrR,GACH,MAAgB,cAATA,GAAiC,oBAATA,GAEtB,SAARA,GAA4B,gBAATA,EAQrB,UACC,OAAO,IAAI,GAAOD,KAAK6gB,MAAO7gB,KAAK8gB,KASpC,iBAAkBmO,GACjB,OAAO,IAAI,GAAWA,EAAMpO,MAAOoO,EAAMnO,MA4D3C,SAASyoC,KACRvpD,KAAKmR,SACJnR,KAAKnD,KAAKmE,SAASgoD,MACnB,iBACA,CAAE/3C,EAAOI,KACR,MAAMquC,EAAYruC,EAAM,GAElBquC,EAAU8J,qBAIhB,GAAU9rD,KAAMsC,KAAM0/C,IAEvB,CAAEjvC,SAAU,QAQd,SAAS,GAAWivC,GAEnB,MAAM7xB,EAAS7tB,KAAKmhD,0BAA2BzB,GACzC59C,EAAS,GAAM2nD,kBAAmB57B,GAElC67B,GAAqB5nD,EAAOwqB,QAAStsB,MACrC2pD,EAmCP,SAA0C16B,EAAOywB,GAChD,OAASA,EAAUz/C,MAClB,IAAK,SACJ,OAAOgvB,EAAMtB,iBAAkB+xB,EAAU70B,UAC1C,IAAK,OACL,IAAK,SACL,IAAK,WACL,IAAK,QACJ,OAAOoE,EAAMtB,iBAAkB+xB,EAAUO,iBACxChxB,EAAMpO,MAAMyL,QAASozB,EAAUO,iBAC/BhxB,EAAMtB,iBAAkB+xB,EAAUpnB,gBACpC,IAAK,QACJ,OAAOrJ,EAAMtB,iBAAkB+xB,EAAUU,gBAAmBnxB,EAAMtB,iBAAkB+xB,EAAUnmB,mBAGhG,OAAO,EAlDgBqwB,CAAiC5pD,KAAM0/C,GAE9D,IAAIc,EAAmB,KAEvB,GAAKkJ,EAAoB,CAGK,cAAxB5nD,EAAOjF,KAAK0tB,WAGfi2B,EADsB,UAAlBd,EAAUz/C,KACKy/C,EAAUO,eAGVP,EAAUc,kBAI/B,MAAMwH,EAAWhoD,KAAK6pD,UAEtB7pD,KAAK6gB,MAAQ/e,EAAO+e,MACpB7gB,KAAK8gB,IAAMhf,EAAOgf,IAElB9gB,KAAKqU,KAAM,eAAgB2zC,EAAU,CAAExH,0BAC5BmJ,GAEX3pD,KAAKqU,KAAM,iBAAkBrU,KAAK6pD,UAAW,CAAErJ,qBA4BjDhsC,GAAK,GAAW,IC3KD,MAAM,GAMpB,YAAa4yB,GAMZpnC,KAAKsxB,WAAa,IAAI,GAAe8V,GAErCpnC,KAAKsxB,WAAWC,SAAU,gBAAiB3d,GAAI5T,MAC/CA,KAAKsxB,WAAWC,SAAU,oBAAqB3d,GAAI5T,MACnDA,KAAKsxB,WAAWC,SAAU,iBAAkB3d,GAAI5T,MAUjD,kBACC,OAAOA,KAAKsxB,WAAW7D,YAexB,aACC,OAAOztB,KAAKsxB,WAAWnC,OAYxB,YACC,OAAOnvB,KAAKsxB,WAAWzB,MASxB,iBACC,OAAO7vB,KAAKsxB,WAAWpC,WAUxB,kBACC,OAAOlvB,KAAKsxB,WAAWw4B,YAUxB,iBACC,OAAO9pD,KAAKsxB,WAAWtB,WAWxB,0BACC,OAAOhwB,KAAKsxB,WAAWy4B,oBAYxB,cACC,OAAO/pD,KAAKsxB,WAAW6zB,QAQxB,cACC,OAAOnlD,KAAKsxB,WAAWzC,QAQxB,YACC,OAAO7uB,KAAKsxB,WAAWpB,YAYxB,mBACC,OAAOlwB,KAAKsxB,WAAWE,mBAYxB,kBACC,OAAOxxB,KAAKsxB,WAAWG,kBAaxB,gBACC,OAAOzxB,KAAKsxB,WAAW/B,gBAaxB,eACC,OAAOvvB,KAAKsxB,WAAW7B,eAgDxB,oBACC,OAAOzvB,KAAKsxB,WAAW04B,oBAUxB,qBACC,OAAOhqD,KAAKsxB,WAAWI,qBAcxB,sBAAuB9S,GACtB,OAAO5e,KAAKsxB,WAAW24B,sBAAuBrrC,GAM/C,UACC5e,KAAKsxB,WAAWpX,UAQjB,mBACC,OAAOla,KAAKsxB,WAAWkE,mBAWxB,gBACC,OAAOx1B,KAAKsxB,WAAWyJ,gBASxB,aAAcj8B,GACb,OAAOkB,KAAKsxB,WAAWlS,aAActgB,GAStC,aAAcA,GACb,OAAOkB,KAAKsxB,WAAWpS,aAAcpgB,GAMtC,UACCkB,KAAKsxB,WAAW44B,iBAChBlqD,KAAKsxB,WAAW64B,mBAAmB,GAUpC,eAAgBC,GACfpqD,KAAKsxB,WAAW+4B,eAAgBD,GAoBjC,GAAInqD,GACH,MAAgB,cAATA,GACE,mBAARA,GACQ,qBAARA,GACQ,2BAARA,EAgBF,UAAW8sB,EAAgBzgB,GAC1BtM,KAAKsxB,WAAWM,SAAU7E,EAAgBzgB,GAe3C,OAAQqiB,EAAYC,EAAe1sB,GAClClC,KAAKsxB,WAAWrL,MAAO0I,EAAYC,EAAe1sB,GAYnD,cAAepD,EAAKN,GACnBwB,KAAKsxB,WAAW5tB,aAAc5E,EAAKN,GAapC,iBAAkBM,GACjBkB,KAAKsxB,WAAW1sB,gBAAiB9F,GASlC,uBACC,OAAOkB,KAAKsxB,WAAWg5B,uBAiBxB,mBACC,OAAOtqD,KAAKsxB,WAAWi5B,kBAcxB,gBAAiB5gD,GAChB3J,KAAKsxB,WAAWk5B,eAAgB7gD,GAUjC,6BAA8B7K,GAC7B,MA7ekB,aA6eGA,EAUtB,4BAA6BA,GAC5B,OAAOA,EAAI2rD,WAxfO,eA4fpBj2C,GAAK,GAAmB,IAqDxB,MAAM,WAAsB,GAG3B,YAAa4yB,GACZxnC,QAMAI,KAAKmlD,QAAU,IAAI,GAAY,CAAE/vC,WAAY,SAM7CpV,KAAK0qD,OAAStjB,EAAI4hB,MAMlBhpD,KAAKq3B,UAAY+P,EAUjBpnC,KAAK2qD,mBAAqB,IAAI72C,IAK9B9T,KAAK4qD,0BAA4B,KAKjC5qD,KAAK6qD,kBAAmB,EAQxB7qD,KAAK8qD,2BAA6B,IAAIzyC,IAKtCrY,KAAK+qD,iBAAmB,IAAI1yC,IAG5BrY,KAAKmR,SAAUnR,KAAK0qD,OAAQ,iBAAkB,CAAE5zC,EAAKzF,KACpD,MAAMquC,EAAYruC,EAAM,GAElBquC,EAAU8J,qBAAyC,UAAlB9J,EAAUz/C,MAAsC,UAAlBy/C,EAAUz/C,MAAsC,QAAlBy/C,EAAUz/C,OAKjF,GAAvBD,KAAK6uB,QAAQ9sB,QAAe/B,KAAK4qD,2BACrC5qD,KAAKgrD,uBAAwBhrD,KAAK4qD,2BAInC5qD,KAAK4qD,0BAA4B,KAE5B5qD,KAAK6qD,mBACT7qD,KAAK6qD,kBAAmB,EACxB7qD,KAAKqU,KAAM,eAAgB,CAAE6zC,cAAc,OAE1C,CAAEz3C,SAAU,WAGfzQ,KAAKkpB,GAAI,eAAgB,KACxB,IAAM,MAAM+F,KAASjvB,KAAKkwB,YACzB,IAAMlwB,KAAKq3B,UAAU4zB,wBAAyBh8B,GAQ7C,MAAM,IAAI,KACT,oCACAjvB,KACA,CAAEivB,YAQNjvB,KAAKmR,SAAUnR,KAAK0qD,OAAOvF,QAAS,SAAU,CAAEruC,EAAKswC,EAAQY,EAAUrtB,KACtE36B,KAAKkrD,cAAe9D,EAAQzsB,KAI7B36B,KAAKmR,SAAUnR,KAAKq3B,UAAW,SAAU,CAAEvgB,EAAKq0C,MAqiBlD,SAAyCnC,EAAOmC,GAC/C,MAAMjG,EAAS8D,EAAMhoD,SAASkkD,OAE9B,IAAM,MAAM17C,KAAS07C,EAAOyC,aAAe,CAC1C,GAAmB,UAAdn+C,EAAMvJ,KACV,SAGD,MAAMmrD,EAAe5hD,EAAMqhB,SAAS9N,OACZvT,EAAMzH,SAAWqpD,EAAalN,WAGrD8K,EAAMqC,cAAeF,EAAOn5B,IAC3B,MAAMs5B,EAAmBniD,MAAMiK,KAAMg4C,EAAa51B,oBAChDxxB,OAAQlF,GAAOA,EAAI2rD,WA9sCL,eAgtChB,IAAM,MAAM3rD,KAAOwsD,EAClBt5B,EAAOptB,gBAAiB9F,EAAKssD,MArjB/BG,CAAgCvrD,KAAK0qD,OAAQS,KAI/C,kBAGC,OAAkB,IAFHnrD,KAAK6uB,QAAQ9sB,OAEN/B,KAAKq3B,UAAUm0B,mBAAmB/9B,YAAc7tB,MAAM6tB,YAG7E,aACC,OAAO7tB,MAAMuvB,QAAUnvB,KAAKq3B,UAAUm0B,mBAAmB3qC,MAG1D,YACC,OAAOjhB,MAAMiwB,OAAS7vB,KAAKq3B,UAAUm0B,mBAAmB1qC,IAGzD,iBACC,OAAO9gB,KAAK6uB,QAAQ9sB,OAAS/B,KAAK6uB,QAAQ9sB,OAAS,EAQpD,kBACC,OAAO/B,KAAK6uB,QAAQ9sB,OAAS,EAQ9B,0BACC,QAAS/B,KAAK8qD,2BAA2B9hD,KAI1C,UACC,IAAM,IAAIzL,EAAI,EAAGA,EAAIyC,KAAK6uB,QAAQ9sB,OAAQxE,IACzCyC,KAAK6uB,QAAStxB,GAAI2uC,SAGnBlsC,KAAKsR,gBAGN,aACMtR,KAAK6uB,QAAQ9sB,aACVnC,MAAMswB,kBAEPlwB,KAAKq3B,UAAUm0B,mBAIvB,gBACC,OAAO5rD,MAAM2vB,iBAAmBvvB,KAAKq3B,UAAUm0B,mBAGhD,eACC,OAAO5rD,MAAM6vB,gBAAkBzvB,KAAKq3B,UAAUm0B,mBAG/C,MAAO78B,EAAY88B,EAAwBvpD,GAC1CtC,MAAMqmB,MAAO0I,EAAY88B,EAAwBvpD,GACjDlC,KAAKmqD,mBAAmB,GACxBnqD,KAAKkqD,iBAGN,SAAUn9B,EAAgBzgB,GACzB1M,MAAMgyB,SAAU7E,EAAgBzgB,GAChCtM,KAAKmqD,mBAAmB,GACxBnqD,KAAKkqD,iBAGN,aAAcprD,EAAKN,GAClB,GAAKwB,KAAK03B,cAAe54B,EAAKN,GAAU,CAEvC,MAAM4pD,EAAgB,CAAEtpD,GACxBkB,KAAKqU,KAAM,mBAAoB,CAAE+zC,gBAAeF,cAAc,KAIhE,gBAAiBppD,GAChB,GAAKkB,KAAK23B,iBAAkB74B,GAAQ,CAEnC,MAAMspD,EAAgB,CAAEtpD,GACxBkB,KAAKqU,KAAM,mBAAoB,CAAE+zC,gBAAeF,cAAc,KAIhE,kBACC,MAAMwD,EAAc,KAUpB,OANA1rD,KAAK8qD,2BAA2Bl8C,IAAK88C,GAES,IAAzC1rD,KAAK8qD,2BAA2B9hD,MACpChJ,KAAKmqD,mBAAmB,GAGlBuB,EAGR,eAAgB/hD,GACf,IAAM3J,KAAK8qD,2BAA2BphD,IAAKC,GAS1C,MAAM,IAAI,KACT,2CACA3J,KACA,CAAE2J,QAIJ3J,KAAK8qD,2BAA2B/2C,OAAQpK,GAGlC3J,KAAK+pD,qBACV/pD,KAAKmqD,mBAAmB,GAI1B,eAAgBC,GACfpqD,KAAK+qD,iBAAiBn8C,IAAKw7C,GAC3BpqD,KAAKkqD,iBAGN,YACClqD,KAAK6uB,QAAQzlB,MAAM8iC,SAGpB,WAAYjd,GACX,MAAM08B,EAAY3rD,KAAK4rD,cAAe38B,GAGjC08B,GACJ3rD,KAAK6uB,QAAQ5rB,KAAM0oD,GAUrB,cAAe18B,GAGd,GAFAjvB,KAAK8oD,YAAa75B,GAEbA,EAAMpyB,MAAQmD,KAAKq3B,UAAUwpB,UAGjC,OAGD,MAAM8K,EAAY,GAAUE,UAAW58B,GAgBvC,OAZA08B,EAAUziC,GAAI,eAAgB,CAAEpS,EAAKkxC,EAAUroD,KAG9C,GAFAK,KAAK6qD,kBAAmB,EAEnBc,EAAU9uD,MAAQmD,KAAKq3B,UAAUwpB,UAAY,CACjD7gD,KAAK4qD,0BAA4BjrD,EAAK6gD,iBAEtC,MAAM99C,EAAQ1C,KAAK6uB,QAAQ/b,QAAS64C,GACpC3rD,KAAK6uB,QAAQ/oB,OAAQpD,EAAO,GAC5BipD,EAAUzf,YAILyf,EAGR,iBACC,IAAM3rD,KAAK+qD,iBAAiB/hD,KAC3B,OAGD,MAAMm8C,EAAU,GAChB,IAAI2G,GAAU,EAEd,IAAM,MAAM1E,KAAUpnD,KAAK0qD,OAAOvF,QAAU,CAC3C,MAAM4G,EAAc3E,EAAOtpD,KAAKyR,MAAO,IAAK,GAAK,GAEjD,IAAMvP,KAAK+qD,iBAAiBrhD,IAAKqiD,GAChC,SAGD,MAAM/F,EAAcoB,EAAOnB,WAE3B,IAAM,MAAM+F,KAAkBhsD,KAAKkwB,YAC7B81B,EAAY3E,cAAe2K,GAAiBA,EAAev+B,cAC/D03B,EAAQliD,KAAMmkD,GAKjB,MAAM6E,EAAa9iD,MAAMiK,KAAMpT,KAAKmlD,SAEpC,IAAM,MAAMiC,KAAUjC,EACfnlD,KAAKmlD,QAAQz7C,IAAK09C,KACvBpnD,KAAKmlD,QAAQv2C,IAAKw4C,GAElB0E,GAAU,GAIZ,IAAM,MAAM1E,KAAUj+C,MAAMiK,KAAMpT,KAAKmlD,SAChCA,EAAQ/rC,SAAUguC,KACvBpnD,KAAKmlD,QAAQhhD,OAAQijD,GAErB0E,GAAU,GAIPA,GACJ9rD,KAAKqU,KAAM,gBAAiB,CAAE43C,aAAY/D,cAAc,IAI1D,cAAed,EAAQpB,GACtB,MAAM+F,EAAc3E,EAAOtpD,KAAKyR,MAAO,IAAK,GAAK,GAEjD,IAAMvP,KAAK+qD,iBAAiBrhD,IAAKqiD,GAChC,OAGD,IAAID,GAAU,EAEd,MAAMG,EAAa9iD,MAAMiK,KAAMpT,KAAKmlD,SAC9B+G,EAAYlsD,KAAKmlD,QAAQz7C,IAAK09C,GAEpC,GAAMpB,EAKC,CACN,IAAImG,GAAY,EAEhB,IAAM,MAAMH,KAAkBhsD,KAAKkwB,YAClC,GAAK81B,EAAY3E,cAAe2K,GAAiBA,EAAev+B,aAAgB,CAC/E0+B,GAAY,EAEZ,MAIGA,IAAcD,GAClBlsD,KAAKmlD,QAAQv2C,IAAKw4C,GAElB0E,GAAU,IACEK,GAAaD,IACzBlsD,KAAKmlD,QAAQhhD,OAAQijD,GAErB0E,GAAU,QAtBNI,IACJlsD,KAAKmlD,QAAQhhD,OAAQijD,GACrB0E,GAAU,GAwBPA,GACJ9rD,KAAKqU,KAAM,gBAAiB,CAAE43C,aAAY/D,cAAc,IAS1D,kBAAmBkE,GAClB,MAAMC,EAAgB/tC,GAAOte,KAAKssD,6BAC5BC,EAAgBjuC,GAAOte,KAAK+6B,iBAElC,GAAKqxB,EAEJpsD,KAAK2qD,mBAAqB,IAAI72C,IAC9B9T,KAAKylB,OAAS,IAAI3R,SAGlB,IAAM,MAAQhV,EAAK2R,KAAczQ,KAAK2qD,mBACpB,OAAZl6C,IACJzQ,KAAKylB,OAAO1R,OAAQjV,GACpBkB,KAAK2qD,mBAAmB52C,OAAQjV,IAKnCkB,KAAKwsD,iBAAkBH,GAGvB,MAAMP,EAAU,GAIhB,IAAM,MAAQW,EAAQzhD,KAAchL,KAAK+6B,gBAClCwxB,EAAc7iD,IAAK+iD,IAAYF,EAAcnuD,IAAKquD,KAAazhD,GACpE8gD,EAAQ7oD,KAAMwpD,GAKhB,IAAM,MAAQC,KAAYH,EACnBvsD,KAAKkf,aAAcwtC,IACxBZ,EAAQ7oD,KAAMypD,GAKXZ,EAAQ/pD,OAAS,GACrB/B,KAAKqU,KAAM,mBAAoB,CAAE+zC,cAAe0D,EAAS5D,cAAc,IAazE,cAAeppD,EAAKN,EAAO0pD,GAAe,GACzC,MAAMz3C,EAAWy3C,EAAe,SAAW,MAE3C,GAAiB,OAAZz3C,GAA2D,UAAtCzQ,KAAK2qD,mBAAmBvsD,IAAKU,GAEtD,OAAO,EAMR,OAHiBc,MAAMwf,aAActgB,KAGnBN,IAIlBwB,KAAKylB,OAAOhc,IAAK3K,EAAKN,GAGtBwB,KAAK2qD,mBAAmBlhD,IAAK3K,EAAK2R,IAE3B,GAeR,iBAAkB3R,EAAKopD,GAAe,GACrC,MAAMz3C,EAAWy3C,EAAe,SAAW,MAE3C,OAAiB,OAAZz3C,GAA2D,UAAtCzQ,KAAK2qD,mBAAmBvsD,IAAKU,MAMvDkB,KAAK2qD,mBAAmBlhD,IAAK3K,EAAK2R,KAG5B7Q,MAAMsf,aAAcpgB,KAI1BkB,KAAKylB,OAAO1R,OAAQjV,IAEb,IASR,iBAAkB0mB,GACjB,MAAMsmC,EAAU,IAAIzzC,IAEpB,IAAM,MAAQq0C,EAAQ7kC,KAAc7nB,KAAK+6B,gBAEnCvV,EAAMpnB,IAAKsuD,KAAa7kC,GAK7B7nB,KAAK23B,iBAAkB+0B,GAAQ,GAGhC,IAAM,MAAQ5tD,EAAKN,KAAWgnB,EAAQ,CAEpBxlB,KAAK03B,cAAe54B,EAAKN,GAAO,IAGhDstD,EAAQl9C,IAAK9P,GAIf,OAAOgtD,EAOR,wBACC,MAAMpoB,EAAkB1jC,KAAKwxB,mBAAmBzU,OAEhD,GAAK/c,KAAKytB,aAAeiW,EAAgBjhB,QACxC,IAAM,MAAM3jB,KAAO4kC,EAAgBlO,mBAClC,GAAK12B,EAAI2rD,WAzkCO,cAykCqB,CACpC,MAAMkC,EAAU7tD,EAAIuT,OA1kCL,aA0kCyBtQ,aAElC,CAAE4qD,EAASjpB,EAAgBtkB,aAActgB,KAYnD,4BACC,MAAM+rB,EAAW7qB,KAAKwxB,mBAChBy3B,EAASjpD,KAAK0qD,OAAOzB,OAE3B,IAAIzjC,EAAQ,KAEZ,GAAMxlB,KAAKytB,YAgBJ,CAGN,MAAMH,EAAazC,EAAS1M,SAAW0M,EAAS1M,SAAW0M,EAASyC,WAC9DF,EAAYvC,EAAS1M,SAAW0M,EAAS1M,SAAW0M,EAASuC,UAenE,GAZMptB,KAAK+pD,sBAEVvkC,EAAQonC,GAAqBt/B,IAIxB9H,IACLA,EAAQonC,GAAqBx/B,KAKxBptB,KAAK+pD,sBAAwBvkC,EAAQ,CAC1C,IAAIjT,EAAO+a,EAEX,KAAQ/a,IAAS02C,EAAO4D,SAAUt6C,KAAWiT,GAC5CjT,EAAOA,EAAK4b,gBACZ3I,EAAQonC,GAAqBr6C,GAK/B,IAAMiT,EAAQ,CACb,IAAIjT,EAAO6a,EAEX,KAAQ7a,IAAS02C,EAAO4D,SAAUt6C,KAAWiT,GAC5CjT,EAAOA,EAAK2b,YACZ1I,EAAQonC,GAAqBr6C,GAKzBiT,IACLA,EAAQxlB,KAAKsqD,4BAxDU,CAExB,MAAMr7B,EAAQjvB,KAAKuvB,gBAGnB,IAAM,MAAM/wB,KAASywB,EAAQ,CAE5B,GAAKzwB,EAAM6D,KAAKlC,GAAI,YAAe8oD,EAAO6D,SAAUtuD,EAAM6D,MACzD,MAGD,GAAmB,QAAd7D,EAAMyB,KAAiB,CAC3BulB,EAAQhnB,EAAM6D,KAAK04B,gBACnB,QA+CH,OAAOvV,EAOR,uBAAwBg7B,GAEvB,MAAMwL,EAAiBhsD,KAAK0qD,OAAOzB,OAAO8D,yBAA0BvM,GAG/DwL,GAEJhsD,KAAKkxB,WAAY86B,IAYpB,SAASY,GAAqBr6C,GAC7B,OAAKA,aAAgB,IAAaA,aAAgB,GAC1CA,EAAKwoB,gBAGN,KClsCO,MAAMiyB,GAOpB,YAAaC,GACZjtD,KAAKktD,aAAeD,EAYrB,IAAKE,GACJ,IAAM,MAAMnI,KAAchlD,KAAKktD,aAC9BC,EAAkBnI,GAGnB,OAAOhlD,MCTM,OAJf,SAAmBxB,GACjB,OAAO,GAAUA,EAAO,ICGX,MAAM,WAAwBwuD,GAkE5C,iBAAkBnxC,GACjB,OAAO7b,KAAK4O,IAqvCd,SAAmCiN,GAKlC,OAJAA,EAAS,GAAWA,IAEb6Z,KAAO03B,GAA0BvxC,EAAO6Z,KAAM,aAE9CsvB,IAljBD,IAAwBqI,EAqjB7B,GAFArI,EAAW97B,GAAI,UAAYrN,EAAOmtC,OAnjBLqE,EAmjB2BxxC,EAAO6Z,KAljBzD,CAAE5e,EAAKnX,EAAMolD,KACnB,MAAMjqB,EAAcuyB,EAAgB1tD,EAAK0C,KAAM0iD,GAE/C,IAAMjqB,EACL,OAGD,IAAMiqB,EAAcqB,WAAWkH,QAAS3tD,EAAK0C,KAAM,UAClD,OAGD,MAAMm0B,EAAeuuB,EAAcpB,OAAOD,eAAgB/jD,EAAKsvB,MAAMpO,OAErEkkC,EAAcpB,OAAOrgB,aAAc3jC,EAAK0C,KAAMy4B,GAC9CiqB,EAAc/yB,OAAOruB,OAAQ6yB,EAAcsE,KAoiB4B,CAAErqB,SAAUoL,EAAO0xC,mBAAqB,WAE1G1xC,EAAO2xC,UAAY,CACvB,GAAK3xC,EAAO2xC,UAAUlqD,WACrB,IAAM,MAAMsiD,KAAgB/pC,EAAO2xC,UAAUlqD,WAC5C0hD,EAAWyI,6BAA8B5xC,EAAOmtC,MAAO,aAAcpD,KAAkB/pC,EAAOmtC,SAIhG,GAAKntC,EAAO2xC,UAAU1lD,SACrB,IAAM,MAAM4lD,KAAa7xC,EAAO2xC,UAAU1lD,SACzCk9C,EAAWyI,6BAA8B5xC,EAAOmtC,MAAO,UAAW0E,GAClE1I,EAAWyI,6BAA8B5xC,EAAOmtC,MAAO,UAAW0E,KAvwCpDC,CAA0B9xC,IAyF5C,mBAAoBA,GACnB,OAAO7b,KAAK4O,IAisCd,SAAqCiN,GACpCA,EAAS,GAAWA,GAGpB,IAAI9J,EAAY,cADC8J,EAAOmtC,MAAMlqD,IAAM+c,EAAOmtC,MAAMlqD,IAAM+c,EAAOmtC,OAGzDntC,EAAOmtC,MAAMlrD,OACjBiU,GAAa,IAAM8J,EAAOmtC,MAAMlrD,MAGjC,GAAK+d,EAAOmtC,MAAM38C,OACjB,IAAM,MAAMuhD,KAAc/xC,EAAOmtC,MAAM38C,OACtCwP,EAAO6Z,KAAMk4B,GAAeR,GAA0BvxC,EAAO6Z,KAAMk4B,GAAc,kBAGlF/xC,EAAO6Z,KAAO03B,GAA0BvxC,EAAO6Z,KAAM,aAGtD,MAAM23B,EAAiBQ,GAAyBhyC,GAEhD,OAAOmpC,IACNA,EAAW97B,GAAInX,EAzqBV,SAAes7C,GACrB,MAAO,CAAEv2C,EAAKnX,EAAMolD,KAGnB,MAAM+I,EAAiBT,EAAgB1tD,EAAKkmD,kBAAmBd,GAGzDgJ,EAAiBV,EAAgB1tD,EAAKmmD,kBAAmBf,GAE/D,IAAM+I,IAAmBC,EACxB,OAGD,IAAMhJ,EAAcqB,WAAWkH,QAAS3tD,EAAK0C,KAAMyU,EAAIhZ,MACtD,OAGD,MAAMkwD,EAAajJ,EAAc/yB,OAC3BwI,EAAgBwzB,EAAWhtD,SAASopB,UAE1C,GAAKzqB,EAAK0C,gBAAgB,IAAkB1C,EAAK0C,gBAAgB,GAEhE2rD,EAAW1xB,KAAM9B,EAAcjL,gBAAiBw+B,OAC1C,CAEN,IAAIxkB,EAAYwb,EAAcpB,OAAOsK,YAAatuD,EAAKsvB,OAGvB,OAA3BtvB,EAAKkmD,mBAA8BiI,IACvCvkB,EAAYykB,EAAWE,OAAQ3kB,EAAWukB,IAGX,OAA3BnuD,EAAKmmD,mBAA8BiI,GACvCC,EAAW1xB,KAAMiN,EAAWwkB,KAwoBJzxB,CAAM+wB,GAAkB,CAAE58C,SAAUoL,EAAO0xC,mBAAqB,YAttCzEY,CAA4BtyC,IAkF9C,qBAAsBA,GACrB,OAAO7b,KAAK4O,IAqpCd,SAAuCiN,GACtCA,EAAS,GAAWA,GAGpB,IAAI9J,EAAY,cADC8J,EAAOmtC,MAAMlqD,IAAM+c,EAAOmtC,MAAMlqD,IAAM+c,EAAOmtC,OAGzDntC,EAAOmtC,MAAMlrD,OACjBiU,GAAa,IAAM8J,EAAOmtC,MAAMlrD,MAGjC,GAAK+d,EAAOmtC,MAAM38C,OACjB,IAAM,MAAMuhD,KAAc/xC,EAAOmtC,MAAM38C,OACtCwP,EAAO6Z,KAAMk4B,GAAeQ,GAA4BvyC,EAAO6Z,KAAMk4B,SAGtE/xC,EAAO6Z,KAAO04B,GAA4BvyC,EAAO6Z,MAGlD,MAAM23B,EAAiBQ,GAAyBhyC,GAEhD,OAAOmpC,IAhYR,IAA0BqJ,EAiYxBrJ,EAAW97B,GAAInX,GAjYSs8C,EAiYmBhB,EAhYrC,CAAEv2C,EAAKnX,EAAMolD,KACnB,MAAMuJ,EAAeD,EAAkB1uD,EAAKkmD,kBAAmBd,GACzDtpB,EAAe4yB,EAAkB1uD,EAAKmmD,kBAAmBf,GAE/D,IAAMuJ,IAAiB7yB,EACtB,OAGD,IAAMspB,EAAcqB,WAAWkH,QAAS3tD,EAAK0C,KAAMyU,EAAIhZ,MACtD,OAGD,MAAMg9B,EAAciqB,EAAcpB,OAAOR,cAAexjD,EAAK0C,MACvD2rD,EAAajJ,EAAc/yB,OAIjC,IAAM8I,EAmCL,MAAM,IAAI,KACT,4CACA,CAAEn7B,EAAMolD,IAKV,GAAgC,OAA3BplD,EAAKkmD,mBAA8ByI,EACvC,GAAyB,SAApBA,EAAaxvD,IAAiB,CAClC,MAAM6f,EAAUtE,GAASi0C,EAAa9vD,OAEtC,IAAM,MAAM4nB,KAAazH,EACxBqvC,EAAWnxB,YAAazW,EAAW0U,QAE9B,GAAyB,SAApBwzB,EAAaxvD,IAAiB,CACzC,MAAM0E,EAAOvF,OAAOuF,KAAM8qD,EAAa9vD,OAEvC,IAAM,MAAMM,KAAO0E,EAClBwqD,EAAWlxB,YAAah+B,EAAKg8B,QAG9BkzB,EAAWppD,gBAAiB0pD,EAAaxvD,IAAKg8B,GAKhD,GAAgC,OAA3Bn7B,EAAKmmD,mBAA8BrqB,EACvC,GAAyB,SAApBA,EAAa38B,IAAiB,CAClC,MAAM6f,EAAUtE,GAASohB,EAAaj9B,OAEtC,IAAM,MAAM4nB,KAAazH,EACxBqvC,EAAWrxB,SAAUvW,EAAW0U,QAE3B,GAAyB,SAApBW,EAAa38B,IAAiB,CACzC,MAAM0E,EAAOvF,OAAOuF,KAAMi4B,EAAaj9B,OAEvC,IAAM,MAAMM,KAAO0E,EAClBwqD,EAAWtxB,SAAU59B,EAAK28B,EAAaj9B,MAAOM,GAAOg8B,QAGtDkzB,EAAWtqD,aAAc+3B,EAAa38B,IAAK28B,EAAaj9B,MAAOs8B,KAoSJ,CAAErqB,SAAUoL,EAAO0xC,mBAAqB,YA1qCpFgB,CAA8B1yC,IAmEhD,gBAAiBA,GAChB,OAAO7b,KAAK4O,IAonCd,SAAkCiN,GAKjC,OAJAA,EAAS,GAAWA,IAEb6Z,KAAO03B,GAA0BvxC,EAAO6Z,KAAM,MAE9CsvB,IAhoBD,IAA0BqI,EAioB/BrI,EAAW97B,GAAI,aAAerN,EAAOmtC,OAjoBNqE,EAioB8BxxC,EAAO6Z,KAhoB9D,CAAE5e,EAAKnX,EAAMolD,KAGnBplD,EAAK6uD,WAAY,EACjB,MAAMC,EAAmBpB,EAAgB1tD,EAAMolD,GAE/CplD,EAAK6uD,WAAY,EACjB,MAAME,EAAiBrB,EAAgB1tD,EAAMolD,GAE7C,IAAM0J,IAAqBC,EAC1B,OAGD,MAAM1I,EAAcrmD,EAAKqmD,YAKzB,GAAKA,EAAYv4B,cAAgBs3B,EAAcqB,WAAWkH,QAAStH,EAAalvC,EAAIhZ,MACnF,OAID,IAAM,MAAMU,KAASwnD,EACpB,IAAMjB,EAAcqB,WAAWkH,QAAS9uD,EAAM6D,KAAMyU,EAAIhZ,MACvD,OAIF,MAAM6lD,EAASoB,EAAcpB,OACvBqK,EAAajJ,EAAc/yB,OAGjCg8B,EAAWrqD,OAAQggD,EAAOD,eAAgBsC,EAAYnlC,OAAS4tC,GAC/D1J,EAAcpB,OAAOgL,oBAAqBF,EAAkB9uD,EAAKujD,YAG3D8C,EAAYv4B,cACjBugC,EAAWrqD,OAAQggD,EAAOD,eAAgBsC,EAAYllC,KAAO4tC,GAC7D3J,EAAcpB,OAAOgL,oBAAqBD,EAAgB/uD,EAAKujD,aAGhEpsC,EAAIhH,SAslBwE,CAAEW,SAAUoL,EAAO0xC,mBAAqB,WACpHvI,EAAW97B,GAAI,gBAAkBrN,EAAOmtC,OAAwBntC,EAAO6Z,KA5kBjE,CAAE5e,EAAKnX,EAAMolD,KACnB,MAAM3B,EAAW2B,EAAcpB,OAAOiL,qBAAsBjvD,EAAKujD,YAEjE,GAAME,EAAN,CAIA,IAAM,MAAMxkC,KAAWwkC,EACtB2B,EAAcpB,OAAOkL,4BAA6BjwC,EAASjf,EAAKujD,YAChE6B,EAAc/yB,OAAOzoB,MAAOw7C,EAAc/yB,OAAO+0B,cAAenoC,GAAWA,GAG5EmmC,EAAc/yB,OAAO88B,yBAA0BnvD,EAAKujD,YAEpDpsC,EAAIhH,UA8jB2E,CAAEW,SAAUoL,EAAO0xC,mBAAqB,YA3nCtGwB,CAAyBlzC,IA6D3C,kBAAmBA,GAClB,OAAO7b,KAAK4O,IAumCd,SAAoCiN,GACnC,OAAOmpC,IA9UR,IAAwBgK,EA+UtBhK,EAAW97B,GAAI,aAAerN,EAAOmtC,OA/UfgG,EA+UqCnzC,EAAO6Z,KA9U5D,CAAE5e,EAAKnX,EAAMolD,KACnB,IAAMplD,EAAK0C,KACV,OAGD,KAAQ1C,EAAK0C,gBAAgB,IAAkB1C,EAAK0C,gBAAgB,IAAwB1C,EAAK0C,KAAKlC,GAAI,eACzG,OAGD,MAAM8uD,EAAaC,GAAmBF,EAAqBrvD,EAAMolD,GAEjE,IAAMkK,EACL,OAGD,IAAMlK,EAAcqB,WAAWkH,QAAS3tD,EAAK0C,KAAMyU,EAAIhZ,MACtD,OAGD,MAAMkwD,EAAajJ,EAAc/yB,OAC3B8I,EAAcq0B,GAA0CnB,EAAYiB,GACpEz0B,EAAgBwzB,EAAWhtD,SAASopB,UAE1C,GAAKzqB,EAAK0C,gBAAgB,IAAkB1C,EAAK0C,gBAAgB,GAChE2rD,EAAW1xB,KAAM9B,EAAcjL,gBAAiBuL,EAAaN,OACvD,CACN,MAAM+O,EAAYwb,EAAcpB,OAAOsK,YAAatuD,EAAKsvB,OACnDmgC,EAAiBpB,EAAW1xB,KAAMiN,EAAWzO,GAEnD,IAAM,MAAMlc,KAAWwwC,EAAe9H,WACrC,GAAK1oC,EAAQze,GAAI,qBAAwBye,EAAQ+S,UAAWmJ,GAAgB,CAC3EiqB,EAAcpB,OAAOgL,oBAAqB/vC,EAASjf,EAAKujD,YAIxD,UA2SuE,CAAEzyC,SAAUoL,EAAO0xC,mBAAqB,WAClHvI,EAAW97B,GAAI,aAAerN,EAAOmtC,MAnRvC,SAA2BgG,GAC1B,MAAO,CAAEl4C,EAAKnX,EAAMolD,KACnB,IAAMplD,EAAK0C,KACV,OAGD,KAAQ1C,EAAK0C,gBAAgB,IAC5B,OAGD,MAAM4sD,EAAaC,GAAmBF,EAAqBrvD,EAAMolD,GAEjE,IAAMkK,EACL,OAGD,IAAMlK,EAAcqB,WAAWj8C,KAAMxK,EAAK0C,KAAMyU,EAAIhZ,MACnD,OAGD,MAAMg9B,EAAciqB,EAAcpB,OAAOR,cAAexjD,EAAK0C,MAE7D,GAAKy4B,GAAeA,EAAYtQ,kBAAmB,gBAAmB,CAErEu6B,EAAcqB,WAAWkH,QAAS3tD,EAAK0C,KAAMyU,EAAIhZ,MAGjD,IAAM,MAAMU,KAAS,GAAWoyB,UAAWjxB,EAAK0C,MAC/C0iD,EAAcqB,WAAWkH,QAAS9uD,EAAM6D,KAAMyU,EAAIhZ,MAGnDg9B,EAAYtQ,kBAAmB,eAA/BsQ,CAAiDA,EAAam0B,EAAYlK,EAAc/yB,QAExF+yB,EAAcpB,OAAOgL,oBAAqB7zB,EAAan7B,EAAKujD,cAkPjBmM,CAAkBxzC,EAAO6Z,MAAQ,CAAEjlB,SAAUoL,EAAO0xC,mBAAqB,WACrHvI,EAAW97B,GAAI,gBAAkBrN,EAAOmtC,MAxN1C,SAA0BgG,GACzB,MAAO,CAAEl4C,EAAKnX,EAAMolD,KAEnB,GAAKplD,EAAKqmD,YAAYv4B,YACrB,OAGD,MAAMwhC,EAAaC,GAAmBF,EAAqBrvD,EAAMolD,GAEjE,IAAMkK,EACL,OAID,MAAMK,EAAuBH,GAA0CpK,EAAc/yB,OAAQi9B,GAGvF7L,EAAW2B,EAAcpB,OAAOiL,qBAAsBjvD,EAAKujD,YAEjE,GAAME,EAAN,CAIA,IAAM,MAAMxkC,KAAWwkC,EACtB2B,EAAcpB,OAAOkL,4BAA6BjwC,EAASjf,EAAKujD,YAE3DtkC,EAAQze,GAAI,oBAChB4kD,EAAc/yB,OAAOk8B,OAAQnJ,EAAc/yB,OAAO+0B,cAAenoC,GAAW0wC,GAG5E1wC,EAAQ4L,kBAAmB,kBAA3B5L,CAAgDA,EAASqwC,EAAW3sD,GAAIyiD,EAAc/yB,QAIxF+yB,EAAc/yB,OAAO88B,yBAA0BnvD,EAAKujD,YAEpDpsC,EAAIhH,SAoL2Cy/C,CAAiB1zC,EAAO6Z,MAAQ,CAAEjlB,SAAUoL,EAAO0xC,mBAAqB,YA3mCtGiC,CAA2B3zC,IAkH7C,aAAcA,GACb,OAAO7b,KAAK4O,IAu9Bd,SAA+BiN,GAG9B,MAAMyhB,GAFNzhB,EAAS,GAAWA,IAECmtC,MAGfntC,EAAO6Z,OACZ7Z,EAAO6Z,KAAOwtB,IAAc,CAC3B5lB,QACAx/B,KAAMolD,EAAW7wC,OAAQwJ,EAAOmtC,MAAMjnD,OAAS,MAIjD,OAAOijD,IA5kBR,IAA2ByK,EA6kBzBzK,EAAW97B,GAAI,aAAeoU,GA7kBLmyB,EA6kB8B5zC,EAAO6Z,KA5kBxD,CAAE5e,EAAKnX,EAAMolD,KACnB,MAAM2K,EAAiBD,EAAa9vD,EAAKujD,WAAY6B,GAErD,IAAM2K,EACL,OAGD,MAAM1J,EAAcrmD,EAAKqmD,YAEnBjB,EAAcqB,WAAWkH,QAAStH,EAAalvC,EAAIhZ,QAKzD6xD,GAAsB3J,GAAa,EAAOjB,EAAeplD,EAAM+vD,GAC/DC,GAAsB3J,GAAa,EAAMjB,EAAeplD,EAAM+vD,GAE9D54C,EAAIhH,UA2jBkE,CAAEW,SAAUoL,EAAO0xC,mBAAqB,WAC9GvI,EAAW97B,GAAI,gBAAkBoU,EA7fnC,SAA2BmyB,GAC1B,MAAO,CAAE34C,EAAKnX,EAAMolD,KACnB,MAAM6K,EAAWH,EAAa9vD,EAAKujD,WAAY6B,GAE/C,IAAM6K,EACL,OAGD,MAAMxM,EAAW2B,EAAcpB,OAAOiL,qBAAsBjvD,EAAKujD,YAEjE,GAAME,EAAN,CAIA,IAAM,MAAMxkC,KAAWwkC,EACtB2B,EAAcpB,OAAOkL,4BAA6BjwC,EAASjf,EAAKujD,YAE3DtkC,EAAQze,GAAI,qBAChB0vD,EAA2B,QAASD,EAAStyB,qBAAuB1e,GACpEixC,EAA2B,QAASD,EAAStyB,oBAAsB1e,GACnEixC,EAA2B,QAASD,EAAStyB,mBAAqB1e,GAClEixC,EAA2B,QAASD,EAAStyB,kBAAoB1e,IAEjEmmC,EAAc/yB,OAAOzoB,MAAOw7C,EAAc/yB,OAAO+0B,cAAenoC,GAAWA,GAI7EmmC,EAAc/yB,OAAO88B,yBAA0BnvD,EAAKujD,YAEpDpsC,EAAIhH,OAEJ,SAAS+/C,EAA2BC,EAAelxC,GAClD,GAAKA,EAAQM,aAAc4wC,GAAkB,CAC5C,MAAMvM,EAAc,IAAIlrC,IAAKuG,EAAQQ,aAAc0wC,GAAgBvgD,MAAO,MAC1Eg0C,EAAYxvC,OAAQ67C,EAAS9xD,MAEJ,GAApBylD,EAAYv6C,KAChB+7C,EAAc/yB,OAAOptB,gBAAiBkrD,EAAelxC,GAErDmmC,EAAc/yB,OAAOtuB,aAAcosD,EAAe3mD,MAAMiK,KAAMmwC,GAAct/C,KAAM,KAAO2a,MAsdpDmxC,CAAkBl0C,EAAO6Z,MAAQ,CAAEjlB,SAAUoL,EAAO0xC,mBAAqB,YAt+BhGyC,CAAsBn0C,KAiElC,SAASszC,GAA0Cn9B,EAAQi9B,GACjE,MAAMn0B,EAAc9I,EAAOmK,uBAAwB,OAAQ8yB,EAAW3rD,YAYtE,OAVK2rD,EAAWtwC,SACfmc,EAAYlD,UAAWq3B,EAAWtwC,SAG9BswC,EAAWx+C,WACfqqB,EAAY5I,UAAY+8B,EAAWx+C,UAGpCqqB,EAAY3I,IAAM88B,EAAW3sD,GAEtBw4B,EAiWR,SAAS60B,GAAsB1gC,EAAOghC,EAASlL,EAAeplD,EAAM+vD,GACnE,MAAMjN,EAAgBwN,EAAUhhC,EAAMpO,MAAQoO,EAAMnO,IAGpD,GAFyBikC,EAAckE,OAAOiH,WAAYzN,EAAe,SAEjD,EAyCzB,SAAgC53B,EAAUolC,EAASlL,EAAeplD,EAAM+vD,GACvE,MAAM3L,EAAkB,GAAI2L,EAAepyB,SAAW2yB,EAAU,QAAU,QAEpEzqC,EAAQkqC,EAAe5xD,KAAO,CAAE,KAAQ4xD,EAAe5xD,MAAS,KAChEg9B,EAAciqB,EAAc/yB,OAAOm+B,gBAAiBpM,EAAiBv+B,GAE3Eu/B,EAAc/yB,OAAOruB,OAAQknB,EAAUiQ,GACvCiqB,EAAcpB,OAAOgL,oBAAqB7zB,EAAan7B,EAAKujD,YA7C3DkN,CAFqBrL,EAAcpB,OAAOD,eAAgBjB,GAErBwN,EAASlL,EAAeplD,EAAM+vD,OAC7D,CACN,IAAI1M,EACAnlC,EAOCoyC,GAAWxN,EAAcr1B,YAAc6iC,IAAYxN,EAAcn1B,YACrE01B,EAAeP,EAAcr1B,UAC7BvP,GAAW,IAEXmlC,EAAeP,EAAcn1B,WAC7BzP,GAAW,IAUd,SAAkCid,EAAam1B,EAASpyC,EAAUknC,EAAeplD,EAAM+vD,GACtF,MAAMI,EAAgB,QAASJ,EAAepyB,SAAW2yB,EAAU,QAAU,SAAWpyC,EAAW,SAAW,UAExG0lC,EAAczoB,EAAY5b,aAAc4wC,GAAkBh1B,EAAY1b,aAAc0wC,GAAgBvgD,MAAO,KAAQ,GAGzHg0C,EAAYpmC,QAASuyC,EAAe5xD,MAEpCinD,EAAc/yB,OAAOtuB,aAAcosD,EAAevM,EAAYt/C,KAAM,KAAO62B,GAC3EiqB,EAAcpB,OAAOgL,oBAAqB7zB,EAAan7B,EAAKujD,YAd3DmN,CAFoBtL,EAAcpB,OAAOR,cAAeH,GAElBiN,EAASpyC,EAAUknC,EAAeplD,EAAM+vD,IAwjBhF,SAAStC,GAA0B13B,EAAM46B,GACxC,MAAoB,mBAAR56B,EAEJA,EAGD,CAAE66B,EAAWxL,IASrB,SAA0CyL,EAAuBzL,EAAeuL,GAC1C,iBAAzBE,IAEXA,EAAwB,CAAE1yD,KAAM0yD,IAGjC,IAAI5xC,EACJ,MAAMovC,EAAajJ,EAAc/yB,OAC3B1uB,EAAarF,OAAO4nC,OAAQ,GAAI2qB,EAAsBltD,YAE5D,GAAwB,aAAnBgtD,EACJ1xC,EAAUovC,EAAWyC,uBAAwBD,EAAsB1yD,KAAMwF,QACnE,GAAwB,aAAnBgtD,EAAiC,CAC5C,MAAMpuD,EAAU,CACfuO,SAAU+/C,EAAsB//C,UAAY,GAAqB6hB,kBAGlE1T,EAAUovC,EAAW7xB,uBAAwBq0B,EAAsB1yD,KAAMwF,EAAYpB,QAGrF0c,EAAUovC,EAAWmC,gBAAiBK,EAAsB1yD,KAAMwF,GAGnE,GAAKktD,EAAsB/wC,OAAS,CACnC,MAAMjc,EAAOvF,OAAOuF,KAAMgtD,EAAsB/wC,QAEhD,IAAM,MAAM3gB,KAAO0E,EAClBwqD,EAAWtxB,SAAU59B,EAAK0xD,EAAsB/wC,OAAQ3gB,GAAO8f,GAIjE,GAAK4xC,EAAsB7xC,QAAU,CACpC,MAAMA,EAAU6xC,EAAsB7xC,QAEtC,GAAuB,iBAAXA,EACXqvC,EAAWrxB,SAAUhe,EAASC,QAE9B,IAAM,MAAMwH,KAAazH,EACxBqvC,EAAWrxB,SAAUvW,EAAWxH,GAKnC,OAAOA,EApDgC8xC,CAAiCh7B,EAAMqvB,EAAeuL,GAuD9F,SAASzC,GAAyBhyC,GACjC,OAAKA,EAAOmtC,MAAM38C,OACV,CAAEskD,EAAqB5L,KAC7B,MAAMrvB,EAAO7Z,EAAO6Z,KAAMi7B,GAE1B,OAAKj7B,EACGA,EAAMi7B,EAAqB5L,GAG5B,MAGDlpC,EAAO6Z,KAQhB,SAAS04B,GAA4B14B,GACpC,MAAoB,iBAARA,EACJi7B,IAAuB,CAAI7xD,IAAK42B,EAAMl3B,MAAOmyD,IAC1B,iBAARj7B,EAEbA,EAAKl3B,MACF,IAAMk3B,EAINi7B,IAAuB,CAAI7xD,IAAK42B,EAAK52B,IAAKN,MAAOmyD,IAIlDj7B,EAKT,SAASw5B,GAAmBF,EAAqBrvD,EAAMolD,GAEtD,MAAMkK,EAA2C,mBAAvBD,EACzBA,EAAqBrvD,EAAMolD,GAC3BiK,EAED,OAAMC,GAKAA,EAAWx+C,WAChBw+C,EAAWx+C,SAAW,IAIjBw+C,EAAW3sD,KAChB2sD,EAAW3sD,GAAK3C,EAAKujD,YAGf+L,GAbC,KC9lDF,SAAS2B,GAAyB5+B,GACxC,MAAM,OAAEi3B,EAAM,SAAEjoD,GAAagxB,EAAOg3B,MAEpC,IAAM,MAAMz+B,KAAYvpB,EAAS6vD,eAAiB,CACjD,MAAMh0D,EAAOmE,EAAS+7C,QAASxyB,GAE/B,GAAK1tB,EAAK4lB,UAAYwmC,EAAOiH,WAAYrzD,EAAM,UAEzCosD,EAAOiH,WAAYrzD,EAAM,aAM7B,OALAm1B,EAAO8+B,cAAe,YAAaj0D,IAK5B,EAKV,OAAO,EAWD,SAASk0D,GAAiBlmC,EAAUmmC,EAAY/H,GACtD,MAAMvpD,EAAUupD,EAAOgI,cAAepmC,GAGtC,QAAMo+B,EAAOiH,WAAYxwD,EAAS,gBAK5BupD,EAAOiH,WAAYxwD,EAAQuD,KAAM,aAAe+tD,GAehD,SAASE,GAAiBrmC,EAAUmH,GAC1C,MAAMm/B,EAAYn/B,EAAO3uB,cAAe,aAIxC,OAFA2uB,EAAOruB,OAAQwtD,EAAWtmC,GAEnBmH,EAAOo/B,iBAAkBD,EAAW,GCjD7B,MAAM,WAAsBnE,GAsD1C,iBAAkBnxC,GACjB,OAAO7b,KAAK4O,IAAKyiD,GAAwBx1C,IAsF1C,mBAAoBA,GACnB,OAAO7b,KAAK4O,IAsYd,SAAmCiN,GAGlCy1C,GAFAz1C,EAAS,GAAWA,IAIpB,MAAM01C,EAAYC,GAA6B31C,GAAQ,GAEjDgsC,EAAc4J,GAA8B51C,EAAO6Z,MACnD3jB,EAAY81C,EAAc,WAAaA,EAAc,UAE3D,OAAO7C,IACNA,EAAW97B,GAAInX,EAAWw/C,EAAW,CAAE9gD,SAAUoL,EAAO0xC,mBAAqB,SAjZ5DmE,CAA0B71C,IAyH5C,qBAAsBA,GACrB,OAAO7b,KAAK4O,IA0Sd,SAAqCiN,GACpCA,EAAS,GAAWA,GAEpB,IAAI81C,EAAU,MAEa,iBAAf91C,EAAO6Z,MAAoB7Z,EAAO6Z,KAAK52B,OAClD6yD,EAiNF,SAA+C91C,GACnB,iBAAfA,EAAO6Z,OAClB7Z,EAAO6Z,KAAO,CAAE52B,IAAK+c,EAAO6Z,OAG7B,MAAM52B,EAAM+c,EAAO6Z,KAAK52B,IACxB,IAAI8yD,EAEJ,GAAY,SAAP9yD,GAAyB,SAAPA,EAAiB,CAGvC8yD,EAAa,CACZ,CAHsB,SAAP9yD,EAAiB,UAAY,UAG/B+c,EAAO6Z,KAAKl3B,WAEpB,CACN,MAAMA,OAAoC,IAArBqd,EAAO6Z,KAAKl3B,MAAuB,UAAYqd,EAAO6Z,KAAKl3B,MAEhFozD,EAAa,CACZtuD,WAAY,CACX,CAAExE,GAAON,IAKPqd,EAAO6Z,KAAK53B,OAChB8zD,EAAW9zD,KAAO+d,EAAO6Z,KAAK53B,MAK/B,OAFA+d,EAAO6Z,KAAOk8B,EAEP9yD,EA/OI+yD,CAAsCh2C,IAGjDy1C,GAA+Bz1C,EAAQ81C,GAEvC,MAAMJ,EAAYC,GAA6B31C,GAAQ,GAEvD,OAAOmpC,IACNA,EAAW97B,GAAI,UAAWqoC,EAAW,CAAE9gD,SAAUoL,EAAO0xC,mBAAqB,SAxT5DuE,CAA4Bj2C,IAmD9C,gBAAiBA,GAUhB,OAFA,aAAY,+CAEL7b,KAAK4O,IAyQd,SAAgCiN,GAK/B,OAyUD,SAAyCA,GACxC,MAAMk2C,EAAWl2C,EAAOmtC,MAExBntC,EAAOmtC,MAAQ,CAAEluB,EAAaiqB,KAC7B,MAAM7B,EAAgC,iBAAZ6O,EAAuBA,EAAWA,EAAUj3B,EAAaiqB,GAEnF,OAAOA,EAAc/yB,OAAO3uB,cAAe,UAAW,CAAE,YAAa6/C,KAjVtE8O,CAFAn2C,EAAS,GAAWA,IAIbw1C,GAAwBx1C,GA9Qbo2C,CAAuBp2C,IAsEzC,aAAcA,GACb,OAAO7b,KAAK4O,IAmNd,SAA6BiN,IAC5BA,EAAS,GAAWA,IAGPmtC,QACZntC,EAAOmtC,MAAQlrD,GACPA,EAAO+d,EAAO6Z,KAAO,IAAM53B,EAAO+d,EAAO6Z,MAIlD,MAAMw8B,EAAiBC,GAA2BC,GAA6Bv2C,EAAQ,UACjFw2C,EAAeF,GAA2BC,GAA6Bv2C,EAAQ,QAErF,OAAOmpC,IACNA,EAAW97B,GAAI,WAAarN,EAAO6Z,KAAO,SAAUw8B,EAAgB,CAAEzhD,SAAUoL,EAAO0xC,mBAAqB,WAC5GvI,EAAW97B,GAAI,WAAarN,EAAO6Z,KAAO,OAAQ28B,EAAc,CAAE5hD,SAAUoL,EAAO0xC,mBAAqB,WAcxG,MAAM+E,EAAe,GAAWl0D,IAAK,OAC/Bm0D,EAAc,GAAWn0D,IAAK,WAC9Bo0D,EAAiB,GAAWp0D,IAAKyd,EAAO0xC,mBAAsBgF,EAEpEvN,EAAW97B,GAAI,UAcjB,SAAkCrN,GACjC,MAAO,CAAE/E,EAAKnX,EAAMolD,KACnB,MAAM0N,EAAW,QAAS52C,EAAO6Z,KA0BjC,SAASg9B,EAAmB7nC,EAAU8nC,GACrC,IAAM,MAAMC,KAAkBD,EAAkB,CAC/C,MAAMzP,EAAarnC,EAAOmtC,MAAO4J,EAAgB7N,GAC3CnmC,EAAUmmC,EAAc/yB,OAAO3uB,cAAe,UAAW,CAAE,YAAa6/C,IAE9E6B,EAAc/yB,OAAOruB,OAAQib,EAASiM,GAEjClrB,EAAKkzD,YAAYvmC,QAASzB,GAC9BlrB,EAAKkzD,YAAclzD,EAAKkzD,YAAYvkC,aAAc,GAElD3uB,EAAKkzD,YAAclzD,EAAKkzD,YAAY9S,2BAA4Bl1B,EAAU,GAG3ElrB,EAAK8jD,WAAa9jD,EAAK8jD,WAAW1D,2BAA4Bl1B,EAAU,GAAK,IAjCzElrB,EAAK8jD,aACV9jD,EAAO1B,OAAO4nC,OAAQlmC,EAAMolD,EAAc+N,gBAAiBnzD,EAAKozD,SAAUpzD,EAAKkzD,eAG3E9N,EAAcqB,WAAWkH,QAAS3tD,EAAKozD,SAAU,CAAEzvD,WAAYmvD,EAAW,gBAC9EC,EAAmB/yD,EAAK8jD,WAAW3iC,IAAKnhB,EAAKozD,SAAS3zC,aAAcqzC,EAAW,cAAeljD,MAAO,MAGjGw1C,EAAcqB,WAAWkH,QAAS3tD,EAAKozD,SAAU,CAAEzvD,WAAYmvD,EAAW,kBAC9EC,EAAmB/yD,EAAK8jD,WAAW3iC,IAAKnhB,EAAKozD,SAAS3zC,aAAcqzC,EAAW,gBAAiBljD,MAAO,MAGnGw1C,EAAcqB,WAAWkH,QAAS3tD,EAAKozD,SAAU,CAAEzvD,WAAYmvD,EAAW,iBAC9EC,EAAmB/yD,EAAK8jD,WAAW5iC,MAAOlhB,EAAKozD,SAAS3zC,aAAcqzC,EAAW,eAAgBljD,MAAO,MAGpGw1C,EAAcqB,WAAWkH,QAAS3tD,EAAKozD,SAAU,CAAEzvD,WAAYmvD,EAAW,mBAC9EC,EAAmB/yD,EAAK8jD,WAAW5iC,MAAOlhB,EAAKozD,SAAS3zC,aAAcqzC,EAAW,iBAAkBljD,MAAO,OAvCjFyjD,CAAyBn3C,GAAU,CAAEpL,SAAU6hD,EAAeE,KApPvES,CAAoBp3C,KAgHvC,SAASw1C,GAAwBx1C,GAGhC,MAAM01C,EAAYY,GAFlBt2C,EAAS,GAAWA,IAIdgsC,EAAc4J,GAA8B51C,EAAO6Z,MACnD3jB,EAAY81C,EAAc,WAAaA,EAAc,UAE3D,OAAO7C,IACNA,EAAW97B,GAAInX,EAAWw/C,EAAW,CAAE9gD,SAAUoL,EAAO0xC,mBAAqB,YA6L/E,SAASkE,GAA8ByB,GACtC,MAA0B,iBAAdA,EACJA,EAGkB,iBAAdA,GAAoD,iBAAnBA,EAAWp1D,KAChDo1D,EAAWp1D,KAGZ,KAOR,SAASq0D,GAA2Bt2C,GACnC,MAAMyK,EAAU,IAAI9H,GAAS3C,EAAO6Z,MAEpC,MAAO,CAAE5e,EAAKnX,EAAMolD,KACnB,MAAMoO,EAAgB7sC,EAAQ5K,MAAO/b,EAAKozD,UAE1C,IAAMI,EACL,OAGD,MAAMz3C,EAAQy3C,EAAcz3C,MAK5B,GAFAA,EAAM5d,MAAO,GAEPinD,EAAcqB,WAAWj8C,KAAMxK,EAAKozD,SAAUr3C,GACnD,OAGD,MAAMsnC,EAsBR,SAA0BgG,EAAO97C,EAAO63C,GACvC,OAAKiE,aAAiB/iD,SACd+iD,EAAO97C,EAAO63C,GAEdA,EAAc/yB,OAAO3uB,cAAe2lD,GA1BtBoK,CAAiBv3C,EAAOmtC,MAAOrpD,EAAKozD,SAAUhO,GAE7D/B,GAIA+B,EAAcsO,WAAYrQ,EAAcrjD,EAAKkzD,eAInD9N,EAAcqB,WAAWkH,QAAS3tD,EAAKozD,SAAUr3C,GACjDqpC,EAAc+N,gBAAiBnzD,EAAKozD,SAAU/P,GAC9C+B,EAAcuO,uBAAwBtQ,EAAcrjD,KAgEtD,SAAS2xD,GAA+Bz1C,EAAQ03C,EAAyB,MACxE,MAAMC,EAA+C,OAA3BD,GAAyCz4B,IAAeA,EAAY1b,aAAcm0C,IAEtGz0D,EAA6B,iBAAhB+c,EAAOmtC,MAAoBntC,EAAOmtC,MAAQntC,EAAOmtC,MAAMlqD,IACpEN,EAA+B,iBAAhBqd,EAAOmtC,YAAkD,IAAtBntC,EAAOmtC,MAAMxqD,MAAuBg1D,EAAoB33C,EAAOmtC,MAAMxqD,MAE7Hqd,EAAOmtC,MAAQ,CAAElqD,MAAKN,SAUvB,SAASgzD,GAA6B31C,EAAQmP,GAC7C,MAAM1E,EAAU,IAAI9H,GAAS3C,EAAO6Z,MAEpC,MAAO,CAAE5e,EAAKnX,EAAMolD,KACnB,MAAMrpC,EAAQ4K,EAAQ5K,MAAO/b,EAAKozD,UAGlC,IAAMr3C,EACL,OAGD,MAAM+3C,EAAW53C,EAAOmtC,MAAMlqD,IACxB8uD,EAA0C,mBAAtB/xC,EAAOmtC,MAAMxqD,MACtCqd,EAAOmtC,MAAMxqD,MAAOmB,EAAKozD,SAAUhO,GAAkBlpC,EAAOmtC,MAAMxqD,MAGnE,GAAoB,OAAfovD,EACJ,OAWD,IAwBF,SAAgCsF,EAAYH,GAE3C,MAAMW,EAAoC,mBAAdR,EAA2BA,EAAYH,GAAaG,EAEhF,GAA4B,iBAAhBQ,IAA6BjC,GAA8BiC,GACtE,OAAO,EAGR,OAAQA,EAAa/0C,UAAY+0C,EAAapwD,aAAeowD,EAAaj0C,OAxCpEk0C,CAAuB93C,EAAO6Z,KAAM/1B,EAAKozD,iBAItCr3C,EAAMA,MAAM5d,KAHnB4d,EAAMA,MAAM5d,MAAO,GAOdinD,EAAcqB,WAAWj8C,KAAMxK,EAAKozD,SAAUr3C,EAAMA,OACzD,OAKK/b,EAAK8jD,aAEV9jD,EAAO1B,OAAO4nC,OAAQlmC,EAAMolD,EAAc+N,gBAAiBnzD,EAAKozD,SAAUpzD,EAAKkzD,gBAoClF,SAAyBpP,EAAYmQ,EAAgB5oC,EAAS+5B,GAC7D,IAAIjjD,GAAS,EAGb,IAAM,MAAMyQ,KAAQpJ,MAAMiK,KAAMqwC,EAAW6D,SAAU,CAAEt8B,aACjD+5B,EAAckE,OAAO4K,eAAgBthD,EAAMqhD,EAAe90D,OAC9DimD,EAAc/yB,OAAOtuB,aAAckwD,EAAe90D,IAAK80D,EAAep1D,MAAO+T,GAE7EzQ,GAAS,GAIX,OAAOA,GA5CkBgyD,CAAgBn0D,EAAK8jD,WAAY,CAAE3kD,IAAK20D,EAAUj1D,MAAOovD,GAAc5iC,EAAS+5B,IAGvGA,EAAcqB,WAAWkH,QAAS3tD,EAAKozD,SAAUr3C,EAAMA,QA8D1D,SAAS02C,GAA6Bv2C,EAAQ5b,GAC7C,MAAM8zD,EAAoB,GAY1B,OATAA,EAAkBr+B,KAAO7Z,EAAO6Z,KAAO,IAAMz1B,EAE7C8zD,EAAkB/K,MAAQ,CAAEluB,EAAaiqB,KACxC,MAAM3a,EAAWtP,EAAY1b,aAAc,QACrC8jC,EAAarnC,EAAOmtC,MAAO5e,EAAU2a,GAE3C,OAAOA,EAAc/yB,OAAO3uB,cAAe,UAAW,CAAE,YAAa6/C,KAG/D6Q,ECr7BO,MAAM,GAOpB,YAAa/K,EAAOhjC,GAOnBhmB,KAAKgpD,MAAQA,EAQbhpD,KAAK01B,KAAO,IAAI,GAAM1P,GAQtBhmB,KAAK2jD,OAAS,IAAI,GAQlB3jD,KAAKg0D,mBAAqB,IAAI,GAAoB,CACjDrQ,OAAQ3jD,KAAK2jD,OACbsF,OAAQD,EAAMC,SAGf,MAAM7hB,EAAMpnC,KAAKgpD,MAAMhoD,SACjBopB,EAAYgd,EAAIhd,UAChB+6B,EAAUnlD,KAAKgpD,MAAM7D,QAO3BnlD,KAAKmR,SAAUnR,KAAKgpD,MAAO,iBAAkB,KAC5ChpD,KAAK01B,KAAKu+B,mBAAmB,IAC3B,CAAExjD,SAAU,YAEfzQ,KAAKmR,SAAUnR,KAAKgpD,MAAO,gBAAiB,KAC3ChpD,KAAK01B,KAAKu+B,mBAAmB,IAC3B,CAAExjD,SAAU,WAKfzQ,KAAKmR,SAAUi2B,EAAK,SAAU,KAC7BpnC,KAAK01B,KAAK0nB,OAAQprB,IACjBhyB,KAAKg0D,mBAAmBE,eAAgB9sB,EAAI8d,OAAQC,EAASnzB,GAC7DhyB,KAAKg0D,mBAAmBG,iBAAkB/pC,EAAW+6B,EAASnzB,MAE7D,CAAEvhB,SAAU,QAGfzQ,KAAKmR,SAAUnR,KAAK01B,KAAK10B,SAAU,kBDoZ9B,SAAiCgoD,EAAOrF,GAC9C,MAAO,CAAE7sC,EAAKnX,KACb,MAAM66B,EAAgB76B,EAAK22C,aAErBzoB,EAAS,GAEf,IAAM,MAAM0b,KAAa/O,EAActK,YACtCrC,EAAO5qB,KAAM0gD,EAAOyQ,aAAc7qB,IAGnC,MAAM8qB,EAAiBrL,EAAMsL,gBAAiBzmC,EAAQ,CAAE8C,SAAU6J,EAAcxK,aAE1EqkC,EAAe/nC,QAAS08B,EAAMhoD,SAASopB,YAC5C4+B,EAAM5L,OAAQprB,IACbA,EAAOyI,aAAc45B,MCla+BE,CAAwBv0D,KAAKgpD,MAAOhpD,KAAK2jD,SAG/F3jD,KAAKg0D,mBAAmB9qC,GAAI,eH0atB,CAAEpS,EAAKnX,EAAMolD,KACnB,IAAMA,EAAcqB,WAAWkH,QAAS3tD,EAAK0C,KAAM,UAClD,OAGD,MAAM2rD,EAAajJ,EAAc/yB,OAC3BwE,EAAeuuB,EAAcpB,OAAOD,eAAgB/jD,EAAKsvB,MAAMpO,OAC/DijB,EAAWkqB,EAAWwG,WAAY70D,EAAK0C,KAAK1C,MAElDquD,EAAWrqD,OAAQ6yB,EAAcsN,IGnbyB,CAAErzB,SAAU,WACtEzQ,KAAKg0D,mBAAmB9qC,GAAI,SH8btB,CAAEpS,EAAKnX,EAAMolD,KAEnB,MAAMla,EAAYka,EAAcpB,OAAOD,eAAgB/jD,EAAKkrB,UAEtD4pC,EAAW90D,EAAKkrB,SAASyD,aAAc3uB,EAAKoC,QAC5C+oC,EAAUia,EAAcpB,OAAOD,eAAgB+Q,EAAU,CAAE7Q,WAAW,IAEtEra,EAAYwb,EAAc/yB,OAAOsU,YAAauE,EAAWC,GAGzDh1B,EAAUivC,EAAc/yB,OAAO7tB,OAAQolC,EAAUnZ,cAIvD,IAAM,MAAM3J,KAASs+B,EAAc/yB,OAAO0iC,cAAe5+C,GAAUwxC,WAClEvC,EAAcpB,OAAOqD,kBAAmBvgC,IG7cO,CAAEhW,SAAU,QAG5DzQ,KAAKg0D,mBAAmB9qC,GAAI,YH4kBtB,CAAEpS,EAAKnX,EAAMolD,KACnB,MAAMiJ,EAAajJ,EAAc/yB,OAC3BwI,EAAgBwzB,EAAWhtD,SAASopB,UAE1C,IAAM,MAAM6E,KAASuL,EAActK,YAE7BjB,EAAMxB,aAELwB,EAAMnO,IAAI/D,OAAO43C,cACrB5P,EAAc/yB,OAAO2G,gBAAiB1J,EAAMpO,OAI/CmtC,EAAWvzB,aAAc,OGzlBmC,CAAEhqB,SAAU,QACxEzQ,KAAKg0D,mBAAmB9qC,GAAI,YHiftB,CAAEpS,EAAKnX,EAAMolD,KACnB,MAAM36B,EAAYzqB,EAAKyqB,UAEvB,GAAKA,EAAUqD,YACd,OAGD,IAAMs3B,EAAcqB,WAAWkH,QAASljC,EAAW,aAClD,OAGD,MAAMugB,EAAa,GAEnB,IAAM,MAAM1b,KAAS7E,EAAU8F,YAAc,CAC5C,MAAMqZ,EAAYwb,EAAcpB,OAAOsK,YAAah/B,GACpD0b,EAAW1nC,KAAMsmC,GAGlBwb,EAAc/yB,OAAOyI,aAAckQ,EAAY,CAAEha,SAAUvG,EAAU4F,cGngBH,CAAEvf,SAAU,QAC9EzQ,KAAKg0D,mBAAmB9qC,GAAI,YH6hBtB,CAAEpS,EAAKnX,EAAMolD,KACnB,MAAM36B,EAAYzqB,EAAKyqB,UAEvB,IAAMA,EAAUqD,YACf,OAGD,IAAMs3B,EAAcqB,WAAWkH,QAASljC,EAAW,aAClD,OAGD,MAAM4jC,EAAajJ,EAAc/yB,OAC3BywB,EAAgBr4B,EAAUoH,mBAC1BgF,EAAeuuB,EAAcpB,OAAOD,eAAgBjB,GACpDmS,EAAiB5G,EAAW6G,gBAAiBr+B,GAEnDw3B,EAAWvzB,aAAcm6B,IG7iB6C,CAAEnkD,SAAU,QAKlFzQ,KAAK01B,KAAK10B,SAAS6wB,MAAM3J,OAAQloB,KAAKgpD,MAAMhoD,SAAS6wB,OAAQlb,MAAO9Z,IAEnE,GAAsB,cAAjBA,EAAK0tB,SACT,OAAO,KAGR,MAAMuyB,EAAW,IAAI,GAAqB98C,KAAK01B,KAAK10B,SAAUnE,EAAKiB,MAKnE,OAHAg/C,EAASvyB,SAAW1tB,EAAK0tB,SACzBvqB,KAAK2jD,OAAOrgB,aAAczmC,EAAMigD,GAEzBA,IAkBT,UACC98C,KAAK01B,KAAKxb,UACVla,KAAKsR,iBAIPkD,GAAK,GAAmB,ICtIT,MAAM,GAIpB,cAOCxU,KAAK80D,UAAY,IAAIhhD,IAStB,IAAKihD,EAAaC,GACjBh1D,KAAK80D,UAAUrrD,IAAKsrD,EAAaC,GASlC,IAAKD,GACJ,OAAO/0D,KAAK80D,UAAU12D,IAAK22D,GAU5B,QAASA,KAAgB1jD,GACxB,MAAM2jD,EAAUh1D,KAAK5B,IAAK22D,GAE1B,IAAMC,EAOL,MAAM,IAAI,KAAe,sCAAuCh1D,KAAM,CAAE+0D,gBAGzE,OAAOC,EAAQC,WAAY5jD,GAQ5B,eACQrR,KAAK80D,UAAUtxD,OAQvB,kBACQxD,KAAK80D,UAAUzoD,SAUvB,CAAE/N,OAAOiW,YACR,OAAOvU,KAAK80D,UAAWx2D,OAAOiW,YAM/B,UACC,IAAM,MAAMygD,KAAWh1D,KAAKk1D,WAC3BF,EAAQ96C,WCtEI,MAAMi7C,GAIpB,cAUCn1D,KAAK0kB,aAAe,IAAI5Q,IA6BzB,IAAK8K,EAASw2C,GACb,IAAIC,EAGCz2C,EAAQze,GAAI,UAAaye,EAAQze,GAAI,oBACzCH,KAAK0kB,aAAajb,IAAKmV,GAAS,IAM3B5e,KAAK0kB,aAAahb,IAAKkV,GAI5By2C,EAAqBr1D,KAAK0kB,aAAatmB,IAAKwgB,IAH5Cy2C,EAAqB,IAAI,GAAwBz2C,GACjD5e,KAAK0kB,aAAajb,IAAKmV,EAASy2C,IAKjCA,EAAmBzmD,IAAKwmD,IAgCzB,KAAMx2C,EAASw2C,GACd,MAAMC,EAAqBr1D,KAAK0kB,aAAatmB,IAAKwgB,GAElD,YAA4BtY,IAAvB+uD,EACG,KAIHz2C,EAAQze,GAAI,UAAaye,EAAQze,GAAI,oBAClCk1D,EAIDA,EAAmBlrD,KAAMirD,GA+BjC,QAASx2C,EAASw2C,GACjB,QAAKp1D,KAAKmK,KAAMyU,EAASw2C,KACnBx2C,EAAQze,GAAI,UAAaye,EAAQze,GAAI,oBAEzCH,KAAK0kB,aAAajb,IAAKmV,GAAS,GAGhC5e,KAAK0kB,aAAatmB,IAAKwgB,GAAU0uC,QAAS8H,IAGpC,GAkCT,OAAQx2C,EAASw2C,GAChB,MAAMC,EAAqBr1D,KAAK0kB,aAAatmB,IAAKwgB,QAEtBtY,IAAvB+uD,IACCz2C,EAAQze,GAAI,UAAaye,EAAQze,GAAI,oBAEzCH,KAAK0kB,aAAajb,IAAKmV,GAAS,GAGhCy2C,EAAmBC,OAAQF,IAa9B,8BAA+Bx2C,GAC9B,MAAMw2C,EAAc,CACnBx2C,UACA9gB,MAAM,EACNwF,WAAY,GACZqb,QAAS,GACTc,OAAQ,IAGHnc,EAAasb,EAAQ4W,mBAE3B,IAAM,MAAMrW,KAAa7b,EAEN,SAAb6b,GAAqC,SAAbA,GAI7Bi2C,EAAY9xD,WAAWL,KAAMkc,GAG9B,MAAMR,EAAUC,EAAQU,gBAExB,IAAM,MAAM8G,KAAazH,EACxBy2C,EAAYz2C,QAAQ1b,KAAMmjB,GAG3B,MAAM3G,EAASb,EAAQ8D,gBAEvB,IAAM,MAAMtf,KAASqc,EACpB21C,EAAY31C,OAAOxc,KAAMG,GAG1B,OAAOgyD,EAcR,kBAAmBhiD,EAAMmiD,GAKxB,GAJMA,IACLA,EAAW,IAAIJ,GAAgB/hD,IAG3BA,EAAKjT,GAAI,SAGb,OAFAo1D,EAAS3mD,IAAKwE,GAEPmiD,EAIHniD,EAAKjT,GAAI,YACbo1D,EAAS3mD,IAAKwE,EAAM+hD,GAAeK,uBAAwBpiD,IAGvDA,EAAKjT,GAAI,qBACbo1D,EAAS3mD,IAAKwE,GAGf,IAAM,MAAMqT,KAASrT,EAAKsT,cACzB6uC,EAAWJ,GAAeM,WAAYhvC,EAAO8uC,GAG9C,OAAOA,GAUT,MAAM,GAOL,YAAaniD,GAKZpT,KAAK4e,QAAUxL,EAQfpT,KAAK01D,gBAAkB,KAQvB11D,KAAK0kB,aAAe,CACnBphB,WAAY,IAAIwQ,IAChB2L,OAAQ,IAAI3L,IACZ6K,QAAS,IAAI7K,KAyBf,IAAKshD,GACCA,EAAYt3D,OAChBkC,KAAK01D,iBAAkB,GAGxB,IAAM,MAAMz1D,KAAQD,KAAK0kB,aACnBzkB,KAAQm1D,GACZp1D,KAAK0Z,KAAMzZ,EAAMm1D,EAAan1D,IAyBjC,KAAMm1D,GAEL,GAAKA,EAAYt3D,OAASkC,KAAK01D,gBAC9B,OAAO11D,KAAK01D,gBAGb,IAAM,MAAMz1D,KAAQD,KAAK0kB,aACxB,GAAKzkB,KAAQm1D,EAAc,CAC1B,MAAM52D,EAAQwB,KAAK21D,MAAO11D,EAAMm1D,EAAan1D,IAE7C,IAAe,IAAVzB,EACJ,OAAOA,EAMV,OAAO,EAqBR,QAAS42D,GACHA,EAAYt3D,OAChBkC,KAAK01D,iBAAkB,GAGxB,IAAM,MAAMz1D,KAAQD,KAAK0kB,aACnBzkB,KAAQm1D,GACZp1D,KAAK41D,SAAU31D,EAAMm1D,EAAan1D,IAsBrC,OAAQm1D,GACFA,EAAYt3D,OAChBkC,KAAK01D,iBAAkB,GAGxB,IAAM,MAAMz1D,KAAQD,KAAK0kB,aACnBzkB,KAAQm1D,GACZp1D,KAAK61D,QAAS51D,EAAMm1D,EAAan1D,IAepC,KAAMA,EAAMoC,GACX,MAAMsT,EAAQ,GAAStT,GAASA,EAAO,CAAEA,GACnC+yD,EAAcp1D,KAAK0kB,aAAczkB,GAEvC,IAAM,MAAMnC,KAAQ6X,EAAQ,CAC3B,GAAc,eAAT1V,IAAoC,UAATnC,GAA6B,UAATA,GAenD,MAAM,IAAI,KAAe,mCAAoCkC,MAK9D,GAFAo1D,EAAY3rD,IAAK3L,GAAM,GAET,WAATmC,EACJ,IAAM,MAAMmlB,KAAYplB,KAAK4e,QAAQ5d,SAASglB,gBAAgB8vC,iBAAkBh4D,GAC/Es3D,EAAY3rD,IAAK2b,GAAU,IAe/B,MAAOnlB,EAAMoC,GACZ,MAAMsT,EAAQ,GAAStT,GAASA,EAAO,CAAEA,GACnC+yD,EAAcp1D,KAAK0kB,aAAczkB,GAEvC,IAAM,MAAMnC,KAAQ6X,EACnB,GAAc,eAAT1V,GAAoC,UAATnC,GAA6B,UAATA,EAS7C,CACN,MAAMU,EAAQ42D,EAAYh3D,IAAKN,GAE/B,QAAewI,IAAV9H,EACJ,OAAO,KAGR,IAAMA,EACL,OAAO,MAjBgE,CACxE,MAAMu3D,EAAyB,SAARj4D,EAAkB,UAAY,SAG/CU,EAAQwB,KAAK21D,MAAOI,EAAgB,IAAK/1D,KAAK0kB,aAAcqxC,GAAiBvyD,SAEnF,IAAe,IAAVhF,EACJ,OAAOA,EAeV,OAAO,EAUR,SAAUyB,EAAMoC,GACf,MAAMsT,EAAQ,GAAStT,GAASA,EAAO,CAAEA,GACnC+yD,EAAcp1D,KAAK0kB,aAAczkB,GAEvC,IAAM,MAAMnC,KAAQ6X,EACnB,GAAc,eAAT1V,GAAoC,UAATnC,GAA6B,UAATA,GAQnD,GAFAs3D,EAAY3rD,IAAK3L,GAAM,GAEV,UAARmC,EACJ,IAAM,MAAM+1D,KAAah2D,KAAK4e,QAAQ5d,SAASglB,gBAAgB8vC,iBAAkBh4D,GAChFs3D,EAAY3rD,IAAKusD,GAAW,OAV0C,CACxE,MAAMD,EAAyB,SAARj4D,EAAkB,UAAY,SAGrDkC,KAAK41D,SAAUG,EAAgB,IAAK/1D,KAAK0kB,aAAcqxC,GAAiBvyD,UAoB3E,QAASvD,EAAMoC,GACd,MAAMsT,EAAQ,GAAStT,GAASA,EAAO,CAAEA,GACnC+yD,EAAcp1D,KAAK0kB,aAAczkB,GAEvC,IAAM,MAAMnC,KAAQ6X,EACnB,GAAc,eAAT1V,GAAoC,UAATnC,GAA6B,UAATA,EAK7C,EAGS,IAFDs3D,EAAYh3D,IAAKN,IAG9Bs3D,EAAY3rD,IAAK3L,GAAM,OATgD,CACxE,MAAMi4D,EAAyB,SAARj4D,EAAkB,UAAY,SAGrDkC,KAAK61D,QAASE,EAAgB,IAAK/1D,KAAK0kB,aAAcqxC,GAAiBvyD,WClkB5D,MAAM,GAIpB,cACCxD,KAAKi2D,mBAAqB,GAQ1Bj2D,KAAKk2D,qBAAuB,GAE5Bl2D,KAAKm2D,SAAU,cACfn2D,KAAKm2D,SAAU,kBAEfn2D,KAAKkpB,GAAI,iBAAkB,CAAEpS,EAAKzF,KACjCA,EAAM,GAAM,IAAI+kD,GAAe/kD,EAAM,KACnC,CAAEZ,SAAU,YAEfzQ,KAAKkpB,GAAI,aAAc,CAAEpS,EAAKzF,KAC7BA,EAAM,GAAM,IAAI+kD,GAAe/kD,EAAM,IACrCA,EAAM,GAAMrR,KAAKq2D,cAAehlD,EAAM,KACpC,CAAEZ,SAAU,YAahB,SAAU6lD,EAAUC,GACnB,GAAKv2D,KAAKi2D,mBAAoBK,GAoB7B,MAAM,IAAI,KACT,oCACAt2D,KACA,CACCs2D,aAKHt2D,KAAKi2D,mBAAoBK,GAAa,CACrCr4D,OAAO4nC,OAAQ,GAAI0wB,IAGpBv2D,KAAKw2D,cA2BN,OAAQF,EAAUC,GACjB,IAAMv2D,KAAKi2D,mBAAoBK,GAU9B,MAAM,IAAI,KAAe,oCAAqCt2D,KAAM,CACnEs2D,aAIFt2D,KAAKi2D,mBAAoBK,GAAWrzD,KAAMhF,OAAO4nC,OAAQ,GAAI0wB,IAE7Dv2D,KAAKw2D,cAaN,iBAKC,OAJMx2D,KAAKy2D,sBACVz2D,KAAK02D,WAGC12D,KAAKy2D,qBAcb,cAAep0D,GACd,IAAIi0D,EAYJ,OATCA,EADmB,iBAARj0D,EACAA,EACAA,EAAKlC,KAAQkC,EAAKlC,GAAI,UAAakC,EAAKlC,GAAI,eAC5C,QAIAkC,EAAKvE,KAGVkC,KAAK22D,iBAAkBL,GAY/B,aAAcj0D,GACb,QAASrC,KAAKq2D,cAAeh0D,GAkB9B,QAASA,GACR,MAAMu0D,EAAM52D,KAAKq2D,cAAeh0D,GAEhC,SAAWu0D,IAAOA,EAAI1N,SAsBvB,QAAS7mD,GACR,MAAMu0D,EAAM52D,KAAKq2D,cAAeh0D,GAEhC,QAAMu0D,MAIKA,EAAIxN,UAAWwN,EAAI9J,UAsB/B,SAAUzqD,GACT,MAAMu0D,EAAM52D,KAAKq2D,cAAeh0D,GAEhC,QAAMu0D,MAMKA,EAAI9J,UAAc8J,EAAIxN,SAAWwN,EAAIC,cAAgBD,EAAIE,WAkBrE,SAAUz0D,GACT,MAAMu0D,EAAM52D,KAAKq2D,cAAeh0D,GAEhC,SAAWu0D,IAAOA,EAAI/J,UAoBvB,aAAcxqD,GACb,MAAMu0D,EAAM52D,KAAKq2D,cAAeh0D,GAEhC,QAAMu0D,MAIKA,EAAIC,eAAgBD,EAAI9J,UAoBpC,UAAWzqD,GACV,MAAMu0D,EAAM52D,KAAKq2D,cAAeh0D,GAEhC,QAAMu0D,MAIKA,EAAIE,YAAaF,EAAI9J,UAsBjC,WAAYptD,EAASk3D,GAEpB,QAAMA,GAIC52D,KAAK+2D,mBAAoBH,EAAKl3D,GAkBtC,eAAgBA,EAASowD,GACxB,MAAM8G,EAAM52D,KAAKq2D,cAAe32D,EAAQ2vB,MAExC,QAAMunC,GAICA,EAAII,gBAAgB59C,SAAU02C,GAmBtC,WAAYmH,EAAuBC,EAAiB,MACnD,GAAKD,aAAiC,GAAW,CAChD,MAAM3pC,EAAa2pC,EAAsB3pC,WACnCF,EAAY6pC,EAAsB7pC,UAExC,KAAQE,aAAsB,IAM7B,MAAM,IAAI,KACT,uCACAttB,MAIF,KAAQotB,aAAqB,IAM5B,MAAM,IAAI,KACT,sCACAptB,MAIF,OAAOA,KAAKm3D,WAAY7pC,EAAYF,GAGrC,IAAM,MAAM3G,KAASywC,EAAexwC,cACnC,IAAM1mB,KAAKkwD,WAAY+G,EAAuBxwC,GAC7C,OAAO,EAIT,OAAO,EA0CR,cAAevV,GACdlR,KAAKkpB,GAAI,aAAc,CAAEpS,GAAOX,EAAKihD,MAIpC,IAAMA,EACL,OAGD,MAAMC,EAAWnmD,EAAUiF,EAAKihD,GAER,kBAAZC,IACXvgD,EAAIhH,OACJgH,EAAIpD,OAAS2jD,IAEZ,CAAE5mD,SAAU,SA0ChB,kBAAmBS,GAClBlR,KAAKkpB,GAAI,iBAAkB,CAAEpS,GAAOX,EAAK25C,MACxC,MAAMuH,EAAWnmD,EAAUiF,EAAK25C,GAER,kBAAZuH,IACXvgD,EAAIhH,OACJgH,EAAIpD,OAAS2jD,IAEZ,CAAE5mD,SAAU,SAyChB,uBAAwBq/C,EAAenoC,GACtC3nB,KAAKk2D,qBAAsBpG,GAAkB7xD,OAAO4nC,OAAQ7lC,KAAKs3D,uBAAwBxH,GAAiBnoC,GAS3G,uBAAwBmoC,GACvB,OAAO9vD,KAAKk2D,qBAAsBpG,IAAmB,GAatD,gBAAiByH,GAChB,IAAI34C,EAEJ,GAAK24C,aAAsC,GAC1C34C,EAAU24C,EAA2Bx6C,WAC/B,CAMN6B,GALe24C,aAAsC,GACpD,CAAEA,GACFpuD,MAAMiK,KAAMmkD,EAA2BrnC,cAItC7Y,OAAQ,CAAEuH,EAASqQ,KACnB,MAAMuoC,EAAsBvoC,EAAMhB,oBAElC,OAAMrP,EAICA,EAAQqP,kBAAmBupC,EAAqB,CAAEp6C,aAAa,IAH9Do6C,GAIN,MAGL,MAASx3D,KAAKopD,QAASxqC,IACjBA,EAAQ7B,QACZ6B,EAAUA,EAAQ7B,OAMpB,OAAO6B,EAeR,0BAA2BwL,EAAWjL,GACrC,GAAKiL,EAAUqD,YAAc,CAC5B,MACM/tB,EAAU,IADM0qB,EAAUoH,mBAEdhU,eACjB,IAAI,GAAM,GAAI4M,EAAU2Q,kBAIzB,OAAO/6B,KAAK6zD,eAAgBn0D,EAASyf,GAC/B,CACN,MAAM0O,EAASzD,EAAU8F,YAGzB,IAAM,MAAMjB,KAASpB,EACpB,IAAM,MAAMrvB,KAASywB,EACpB,GAAKjvB,KAAK6zD,eAAgBr1D,EAAM6D,KAAM8c,GAErC,OAAO,EAOX,OAAO,EAUR,gBAAkB0O,EAAQ1O,GACzB0O,EAyhCF,UAAsCA,GACrC,IAAM,MAAMoB,KAASpB,QACboB,EAAMwoC,uBA3hCJC,CAA4B7pC,GAErC,IAAM,MAAMoB,KAASpB,QACb7tB,KAAK23D,wBAAyB1oC,EAAO9P,GAwB9C,yBAA0B0L,EAAUD,EAAY,QAE/C,GAAK5qB,KAAKkwD,WAAYrlC,EAAU,SAC/B,OAAO,IAAI,GAAOA,GAGnB,IAAI+sC,EAAgBC,EAGpB,MAAMC,EAAejtC,EAASrN,eAAesiB,UAAU1pB,KAAM/T,GAAQrC,KAAKopD,QAAS/mD,KAAYwoB,EAAShuB,KAEtF,QAAb+tB,GAAoC,YAAbA,IAC3BgtC,EAAiB,IAAI,GAAY,CAChCltC,WAAY,GAAMkG,UAAWknC,GAC7BntC,cAAeE,EACfD,UAAW,cAIK,QAAbA,GAAoC,WAAbA,IAC3BitC,EAAgB,IAAI,GAAY,CAC/BntC,WAAY,GAAMkG,UAAWknC,GAC7BntC,cAAeE,KAIjB,IAAM,MAAMlrB,KA+7Bd,UAA0BgxB,EAAUonC,GACnC,IAAI1sC,GAAO,EAEX,MAASA,GAAO,CAGf,GAFAA,GAAO,EAEFsF,EAAW,CACf,MAAMqnC,EAAOrnC,EAASpF,OAEhBysC,EAAK3sC,OACVA,GAAO,OACD,CACL2O,OAAQrJ,EACRnyB,MAAOw5D,EAAKx5D,QAKf,GAAKu5D,EAAU,CACd,MAAMC,EAAOD,EAAQxsC,OAEfysC,EAAK3sC,OACVA,GAAO,OACD,CACL2O,OAAQ+9B,EACRv5D,MAAOw5D,EAAKx5D,UAx9BKy5D,CAAgBL,EAAgBC,GAAkB,CACrE,MAAM53D,EAASN,EAAKq6B,QAAU49B,EAAiB,aAAe,eACxDp5D,EAAQmB,EAAKnB,MAEnB,GAAKA,EAAMyB,MAAQA,GAAQD,KAAK8sD,SAAUtuD,EAAM6D,MAC/C,OAAO,GAAMwuB,UAAWryB,EAAM6D,MAG/B,GAAKrC,KAAKkwD,WAAY1xD,EAAM6tB,aAAc,SACzC,OAAO,IAAI,GAAO7tB,EAAM6tB,cAI1B,OAAO,KAaR,kBAAmBxB,EAAUtY,GAC5B,IAAIwK,EAAS8N,EAAS9N,OAEtB,KAAQA,GAAS,CAChB,GAAK/c,KAAKkwD,WAAYnzC,EAAQxK,GAC7B,OAAOwK,EAIR,GAAK/c,KAAKopD,QAASrsC,GAClB,OAAO,KAGRA,EAASA,EAAOA,OAGjB,OAAO,KASR,2BAA4BgK,EAAOiL,GAClC,IAAM,MAAMzf,KAAQwU,EAEnB,GAAKxU,EAAKpS,GAAI,SACb+3D,GAAmCl4D,KAAMuS,EAAMyf,OAM3C,CACJ,MACMmmC,EADc,GAAMvnC,UAAWre,GACA6lD,eAErC,IAAM,MAAMvtC,KAAYstC,EAAmB,CAG1CD,GAAmCl4D,KAFtB6qB,EAASyC,YAAczC,EAAS9N,OAEEiV,KAYnD,cAAetyB,GACd,OAAO,IAAI02D,GAAe12D,GAM3B,cACCM,KAAKy2D,qBAAuB,KAM7B,WACC,MAAM4B,EAAsB,GACtBC,EAAct4D,KAAKi2D,mBACnBsC,EAAYt6D,OAAOuF,KAAM80D,GAE/B,IAAM,MAAMhC,KAAYiC,EACvBF,EAAqB/B,GAAakC,GAAqBF,EAAahC,GAAYA,GAGjF,IAAM,MAAMA,KAAYiC,EACvBE,GAAuBJ,EAAqB/B,GAG7C,IAAM,MAAMA,KAAYiC,EACvBG,GAAmBL,EAAqB/B,GAGzC,IAAM,MAAMA,KAAYiC,EACvBI,GAA0BN,EAAqB/B,GAC/CsC,GAA8BP,EAAqB/B,GAGpD,IAAM,MAAMA,KAAYiC,EACvBM,GAAgBR,EAAqB/B,GACrCwC,GAAwBT,EAAqB/B,GAG9Ct2D,KAAKy2D,qBAAuB4B,EAS7B,mBAAoBzB,EAAKl3D,EAASq5D,EAAmBr5D,EAAQqC,OAAS,GACrE,MAAMi3D,EAAct5D,EAAQu5D,QAASF,GAErC,GAAKnC,EAAIsC,QAAQ9/C,SAAU4/C,EAAYl7D,MAAS,CAC/C,GAAyB,GAApBi7D,EACJ,OAAO,EACD,CACN,MAAMI,EAAan5D,KAAKq2D,cAAe2C,GAEvC,OAAOh5D,KAAK+2D,mBAAoBoC,EAAYz5D,EAASq5D,EAAmB,IAGzE,OAAO,EAeT,yBAA2B9pC,EAAO9P,GACjC,IAAI0B,EAAQoO,EAAMpO,MACdC,EAAMmO,EAAMpO,MAEhB,IAAM,MAAMxe,KAAQ4sB,EAAMq4B,SAAU,CAAEt8B,SAAS,IACzC3oB,EAAKlC,GAAI,mBACNH,KAAK23D,wBAAyB,GAAM/mC,UAAWvuB,GAAQ8c,IAGzDnf,KAAK6zD,eAAgBxxD,EAAM8c,KAC1B0B,EAAMyL,QAASxL,WACd,IAAI,GAAOD,EAAOC,IAGzBD,EAAQ,GAASgL,aAAcxpB,IAGhCye,EAAM,GAAS+K,aAAcxpB,GAGxBwe,EAAMyL,QAASxL,WACd,IAAI,GAAOD,EAAOC,KAK3BtM,GAAK,GAAQ,IA0VN,MAAM4hD,GAMZ,YAAa12D,GACZ,GAAKA,aAAmB02D,GACvB,OAAO12D,EAGe,iBAAXA,EACXA,EAAU,CAAEA,GACAyJ,MAAMgC,QAASzL,KAG3BA,EAAUA,EAAQ8d,aAAc,CAAEJ,aAAa,KAG3C1d,EAAS,IAA8B,iBAAhBA,EAAS,IAAmBA,EAAS,GAAIS,GAAI,qBACxET,EAAQ+sB,QAGTzsB,KAAKiV,OAASvV,EAAQ2K,IAAK+uD,IAQ5B,aACC,OAAOp5D,KAAKiV,OAAOlT,OAQpB,WACC,OAAO/B,KAAKiV,OAAQjV,KAAKiV,OAAOlT,OAAS,GAU1C,CAAEzD,OAAOiW,YACR,OAAOvU,KAAKiV,OAAQ3W,OAAOiW,YA4B5B,KAAMlS,GACL,MAAM8T,EAAM,IAAIigD,GAAe,CAAE/zD,IAIjC,OAFA8T,EAAIlB,OAAS,IAAKjV,KAAKiV,UAAWkB,EAAIlB,QAE/BkB,EAQR,QAASzT,GACR,OAAO1C,KAAKiV,OAAQvS,GAQrB,kBACQ1C,KAAKiV,OAAO5K,IAAKhI,GAAQA,EAAKvE,MAgBtC,SAAUu7D,GACT,OAAOlwD,MAAMiK,KAAMpT,KAAKs5D,YAAar1D,KAAM,KAAMs1D,SAAUF,GAgB5D,WAAYA,GACX,OAAOlwD,MAAMiK,KAAMpT,KAAKs5D,YAAar1D,KAAM,KAAMwmD,WAAY4O,IA6G/D,SAASb,GAAqBgB,EAAiBlD,GAC9C,MAAMmD,EAAW,CAChB37D,KAAMw4D,EAEN4C,QAAS,GACTQ,eAAgB,GAChBC,WAAY,GAEZ3C,gBAAiB,GACjB4C,kBAAmB,GAEnBC,iBAAkB,IAgBnB,OAkFD,SAAoBL,EAAiBC,GACpC,IAAM,MAAMK,KAAkBN,EAAkB,CAC/C,MAAMO,EAAY97D,OAAOuF,KAAMs2D,GAAiB91D,OAAQlG,GAAQA,EAAK2sD,WAAY,OAEjF,IAAM,MAAM3sD,KAAQi8D,EACnBN,EAAU37D,GAASg8D,EAAgBh8D,IApGrCk8D,CAAWR,EAAiBC,GAE5BQ,GAAcT,EAAiBC,EAAU,WACzCQ,GAAcT,EAAiBC,EAAU,kBACzCQ,GAAcT,EAAiBC,EAAU,cAEzCQ,GAAcT,EAAiBC,EAAU,mBACzCQ,GAAcT,EAAiBC,EAAU,qBAEzCQ,GAAcT,EAAiBC,EAAU,oBA0G1C,SAA6BD,EAAiBC,GAC7C,IAAM,MAAMK,KAAkBN,EAAkB,CAC/C,MAAMU,EAAcJ,EAAeK,eAE9BD,IACJT,EAASC,eAAez2D,KAAMi3D,GAC9BT,EAASE,WAAW12D,KAAMi3D,GAC1BT,EAASG,kBAAkB32D,KAAMi3D,GACjCT,EAASI,iBAAiB52D,KAAMi3D,KAhHlCE,CAAoBZ,EAAiBC,GAE9BA,EAGR,SAAShB,GAAuBJ,EAAqB/B,GACpD,IAAM,MAAM+D,KAA0BhC,EAAqB/B,GAAWoD,eAErE,GAAKrB,EAAqBgC,GAA2B,CAC5BC,GAAoBjC,EAAqBgC,GAEjD52D,QAAS82D,IACxBA,EAAYrB,QAAQj2D,KAAMqzD,YAKtB+B,EAAqB/B,GAAWoD,eAGxC,SAAShB,GAAmBL,EAAqB/B,GAChD,IAAM,MAAMkE,KAAsBnC,EAAqB/B,GAAWqD,WAAa,CAC9E,MAAMO,EAAc7B,EAAqBmC,GAGzC,GAAKN,EAAc,CAClB,MAAMO,EAAYP,EAAYhB,QAE9Bb,EAAqB/B,GAAW4C,QAAQj2D,QAASw3D,WAI5CpC,EAAqB/B,GAAWqD,WAGxC,SAAShB,GAA0BN,EAAqB/B,GACvD,IAAM,MAAMoE,KAAwBrC,EAAqB/B,GAAWsD,kBAAoB,CACvF,MAAMM,EAAc7B,EAAqBqC,GAEzC,GAAKR,EAAc,CAClB,MAAMS,EAAoBT,EAAYlD,gBAEtCqB,EAAqB/B,GAAWU,gBAAgB/zD,QAAS03D,WAIpDtC,EAAqB/B,GAAWsD,kBAGxC,SAAShB,GAA8BP,EAAqB/B,GAC3D,MAAMj0D,EAAOg2D,EAAqB/B,GAElC,IAAM,MAAMsE,KAA2Bv4D,EAAKw3D,iBAAmB,CAC9D,MAAMK,EAAc7B,EAAqBuC,GAEzC,GAAKV,EAAc,CAClB,MAAMH,EAAY97D,OAAOuF,KAAM02D,GAAcl2D,OAAQlG,GAAQA,EAAK2sD,WAAY,OAE9E,IAAM,MAAM3sD,KAAQi8D,EACXj8D,KAAQuE,IACfA,EAAMvE,GAASo8D,EAAap8D,YAMzBuE,EAAKw3D,iBAKb,SAAShB,GAAgBR,EAAqB/B,GAC7C,MAAMmD,EAAWpB,EAAqB/B,GAChCuE,EAAgBpB,EAASP,QAAQl1D,OAAQ82D,GAAezC,EAAqByC,IAEnFrB,EAASP,QAAU/vD,MAAMiK,KAAM,IAAIiF,IAAKwiD,IAGzC,SAAS/B,GAAwBT,EAAqB/B,GACrD,MAAMmD,EAAWpB,EAAqB/B,GAEtCmD,EAASzC,gBAAkB7tD,MAAMiK,KAAM,IAAIiF,IAAKohD,EAASzC,kBAa1D,SAASiD,GAAcT,EAAiBC,EAAUx2C,GACjD,IAAM,MAAM62C,KAAkBN,EACiB,iBAAlCM,EAAgB72C,GAC3Bw2C,EAAUx2C,GAAehgB,KAAM62D,EAAgB72C,IACpC9Z,MAAMgC,QAAS2uD,EAAgB72C,KAC1Cw2C,EAAUx2C,GAAehgB,QAAS62D,EAAgB72C,IAkBrD,SAASq3C,GAAoBjC,EAAqB/B,GACjD,MAAMmD,EAAWpB,EAAqB/B,GAEtC,OAGmB3zD,EAHD01D,EAIXp6D,OAAOuF,KAAMb,GAAM0H,IAAKvL,GAAO6D,EAAK7D,KAJHkF,OAAQ4yD,GAAOA,EAAIsC,QAAQ9/C,SAAUqgD,EAAS37D,OAGvF,IAAoB6E,EAIpB,SAASy2D,GAAgB2B,GACxB,MAAuB,iBAAXA,EACJ,CACNj9D,KAAMi9D,EAEN,sBAEA,kBAGM,CAENj9D,KAAMi9D,EAAQ56D,GAAI,WAAc46D,EAAQj9D,KAAO,QAE/C,0BACQi9D,EAAQvlC,oBAGhBpW,aAActgB,GACNi8D,EAAQ37C,aAActgB,IAwDjC,SAASo5D,GAAmCjP,EAAQ12C,EAAMyf,GACzD,IAAM,MAAM7S,KAAa5M,EAAKijB,mBACvByzB,EAAO4K,eAAgBthD,EAAM4M,IAClC6S,EAAOptB,gBAAiBua,EAAW5M,GCtoDvB,MAAM,GAQpB,YAAawyC,EAAgB,IAS5B/kD,KAAKg7D,YAAc,IAAIlnD,IAUvB9T,KAAKi7D,eAAiB,IAAInnD,IAU1B9T,KAAKk7D,aAAe,KAOpBl7D,KAAK+kD,cAAgB9mD,OAAO4nC,OAAQ,GAAIkf,GAIxC/kD,KAAK+kD,cAAcoW,YAAcn7D,KAAKo7D,aAAar8D,KAAMiB,MACzDA,KAAK+kD,cAAc+N,gBAAkB9yD,KAAKq7D,iBAAiBt8D,KAAMiB,MACjEA,KAAK+kD,cAAcsO,WAAarzD,KAAKs7D,YAAYv8D,KAAMiB,MACvDA,KAAK+kD,cAAcuO,uBAAyBtzD,KAAKu7D,wBAAwBx8D,KAAMiB,MAE/EA,KAAK+kD,cAAcyW,qBAAuBx7D,KAAKy7D,sBAAsB18D,KAAMiB,MAC3EA,KAAK+kD,cAAc2W,cAAgB17D,KAAK27D,eAAe58D,KAAMiB,MAiB9D,QAAS+yD,EAAU/gC,EAAQtyB,EAAU,CAAE,UACtCM,KAAKqU,KAAM,cAAe0+C,GAI1B/yD,KAAKk7D,aAiXP,SAA4BU,EAAmB5pC,GAC9C,IAAInH,EAEJ,IAAM,MAAMxoB,KAAQ,IAAI+zD,GAAewF,GAAsB,CAC5D,MAAMt4D,EAAa,GAEnB,IAAM,MAAMxE,KAAOuD,EAAKmzB,mBACvBlyB,EAAYxE,GAAQuD,EAAK+c,aAActgB,GAGxC,MAAMo7B,EAAUlI,EAAO3uB,cAAehB,EAAKvE,KAAMwF,GAE5CunB,GACJmH,EAAO6pC,OAAQ3hC,EAASrP,GAGzBA,EAAW,GAAcC,UAAWoP,EAAS,GAG9C,OAAOrP,EApYcixC,CAAmBp8D,EAASsyB,GAIhDhyB,KAAK+kD,cAAc/yB,OAASA,EAG5BhyB,KAAK+kD,cAAcqB,WAAa+O,GAAeM,WAAY1C,GAG3D/yD,KAAK+kD,cAAcgX,MAAQ,GAG3B,MAAM,WAAEtY,GAAezjD,KAAKo7D,aAAcrI,EAAU/yD,KAAKk7D,cAGnDc,EAAmBhqC,EAAOkX,yBAGhC,GAAKua,EAAa,CAEjBzjD,KAAKi8D,uBAGL,IAAM,MAAM55D,KAAQ8G,MAAMiK,KAAMpT,KAAKk7D,aAAan+C,OAAO2J,eACxDsL,EAAO6pC,OAAQx5D,EAAM25D,GAItBA,EAAiB7W,QAgTpB,SAA0C+W,EAAWlqC,GACpD,MAAMmqC,EAAiB,IAAI9jD,IACrB8sC,EAAU,IAAIrxC,IAGdmb,EAAQ,GAAW2B,UAAWsrC,GAAY5U,WAGhD,IAAM,MAAMjlD,KAAQ4sB,EAED,WAAb5sB,EAAKvE,MACTq+D,EAAevtD,IAAKvM,GAKtB,IAAM,MAAM+5D,KAAiBD,EAAiB,CAC7C,MAAMjZ,EAAakZ,EAAch9C,aAAc,aACzCi9C,EAAkBrqC,EAAOsqC,qBAAsBF,GAG/CjX,EAAQz7C,IAAKw5C,GAIlBiC,EAAQ/mD,IAAK8kD,GAAapiC,IAAMu7C,EAAgB3wC,QAHhDy5B,EAAQ17C,IAAKy5C,EAAY,IAAI,GAAYmZ,EAAgB3wC,UAO1DsG,EAAO7tB,OAAQi4D,GAGhB,OAAOjX,EAhVsBoX,CAAiCP,EAAkBhqC,GAe/E,OAXAhyB,KAAKk7D,aAAe,KAGpBl7D,KAAKg7D,YAAYzxD,QACjBvJ,KAAKi7D,eAAe1xD,QAGpBvJ,KAAK+kD,cAAc/yB,OAAS,KAC5BhyB,KAAK+kD,cAAcgX,MAAQ,KAGpBC,EAOR,aAAcjJ,EAAUF,GACvB,MAAMlzD,EAAO1B,OAAO4nC,OAAQ,CAAEktB,WAAUF,cAAapP,WAAY,OAWjE,GATKsP,EAAS5yD,GAAI,WACjBH,KAAKqU,KAAM,WAAa0+C,EAASj1D,KAAM6B,EAAMK,KAAK+kD,eACvCgO,EAAS5yD,GAAI,SACxBH,KAAKqU,KAAM,OAAQ1U,EAAMK,KAAK+kD,eAE9B/kD,KAAKqU,KAAM,mBAAoB1U,EAAMK,KAAK+kD,eAItCplD,EAAK8jD,cAAiB9jD,EAAK8jD,sBAAsB,IAQrD,MAAM,IAAI,KAAe,8CAA+CzjD,MAGzE,MAAO,CAAEyjD,WAAY9jD,EAAK8jD,WAAYoP,YAAalzD,EAAKkzD,aAOzD,iBAAkBE,EAAUyJ,GAC3B,IAAIC,EAAkBD,EAAqBr8D,GAAI,YAC9Cq8D,EAAuB,GAAc1xC,UAAW0xC,EAAsB,GAEvE,MAAM/Y,EAAa,IAAI,GAAYgZ,GAEnC,IAAM,MAAMt5B,KAAah6B,MAAMiK,KAAM2/C,EAASrsC,eAAkB,CAC/D,MAAM5kB,EAAS9B,KAAKo7D,aAAcj4B,EAAWs5B,GAExC36D,EAAO2hD,sBAAsB,KACjCA,EAAW3iC,IAAMhf,EAAO2hD,WAAW3iC,IACnC27C,EAAkB36D,EAAO+wD,aAI3B,MAAO,CAAEpP,aAAYoP,YAAa4J,GAOnC,YAAazZ,EAAcn4B,GAI1B,MAAM6xC,EAAc18D,KAAKy7D,sBAAuBzY,EAAcn4B,GAG9D,QAAM6xC,IAKN18D,KAAK+kD,cAAc/yB,OAAOruB,OAAQq/C,EAAc0Z,EAAY7xC,WAErD,GAOR,wBAAyBm4B,EAAcrjD,GACtC,MAAM2P,EAAQtP,KAAK27D,eAAgB3Y,GAE7BhxB,EAAShyB,KAAK+kD,cAAc/yB,OAG5BryB,EAAK8jD,aACV9jD,EAAK8jD,WAAazxB,EAAOsU,YACxBtU,EAAOsqC,qBAAsBtZ,GAC7BhxB,EAAO2qC,oBAAqBrtD,EAAOA,EAAMvN,OAAS,MAIpD,MAAM66D,EAAoB58D,KAAKi7D,eAAe78D,IAAK4kD,GASlDrjD,EAAKkzD,YAND+J,EAMe5qC,EAAOo/B,iBAAkBwL,EAAmB,GAI5Cj9D,EAAK8jD,WAAW3iC,IAQrC,sBAAuBvO,EAAMsgD,GAC5B,MAAM,OAAE5J,EAAM,OAAEj3B,GAAWhyB,KAAK+kD,cAGhC,IAAI8X,EAAgB5T,EAAO6T,kBAAmBjK,EAAatgD,GAE3D,GAAKsqD,EAAgB,CAEpB,GAAKA,IAAkBhK,EAAY91C,OAClC,MAAO,CAAE8N,SAAUgoC,GAIf7yD,KAAKk7D,aAAan+C,OAAOS,eAAepE,SAAUyjD,KACtDA,EAAgB,MAIlB,IAAMA,EAEL,OAAM9L,GAAiB8B,EAAatgD,EAAM02C,GAInC,CACNp+B,SAAUqmC,GAAiB2B,EAAa7gC,IAJjC,KAST,MAAM0qC,EAAc18D,KAAK+kD,cAAc/yB,OAAOziB,MAAOsjD,EAAagK,GAgB5Dv8D,EAAQ,GAEd,IAAM,MAAMy8D,KAAmBL,EAAYztC,MAAMgL,YAChD,GAA6B,cAAxB8iC,EAAgB98D,KACpBK,EAAM2C,KAAM85D,EAAgB16D,UACtB,CAEN,MAAM26D,EAAe18D,EAAM8I,MACrB6zD,EAAYF,EAAgB16D,KAElCrC,KAAKk9D,mBAAoBF,EAAcC,GAIzC,MAAME,EAAeT,EAAYztC,MAAMnO,IAAI/D,OAG3C,OAFA/c,KAAKi7D,eAAexxD,IAAK8I,EAAM4qD,GAExB,CACNtyC,SAAU6xC,EAAY7xC,SACtBsyC,gBAaF,mBAAoBH,EAAcC,GAC3Bj9D,KAAKg7D,YAAYtxD,IAAKszD,IAC3Bh9D,KAAKg7D,YAAYvxD,IAAKuzD,EAAc,CAAEA,IAGvC,MAAM/6D,EAAOjC,KAAKg7D,YAAY58D,IAAK4+D,GAEnCh9D,KAAKg7D,YAAYvxD,IAAKwzD,EAAWh7D,GACjCA,EAAKgB,KAAMg6D,GAOZ,eAAgBr+C,GACf,IAAItP,EAQJ,OAHCA,EAHKtP,KAAKg7D,YAAYtxD,IAAKkV,GAGnB5e,KAAKg7D,YAAY58D,IAAKwgB,GAFtB,CAAEA,GAKJtP,EAWR,uBACC,IAAI8tD,GAAa,EAEjB,IAAM,MAAMx+C,KAAW5e,KAAKg7D,YAAYx3D,OAClCob,EAAQ6D,UACZziB,KAAK+kD,cAAc/yB,OAAO7tB,OAAQya,GAClC5e,KAAKg7D,YAAYjnD,OAAQ6K,GAEzBw+C,GAAa,GAIVA,GACJp9D,KAAKi8D,wBA0CRznD,GAAK,GAAkB,IC1dR,MAAM,GAOpB,YAAaw0C,EAAOhjC,GAOnBhmB,KAAKgpD,MAAQA,EAQbhpD,KAAKgmB,gBAAkBA,EAOvBhmB,KAAKq9D,eAAY/2D,EAUjBtG,KAAK2jD,OAAS,IAAI,GAQlB3jD,KAAKg0D,mBAAqB,IAAI,GAAoB,CACjDrQ,OAAQ3jD,KAAK2jD,OACbsF,OAAQD,EAAMC,SAEfjpD,KAAKg0D,mBAAmB9qC,GAAI,eRgbtB,CAAEpS,EAAKnX,EAAMolD,KACnB,IAAMA,EAAcqB,WAAWkH,QAAS3tD,EAAK0C,KAAM,UAClD,OAGD,MAAM2rD,EAAajJ,EAAc/yB,OAC3BwE,EAAeuuB,EAAcpB,OAAOD,eAAgB/jD,EAAKsvB,MAAMpO,OAC/DijB,EAAWkqB,EAAWwG,WAAY70D,EAAK0C,KAAK1C,MAElDquD,EAAWrqD,OAAQ6yB,EAAcsN,IQzbyB,CAAErzB,SAAU,WAQtEzQ,KAAKs9D,iBAAmB,IAAI,GAAkB,CAC7CrU,OAAQD,EAAMC,SASfjpD,KAAKu9D,aAAe,IAAI,GAAcv3C,GAUtChmB,KAAKw9D,YAAc,IAAI,GAAoBx9D,KAAKu9D,cAOhDv9D,KAAKs9D,iBAAiBp0C,GAAI,ONwUpB,CAAEpS,EAAKnX,GAAQspD,SAAQ7C,aAAYp0B,aACzC,IAAInH,EAAWlrB,EAAKkzD,YAGpB,IAAMzM,EAAWj8C,KAAMxK,EAAKozD,UAC3B,OAGD,IAAM9J,EAAOiH,WAAYrlC,EAAU,SAAY,CAC9C,IAAMkmC,GAAiBlmC,EAAU,QAASo+B,GACzC,OAGDp+B,EAAWqmC,GAAiBrmC,EAAUmH,GAGvCo0B,EAAWkH,QAAS3tD,EAAKozD,UAEzB,MAAMxgB,EAAOvgB,EAAOwiC,WAAY70D,EAAKozD,SAASpzD,MAE9CqyB,EAAOruB,OAAQ4uC,EAAM1nB,GAErBlrB,EAAK8jD,WAAazxB,EAAOsU,YACxBzb,EACAA,EAASyD,aAAcikB,EAAK/jB,aAE7B7uB,EAAKkzD,YAAclzD,EAAK8jD,WAAW3iC,KMlWc,CAAErQ,SAAU,WAC7DzQ,KAAKs9D,iBAAiBp0C,GAAI,UNsTpB,CAAEpS,EAAKnX,EAAMolD,KAEnB,IAAMplD,EAAK8jD,YAAcsB,EAAcqB,WAAWkH,QAAS3tD,EAAKozD,SAAU,CAAEj1D,MAAM,IAAW,CAC5F,MAAM,WAAE2lD,EAAU,YAAEoP,GAAgB9N,EAAc+N,gBAAiBnzD,EAAKozD,SAAUpzD,EAAKkzD,aAEvFlzD,EAAK8jD,WAAaA,EAClB9jD,EAAKkzD,YAAcA,IM5T2C,CAAEpiD,SAAU,WAC3EzQ,KAAKs9D,iBAAiBp0C,GAAI,mBNqTpB,CAAEpS,EAAKnX,EAAMolD,KAEnB,IAAMplD,EAAK8jD,YAAcsB,EAAcqB,WAAWkH,QAAS3tD,EAAKozD,SAAU,CAAEj1D,MAAM,IAAW,CAC5F,MAAM,WAAE2lD,EAAU,YAAEoP,GAAgB9N,EAAc+N,gBAAiBnzD,EAAKozD,SAAUpzD,EAAKkzD,aAEvFlzD,EAAK8jD,WAAaA,EAClB9jD,EAAKkzD,YAAcA,IM3ToD,CAAEpiD,SAAU,WAEpFzQ,KAAKm2D,SAAU,QACfn2D,KAAKm2D,SAAU,OAIfn2D,KAAKkpB,GAAI,OAAQ,KAChBlpB,KAAKqU,KAAM,UACT,CAAE5D,SAAU,WAIfzQ,KAAKkpB,GAAI,QAAS,KACjBlpB,KAAKgpD,MAAMqC,cAAe,cAAeuF,KACvC,CAAEngD,SAAU,WAehB,IAAKvO,EAAU,IACd,MAAM,SAAEqoB,EAAW,OAAM,KAAEjH,EAAO,SAAYphB,EAE9C,IAAMlC,KAAKy9D,oBAAqB,CAAElzC,IAYjC,MAAM,IAAI,KAAe,uCAAwCvqB,MAGlE,MAAMnD,EAAOmD,KAAKgpD,MAAMhoD,SAAS+7C,QAASxyB,GAE1C,MAAc,UAATjH,GAAqBtjB,KAAKgpD,MAAM0U,WAAY7gE,EAAM,CAAE8gE,mBAAmB,IAIrE39D,KAAKF,UAAWjD,EAAMqF,GAHrB,GAgBT,UAAW07D,EAAwB17D,GAElC,MAAM27D,EAAuB79D,KAAK89D,OAAQF,EAAwB17D,GAGlE,OAAOlC,KAAKq9D,UAAUU,OAAQF,GAe/B,OAAQD,EAAwB17D,GAC/B,MAAMq7D,EAAev9D,KAAKu9D,aACpBvP,EAAahuD,KAAKw9D,YAGxBx9D,KAAK2jD,OAAOqa,gBAGZ,MAAMva,EAAa,GAAW7yB,UAAWgtC,GACnCC,EAAuB,IAAI,GAAsBN,GAUvD,GARAv9D,KAAK2jD,OAAOrgB,aAAcs6B,EAAwBC,GAGlD79D,KAAKg0D,mBAAmBjP,cAAc7iD,QAAUA,EAGhDlC,KAAKg0D,mBAAmBxO,cAAe/B,EAAYuK,IAE7C4P,EAAuBz9D,GAAI,oBAAuB,CAGvD,MAAMglD,EAwPT,SAAuCvmC,GACtC,MAAM9c,EAAS,GACTslC,EAAMxoB,EAAQ/hB,KAAKmE,SAEzB,IAAMomC,EACL,MAAO,GAGR,MAAMuf,EAAe,GAAW/1B,UAAWhS,GAE3C,IAAM,MAAMwoC,KAAUhgB,EAAI4hB,MAAM7D,QAAU,CACzC,MAAM8Y,EAAetX,EAAa9N,gBAAiBuO,EAAOnB,YAErDgY,GACJn8D,EAAOmB,KAAM,CAAEmkD,EAAOtpD,KAAMmgE,IAI9B,OAAOn8D,EA1QWo8D,CAA8BN,GAE9C,IAAM,MAAQ9/D,EAAMmxB,KAAWk2B,EAC9BnlD,KAAKg0D,mBAAmB9N,iBAAkBpoD,EAAMmxB,EAAO++B,GAOzD,cAFOhuD,KAAKg0D,mBAAmBjP,cAAc7iD,QAEtC27D,EAwBR,KAAMl+D,GACL,GAAKK,KAAKgpD,MAAMhoD,SAASm9D,QAQxB,MAAM,IAAI,KAAe,yCAA0Cn+D,MAGpE,IAAIo+D,EAAc,GAOlB,GANqB,iBAATz+D,EACXy+D,EAAYC,KAAO1+D,EAEnBy+D,EAAcz+D,GAGTK,KAAKy9D,oBAAqBx/D,OAAOuF,KAAM46D,IAY5C,MAAM,IAAI,KAAe,wCAAyCp+D,MAUnE,OAPAA,KAAKgpD,MAAMqC,cAAe,cAAer5B,IACxC,IAAM,MAAMzH,KAAYtsB,OAAOuF,KAAM46D,GAAgB,CACpD,MAAME,EAAYt+D,KAAKgpD,MAAMhoD,SAAS+7C,QAASxyB,GAC/CyH,EAAOruB,OAAQ3D,KAAKu+D,MAAOH,EAAa7zC,GAAY+zC,GAAaA,EAAW,MAIvEvlD,QAAQ/L,UAwBhB,IAAKrN,GACJ,IAAI6+D,EAAU,GAQd,GANqB,iBAAT7+D,EACX6+D,EAAQH,KAAO1+D,EAEf6+D,EAAU7+D,GAGLK,KAAKy9D,oBAAqBx/D,OAAOuF,KAAMg7D,IAY5C,MAAM,IAAI,KAAe,uCAAwCx+D,MAGlEA,KAAKgpD,MAAMqC,cAAe,cAAer5B,IACxCA,EAAOyI,aAAc,MACrBzI,EAAOysC,yBAA0Bz+D,KAAKgpD,MAAMhoD,SAASopB,UAAUoL,oBAE/D,IAAM,MAAMjL,KAAYtsB,OAAOuF,KAAMg7D,GAAY,CAEhD,MAAMF,EAAYt+D,KAAKgpD,MAAMhoD,SAAS+7C,QAASxyB,GAE/CyH,EAAO7tB,OAAQ6tB,EAAO0iC,cAAe4J,IACrCtsC,EAAOruB,OAAQ3D,KAAKu+D,MAAOC,EAASj0C,GAAY+zC,GAAaA,EAAW,MAe3E,MAAO3+D,EAAMD,EAAU,SAEtB,MAAMm+D,EAAuB79D,KAAKq9D,UAAUS,OAAQn+D,GAGpD,OAAOK,KAAK0+D,QAASb,EAAsBn+D,GAiB5C,QAASi/D,EAAuBj/D,EAAU,SACzC,OAAOM,KAAKgpD,MAAM5L,OAAQprB,GAClBhyB,KAAKs9D,iBAAiBntB,QAASwuB,EAAuB3sC,EAAQtyB,IAgBvE,uBAAwBwR,GACvBA,EAAUlR,KAAKgmB,iBAMhB,UACChmB,KAAKsR,gBAUN,oBAAqBstD,GACpB,IAAM,MAAMr0C,KAAYq0C,EACvB,IAAM5+D,KAAKgpD,MAAMhoD,SAAS6vD,eAAez3C,SAAUmR,GAClD,OAAO,EAIT,OAAO,GA8BT/V,GAAK,GAAgB,IC1aN,MAAM,GASpB,YAAaqqD,EAAqBC,GAOjC9+D,KAAK++D,SAAW,IAAIjrD,IAGpB9T,KAAKg/D,UAAY3kD,GAASwkD,GAC1B7+D,KAAKi/D,yBAA0B,CAAEnhE,KAAM,WAAYmvD,YAAajtD,KAAKg/D,UAAWE,YAAY,IAE5Fl/D,KAAKm/D,QAAU9kD,GAASykD,GACxB9+D,KAAKi/D,yBAA0B,CAAEnhE,KAAM,SAAUmvD,YAAajtD,KAAKm/D,QAASD,YAAY,IAiBzF,SAAUE,EAAOpa,GAChB,MAAMka,EAAal/D,KAAKg/D,UAAU5lD,SAAU4rC,GAG5C,IAFiBhlD,KAAKm/D,QAAQ/lD,SAAU4rC,KAErBka,EAMlB,MAAM,IAAI,KACT,iDACAl/D,MAIFA,KAAKi/D,yBAA0B,CAAEnhE,KAAMshE,EAAOnS,YAAa,CAAEjI,GAAcka,eAgE5E,IAAKlkC,GACJ,IAAMh7B,KAAK++D,SAASr1D,IAAKsxB,GAMxB,MAAM,IAAI,KAAe,+BAAgCh7B,MAG1D,OAAOA,KAAK++D,SAAS3gE,IAAK48B,GA0E3B,iBAAkBu7B,GAEjBv2D,KAAKq/D,IAAK,YAAaC,iBAAkB/I,GAGzC,IAAM,MAAM,MAAEvN,EAAK,KAAEtzB,KAAU6pC,GAA0BhJ,GACxDv2D,KAAKq/D,IAAK,UACRC,iBAAkB,CAClBtW,QACAtzB,OACA63B,kBAAmBgJ,EAAWhJ,oBAkKlC,mBAAoBgJ,GAEnBv2D,KAAKq/D,IAAK,YAAaG,mBAAoBjJ,GAG3C,IAAM,MAAM,MAAEvN,EAAK,KAAEtzB,KAAU6pC,GAA0BhJ,GACxDv2D,KAAKq/D,IAAK,UACRI,mBAAoB,CACpB/pC,OACAszB,QACAuE,kBAAmBgJ,EAAWhJ,oBAmHlC,qBAAsBgJ,GAErBv2D,KAAKq/D,IAAK,YAAaK,qBAAsBnJ,GAG7C,IAAM,MAAM,MAAEvN,EAAK,KAAEtzB,KAAU6pC,GAA0BhJ,GACxDv2D,KAAKq/D,IAAK,UACRK,qBAAsB,CACtBhqC,OACAszB,UAeJ,0BAA0B,KAAElrD,EAAI,YAAEmvD,EAAW,WAAEiS,IAC9C,GAAKl/D,KAAK++D,SAASr1D,IAAK5L,GAMvB,MAAM,IAAI,KAAe,0BAA2BkC,MAGrD,MAAM2/D,EAAUT,EAAa,IAAI,GAAiBjS,GAAgB,IAAI,GAAeA,GAErFjtD,KAAK++D,SAASt1D,IAAK3L,EAAM6hE,IA0B3B,SAAUJ,GAA0BhJ,GACnC,GAAKA,EAAWvN,MAAM38C,OACrB,IAAM,MAAM7N,KAAS+3D,EAAWvN,MAAM38C,OAAS,CAC9C,MAAM28C,EAAQ,CAAElqD,IAAKy3D,EAAWvN,MAAMlqD,IAAKN,SACrCk3B,EAAO6gC,EAAW7gC,KAAMl3B,GACxBohE,EAAarJ,EAAWqJ,WAAarJ,EAAWqJ,WAAYphE,QAAU8H,QAErEu5D,GAAsB7W,EAAOtzB,EAAMkqC,cAGpCC,GAAsBtJ,EAAWvN,MAAOuN,EAAW7gC,KAAM6gC,EAAWqJ,YAI7E,SAAUC,GAAsB7W,EAAOtzB,EAAMkqC,GAG5C,QAFM,CAAE5W,QAAOtzB,QAEVkqC,EACJ,IAAM,MAAME,KAAkBzlD,GAASulD,QAChC,CAAE5W,QAAOtzB,KAAMoqC,GC3mBT,MAAMC,GAQpB,YAAa9/D,EAAO,WAOnBD,KAAKkhD,WAAa,GAalBlhD,KAAKC,KAAOA,EAUb,kBACC,IAAM,MAAM+/D,KAAMhgE,KAAKkhD,WACtB,GAAwB,OAAnB8e,EAAGC,YACP,OAAOD,EAAGC,YAIZ,OAAO,KASR,aAAcvgB,GAIb,OAHAA,EAAUyL,MAAQnrD,KAClBA,KAAKkhD,WAAWj+C,KAAMy8C,GAEfA,GCjEM,MAAMwgB,GAOpB,YAAaD,GASZjgE,KAAKigE,YAAcA,EAQnBjgE,KAAKwpD,oBAA2C,OAArBxpD,KAAKigE,YAQhCjgE,KAAKmrD,MAAQ,KA4Cd,aASA,SAGC,MAAMntC,EAAO/f,OAAO4nC,OAAQ,GAAI7lC,MAUhC,OARAge,EAAKmiD,YAAcngE,KAAK0H,YAAY0e,iBAG7BpI,EAAKmtC,aAGLntC,EAAKwrC,oBAELxrC,EAQR,uBACC,MAAO,YAUR,gBAAiBA,GAChB,OAAO,IAAIhe,KAAMge,EAAKiiD,cC3GT,MAAM,GAWpB,YAAan4D,GASZ9H,KAAKmlD,QAAU,IAAIrxC,IAQnB9T,KAAK2lB,UAAY,IAAI,GAEhB7d,GACJ9H,KAAK4lB,aAAc,EAAG9d,GASxB,CAAExJ,OAAOiW,YACR,OAAOvU,KAAK0mB,cASb,iBACC,OAAO1mB,KAAK2lB,UAAU5jB,OASvB,gBACC,OAAO/B,KAAK2lB,UAAUu4B,UASvB,cACC,OAA2B,IAApBl+C,KAAK8mB,WASb,WACC,OAAO9mB,KASR,aACC,OAAO,KAkBR,GAAIC,GACH,MAAgB,qBAATA,GAAwC,2BAATA,EASvC,SAAUyC,GACT,OAAO1C,KAAK2lB,UAAU44B,QAAS77C,GAQhC,cACC,OAAO1C,KAAK2lB,UAAWrnB,OAAOiW,YAS/B,cAAehC,GACd,OAAOvS,KAAK2lB,UAAUs4B,aAAc1rC,GAWrC,oBAAqBA,GACpB,OAAOvS,KAAK2lB,UAAUw4B,mBAAoB5rC,GAQ3C,UACC,MAAO,GAcR,cAAeksC,GACd,IAAIlsC,EAAOvS,KAEX,IAAM,MAAM0C,KAAS+7C,EACpBlsC,EAAOA,EAAK2K,SAAU3K,EAAKisC,cAAe97C,IAG3C,OAAO6P,EAsBR,cAAejG,GACd,OAAOtM,KAAK2lB,UAAU64B,cAAelyC,GAStC,SACC,MAAM0R,EAAO,GAEb,IAAM,MAAMzL,KAAQvS,KAAK2lB,UACxB3H,EAAK/a,KAAMsP,EAAKurC,UAGjB,OAAO9/B,EAUR,gBAAiBA,GAChB,MAAMlW,EAAW,GAEjB,IAAM,MAAM2e,KAASzI,EACfyI,EAAM3oB,KAEVgK,EAAS7E,KAAM,GAAQ27C,SAAUn4B,IAGjC3e,EAAS7E,KAAM,GAAK27C,SAAUn4B,IAIhC,OAAO,IAAI,GAAkB3e,GAS9B,aAAc6N,GACb3V,KAAK4lB,aAAc5lB,KAAK8mB,WAAYnR,GAWrC,aAAcjT,EAAOiT,GACpB,MAAMoR,EA4ER,SAAoBA,GAEnB,GAAqB,iBAATA,EACX,MAAO,CAAE,IAAI,GAAMA,IAGdzS,GAAYyS,KACjBA,EAAQ,CAAEA,IAIX,OAAO5d,MAAMiK,KAAM2T,GACjB1c,IAAKkI,GACe,iBAARA,EACJ,IAAI,GAAMA,GAGbA,aAAgB,GACb,IAAI,GAAMA,EAAK5S,KAAM4S,EAAKwoB,iBAG3BxoB,GAjGM,CAAWoD,GAEzB,IAAM,MAAMpD,KAAQwU,EAEE,OAAhBxU,EAAKwK,QACTxK,EAAK2D,UAGN3D,EAAKwK,OAAS/c,KAGfA,KAAK2lB,UAAUq4B,aAAct7C,EAAOqkB,GAYrC,gBAAiBrkB,EAAOukB,EAAU,GACjC,MAAMF,EAAQ/mB,KAAK2lB,UAAUg5B,aAAcj8C,EAAOukB,GAElD,IAAM,MAAM1U,KAAQwU,EACnBxU,EAAKwK,OAAS,KAGf,OAAOgK,GC9RF,SAASkZ,GAASpV,EAAU9D,GAIlC,MAAMza,GAHNya,EAAQq5C,GAAiBr5C,IAGJ1P,OAAQ,CAAEyd,EAAKviB,IAAUuiB,EAAMviB,EAAKic,WAAY,GAC/DzR,EAAS8N,EAAS9N,OAGxBsjD,GAAsBx1C,GACtB,MAAMnoB,EAAQmoB,EAASnoB,MAUvB,OANAqa,EAAO6I,aAAcljB,EAAOqkB,GAG5Bu5C,GAAoBvjD,EAAQra,EAAQqkB,EAAMhlB,QAC1Cu+D,GAAoBvjD,EAAQra,GAErB,IAAI,GAAOmoB,EAAUA,EAASyD,aAAchiB,IAW7C,SAAS4J,GAAS+Y,GACxB,IAAMA,EAAM1gB,OAMX,MAAM,IAAI,KACT,wCACAvO,MAIF,MAAM+c,EAASkS,EAAMpO,MAAM9D,OAG3BsjD,GAAsBpxC,EAAMpO,OAC5Bw/C,GAAsBpxC,EAAMnO,KAG5B,MAAMhL,EAAUiH,EAAOe,gBAAiBmR,EAAMpO,MAAMne,MAAOusB,EAAMnO,IAAIpe,MAAQusB,EAAMpO,MAAMne,OAMzF,OAFA49D,GAAoBvjD,EAAQkS,EAAMpO,MAAMne,OAEjCoT,EAYD,SAASyqD,GAAOloC,EAAaC,GACnC,IAAMD,EAAY9pB,OAMjB,MAAM,IAAI,KACT,sCACAvO,MAIF,MAAM+mB,EAAQ7Q,GAASmiB,GAMvB,OAAO4H,GAFP3H,EAAiBA,EAAeioB,0BAA2BloB,EAAYxX,MAAOwX,EAAYvX,IAAIxU,OAAS+rB,EAAYxX,MAAMvU,QAEzFya,GA+C1B,SAASq5C,GAAiBr5C,GAChC,MAAM6qC,EAAa,GAEX7qC,aAAiB5d,QACxB4d,EAAQ,CAAEA,IAIX,IAAM,IAAIxpB,EAAI,EAAGA,EAAIwpB,EAAMhlB,OAAQxE,IAClC,GAA0B,iBAAdwpB,EAAOxpB,GAClBq0D,EAAW3uD,KAAM,IAAI,GAAM8jB,EAAOxpB,UAC5B,GAAKwpB,EAAOxpB,aAAe,GACjCq0D,EAAW3uD,KAAM,IAAI,GAAM8jB,EAAOxpB,GAAIoC,KAAMonB,EAAOxpB,GAAIw9B,uBACjD,GAAKhU,EAAOxpB,aAAe,IAAoBwpB,EAAOxpB,aAAe,GAC3E,IAAM,MAAMkpB,KAASM,EAAOxpB,GAC3Bq0D,EAAW3uD,KAAMwjB,QAEPM,EAAOxpB,aAAe,IACjCq0D,EAAW3uD,KAAM8jB,EAAOxpB,IAM1B,IAAM,IAAIA,EAAI,EAAGA,EAAIq0D,EAAW7vD,OAAQxE,IAAM,CAC7C,MAAMgV,EAAOq/C,EAAYr0D,GACnBu7B,EAAO84B,EAAYr0D,EAAI,GAExBgV,aAAgB,IAAQumB,aAAgB,IAAQ0nC,GAAqBjuD,EAAMumB,KAE/E84B,EAAW9rD,OAAQvI,EAAI,EAAG,EAAG,IAAI,GAAMu7B,EAAKn5B,KAAO4S,EAAK5S,KAAMm5B,EAAKiC,kBACnEx9B,KAIF,OAAOq0D,EAWR,SAAS0O,GAAoB1hD,EAASlc,GACrC,MAAM4qB,EAAa1O,EAAQ1B,SAAUxa,EAAQ,GACvC0qB,EAAYxO,EAAQ1B,SAAUxa,GAGpC,GAAK4qB,GAAcF,GAAaE,EAAWntB,GAAI,UAAaitB,EAAUjtB,GAAI,UAAaqgE,GAAqBlzC,EAAYF,GAAc,CAErI,MAAMqzC,EAAa,IAAI,GAAMnzC,EAAW3tB,KAAOytB,EAAUztB,KAAM2tB,EAAWyN,iBAG1Enc,EAAQd,gBAAiBpb,EAAQ,EAAG,GAGpCkc,EAAQgH,aAAcljB,EAAQ,EAAG+9D,IASnC,SAASJ,GAAsBx1C,GAC9B,MAAM1M,EAAW0M,EAAS1M,SACpBS,EAAUiM,EAAS9N,OAEzB,GAAKoB,EAAW,CACf,MAAMuiD,EAAa71C,EAASve,OAAS6R,EAASiO,YACxC1pB,EAAQyb,EAASzb,MAEvBkc,EAAQd,gBAAiBpb,EAAO,GAEhC,MAAMi+D,EAAY,IAAI,GAAMxiD,EAASxe,KAAK0S,OAAQ,EAAGquD,GAAcviD,EAAS4c,iBACtE6lC,EAAa,IAAI,GAAMziD,EAASxe,KAAK0S,OAAQquD,GAAcviD,EAAS4c,iBAE1Enc,EAAQgH,aAAcljB,EAAO,CAAEi+D,EAAWC,KAU5C,SAASJ,GAAqB7yB,EAAOC,GACpC,MAAMizB,EAAYlzB,EAAM5S,gBAClB+lC,EAAYlzB,EAAM7S,gBAExB,IAAM,MAAMyJ,KAAQq8B,EAAY,CAC/B,GAAKr8B,EAAM,KAAQoJ,EAAMxuB,aAAcolB,EAAM,IAC5C,OAAO,EAGRs8B,EAAUv1C,OAGX,OAAOu1C,EAAUv1C,OAAOF,KC7OV,OAJf,SAAiB7sB,EAAOyK,GACtB,OAAO,GAAYzK,EAAOyK,ICTb,MAAM,WAA2Bi3D,GAoB/C,YAAajxC,EAAOnwB,EAAK+oB,EAAU7c,EAAUi1D,GAC5CrgE,MAAOqgE,GAQPjgE,KAAKivB,MAAQA,EAAMvD,QAQnB1rB,KAAKlB,IAAMA,EAQXkB,KAAK6nB,cAAwBvhB,IAAbuhB,EAAyB,KAAOA,EAQhD7nB,KAAKgL,cAAwB1E,IAAb0E,EAAyB,KAAOA,EAMjD,WACC,OAAuB,OAAlBhL,KAAK6nB,SACF,eACsB,OAAlB7nB,KAAKgL,SACT,kBAEA,kBAST,QACC,OAAO,IAAI,GAAoBhL,KAAKivB,MAAOjvB,KAAKlB,IAAKkB,KAAK6nB,SAAU7nB,KAAKgL,SAAUhL,KAAKigE,aAQzF,cACC,OAAO,IAAI,GAAoBjgE,KAAKivB,MAAOjvB,KAAKlB,IAAKkB,KAAKgL,SAAUhL,KAAK6nB,SAAU7nB,KAAKigE,YAAc,GAMvG,SACC,MAAMjiD,EAAOpe,MAAMk+C,SAInB,OAFA9/B,EAAKiR,MAAQjvB,KAAKivB,MAAM6uB,SAEjB9/B,EAMR,YACC,IAAMhe,KAAKivB,MAAM1gB,OAMhB,MAAM,IAAI,KAAe,qCAAsCvO,MAGhE,IAAM,MAAMqC,KAAQrC,KAAKivB,MAAMq4B,SAAU,CAAEt8B,SAAS,IAAW,CAC9D,GAAuB,OAAlBhrB,KAAK6nB,WAAsB,GAASxlB,EAAK+c,aAAcpf,KAAKlB,KAAOkB,KAAK6nB,UAS5E,MAAM,IAAI,KACT,sCACA7nB,KACA,CAAEqC,OAAMvD,IAAKkB,KAAKlB,IAAKN,MAAOwB,KAAK6nB,WAIrC,GAAuB,OAAlB7nB,KAAK6nB,UAAuC,OAAlB7nB,KAAKgL,UAAqB3I,EAAK6c,aAAclf,KAAKlB,KAQhF,MAAM,IAAI,KACT,uCACAkB,KACA,CAAEuS,KAAMlQ,EAAMvD,IAAKkB,KAAKlB,OAS5B,WAEO,GAASkB,KAAK6nB,SAAU7nB,KAAKgL,WFvC9B,SAAwBikB,EAAOnwB,EAAKN,GAE1C6hE,GAAsBpxC,EAAMpO,OAC5Bw/C,GAAsBpxC,EAAMnO,KAG5B,IAAM,MAAMze,KAAQ4sB,EAAMq4B,SAAU,CAAEt8B,SAAS,IAAW,CAIzD,MAAMzY,EAAOlQ,EAAKlC,GAAI,cAAiBkC,EAAK8b,SAAW9b,EAExC,OAAV7D,EACJ+T,EAAKmlB,cAAe54B,EAAKN,GAEzB+T,EAAKolB,iBAAkB74B,GAIxBwhE,GAAoB/tD,EAAKwK,OAAQxK,EAAK7P,OAIvC49D,GAAoBrxC,EAAMnO,IAAI/D,OAAQkS,EAAMnO,IAAIpe,OEkB9Cg1B,CAAe13B,KAAKivB,MAAOjvB,KAAKlB,IAAKkB,KAAKgL,UAO5C,uBACC,MAAO,qBAUR,gBAAiBgT,EAAMhd,GACtB,OAAO,IAAI,GAAoB,GAAM49C,SAAU5gC,EAAKiR,MAAOjuB,GAAYgd,EAAKlf,IAAKkf,EAAK6J,SAAU7J,EAAKhT,SAAUgT,EAAKiiD,cC3KvG,MAAM,WAAwBC,GAS5C,YAAajgB,EAAgBh5B,GAC5BrnB,MAAO,MAOPI,KAAKigD,eAAiBA,EAAev0B,QAOrC1rB,KAAKinB,QAAUA,EAMhB,WACC,MAAO,SAMR,SACC,MAAMjJ,EAAOpe,MAAMk+C,SAInB,OAFA9/B,EAAKiiC,eAAiBjgD,KAAKigD,eAAenC,SAEnC9/B,EAMR,YACC,GAAKhe,KAAKigD,eAAepjD,KAAKmE,SAM7B,MAAM,IAAI,KAAe,oCAAqChB,MAOhE,WACCkW,GAAS,GAAMuY,4BAA6BzuB,KAAKigD,eAAgBjgD,KAAKinB,UAMvE,uBACC,MAAO,mBCpEM,MAAM,WAAsBi5C,GAY1C,YAAajgB,EAAgBh5B,EAASqR,EAAgB2nC,GACrDrgE,MAAOqgE,GAOPjgE,KAAKigD,eAAiBA,EAAev0B,QAErC1rB,KAAKigD,eAAepB,WAAa,SAOjC7+C,KAAKinB,QAAUA,EAOfjnB,KAAKs4B,eAAiBA,EAAe5M,QACrC1rB,KAAKs4B,eAAeumB,WAAa,SAMlC,WACC,MAA0C,cAArC7+C,KAAKs4B,eAAez7B,KAAK0tB,SACtB,SACyC,cAArCvqB,KAAKigD,eAAepjD,KAAK0tB,SAC7B,WAGD,OAQR,QACC,OAAO,IAAIvqB,KAAK0H,YAAa1H,KAAKigD,eAAgBjgD,KAAKinB,QAASjnB,KAAKs4B,eAAgBt4B,KAAKigE,aAiB3F,qBACC,OAAOjgE,KAAKs4B,eAAeioB,0BAA2BvgD,KAAKigD,eAAgBjgD,KAAKinB,SAQjF,cACC,MAAM85C,EAAoB/gE,KAAKigD,eAAeF,2BAA4B//C,KAAKs4B,eAAgBt4B,KAAKinB,SAEpG,OAAO,IAAIjnB,KAAK0H,YAAa1H,KAAKghE,qBAAsBhhE,KAAKinB,QAAS85C,EAAmB/gE,KAAKigE,YAAc,GAM7G,YACC,MAAMgB,EAAgBjhE,KAAKigD,eAAeljC,OACpCmkD,EAAgBlhE,KAAKs4B,eAAevb,OACpCokD,EAAenhE,KAAKigD,eAAe3zC,OACnC80D,EAAephE,KAAKs4B,eAAehsB,OAKzC,GAAK60D,EAAenhE,KAAKinB,QAAUg6C,EAAc/iB,UAMhD,MAAM,IAAI,KACT,oCAAqCl+C,MAEhC,GAAKihE,IAAkBC,GAAiBC,EAAeC,GAAgBA,EAAeD,EAAenhE,KAAKinB,QAMhH,MAAM,IAAI,KACT,mCAAoCjnB,MAE/B,GAAKA,KAAKigD,eAAepjD,MAAQmD,KAAKs4B,eAAez7B,MACuC,UAA7F6f,GAAe1c,KAAKigD,eAAeR,gBAAiBz/C,KAAKs4B,eAAemnB,iBAAgC,CAC5G,MAAMliD,EAAIyC,KAAKigD,eAAepwC,KAAK9N,OAAS,EAE5C,GAAK/B,KAAKs4B,eAAezoB,KAAMtS,IAAO4jE,GAAgBnhE,KAAKs4B,eAAezoB,KAAMtS,GAAM4jE,EAAenhE,KAAKinB,QAMzG,MAAM,IAAI,KACT,kCAAmCjnB,OAUxC,WACCugE,GAAO,GAAM9xC,4BAA6BzuB,KAAKigD,eAAgBjgD,KAAKinB,SAAWjnB,KAAKs4B,gBAMrF,SACC,MAAMta,EAAOpe,MAAMk+C,SAKnB,OAHA9/B,EAAKiiC,eAAiBjgD,KAAKigD,eAAenC,SAC1C9/B,EAAKsa,eAAiBt4B,KAAKs4B,eAAewlB,SAEnC9/B,EAMR,uBACC,MAAO,gBAUR,gBAAiBA,EAAMhd,GACtB,MAAMi/C,EAAiB,GAASrB,SAAU5gC,EAAKiiC,eAAgBj/C,GACzDs3B,EAAiB,GAASsmB,SAAU5gC,EAAKsa,eAAgBt3B,GAE/D,OAAO,IAAIhB,KAAMigD,EAAgBjiC,EAAKiJ,QAASqR,EAAgBta,EAAKiiD,cCjLvD,MAAM,WAAwBC,GAS5C,YAAar1C,EAAU9D,EAAOk5C,GAC7BrgE,MAAOqgE,GAQPjgE,KAAK6qB,SAAWA,EAASa,QACzB1rB,KAAK6qB,SAASg0B,WAAa,SAQ3B7+C,KAAK+mB,MAAQ,IAAI,GAAUq5C,GAAiBr5C,IAS5C/mB,KAAKqhE,yBAA0B,EAMhC,WACC,MAAO,SAQR,cACC,OAAOrhE,KAAK+mB,MAAMm3B,UAQnB,QACC,MAAMn3B,EAAQ,IAAI,GAAU,IAAK/mB,KAAK+mB,OAAQ1c,IAAKkI,GAAQA,EAAKoU,QAAQ,KAClEhjB,EAAS,IAAI,GAAiB3D,KAAK6qB,SAAU9D,EAAO/mB,KAAKigE,aAI/D,OAFAt8D,EAAO09D,wBAA0BrhE,KAAKqhE,wBAE/B19D,EAQR,cACC,MAAMk9C,EAAY7gD,KAAK6qB,SAAShuB,KAAKmE,SAAS6/C,UACxCygB,EAAa,IAAI,GAAUzgB,EAAW,CAAE,IAE9C,OAAO,IAAI,GAAe7gD,KAAK6qB,SAAU7qB,KAAK+mB,MAAMm3B,UAAWojB,EAAYthE,KAAKigE,YAAc,GAM/F,YACC,MAAMiB,EAAgBlhE,KAAK6qB,SAAS9N,OAEpC,IAAMmkD,GAAiBA,EAAchjB,UAAYl+C,KAAK6qB,SAASve,OAM9D,MAAM,IAAI,KACT,oCACAtM,MAQH,WAKC,MAAMuhE,EAAgBvhE,KAAK+mB,MAC3B/mB,KAAK+mB,MAAQ,IAAI,GAAU,IAAKw6C,GAAgBl3D,IAAKkI,GAAQA,EAAKoU,QAAQ,KAE1EsZ,GAASjgC,KAAK6qB,SAAU02C,GAMzB,SACC,MAAMvjD,EAAOpe,MAAMk+C,SAKnB,OAHA9/B,EAAK6M,SAAW7qB,KAAK6qB,SAASizB,SAC9B9/B,EAAK+I,MAAQ/mB,KAAK+mB,MAAM+2B,SAEjB9/B,EAMR,uBACC,MAAO,kBAUR,gBAAiBA,EAAMhd,GACtB,MAAM8G,EAAW,GAEjB,IAAM,MAAM2e,KAASzI,EAAK+I,MACpBN,EAAM3oB,KAEVgK,EAAS7E,KAAM,GAAQ27C,SAAUn4B,IAGjC3e,EAAS7E,KAAM,GAAK27C,SAAUn4B,IAIhC,MAAM9iB,EAAS,IAAI,GAAiB,GAASi7C,SAAU5gC,EAAK6M,SAAU7pB,GAAY8G,EAAUkW,EAAKiiD,aAGjG,OAFAt8D,EAAO09D,wBAA0BrjD,EAAKqjD,wBAE/B19D,GCpKM,MAAM,WAAwBu8D,GAW5C,YAAapiE,EAAMkqD,EAAUrtB,EAAUwqB,EAASqc,EAAavB,GAC5DrgE,MAAOqgE,GAQPjgE,KAAKlC,KAAOA,EAQZkC,KAAKgoD,SAAWA,EAAWA,EAASt8B,QAAU,KAQ9C1rB,KAAK26B,SAAWA,EAAWA,EAASjP,QAAU,KAS9C1rB,KAAKwhE,YAAcA,EAQnBxhE,KAAKyhE,SAAWtc,EAMjB,WACC,MAAO,SAQR,QACC,OAAO,IAAI,GAAiBnlD,KAAKlC,KAAMkC,KAAKgoD,SAAUhoD,KAAK26B,SAAU36B,KAAKyhE,SAAUzhE,KAAKwhE,YAAaxhE,KAAKigE,aAQ5G,cACC,OAAO,IAAI,GAAiBjgE,KAAKlC,KAAMkC,KAAK26B,SAAU36B,KAAKgoD,SAAUhoD,KAAKyhE,SAAUzhE,KAAKwhE,YAAaxhE,KAAKigE,YAAc,GAM1H,WACC,MAAMhgE,EAAOD,KAAK26B,SAAW,OAAS,UAEtC36B,KAAKyhE,SAAUxhE,GAAQD,KAAKlC,KAAMkC,KAAK26B,UAAU,EAAM36B,KAAKwhE,aAM7D,SACC,MAAMxjD,EAAOpe,MAAMk+C,SAYnB,OAVK99C,KAAKgoD,WACThqC,EAAKgqC,SAAWhoD,KAAKgoD,SAASlK,UAG1B99C,KAAK26B,WACT3c,EAAK2c,SAAW36B,KAAK26B,SAASmjB,iBAGxB9/B,EAAKyjD,SAELzjD,EAMR,uBACC,MAAO,kBAUR,gBAAiBA,EAAMhd,GACtB,OAAO,IAAI,GACVgd,EAAKlgB,KACLkgB,EAAKgqC,SAAW,GAAMpJ,SAAU5gC,EAAKgqC,SAAUhnD,GAAa,KAC5Dgd,EAAK2c,SAAW,GAAMikB,SAAU5gC,EAAK2c,SAAU35B,GAAa,KAC5DA,EAASgoD,MAAM7D,QACfnnC,EAAKwjD,YACLxjD,EAAKiiD,cC5HO,MAAM,WAAwBC,GAU5C,YAAar1C,EAAU62C,EAAS7mC,EAASolC,GACxCrgE,MAAOqgE,GAOPjgE,KAAK6qB,SAAWA,EAEhB7qB,KAAK6qB,SAASg0B,WAAa,SAO3B7+C,KAAK0hE,QAAUA,EAOf1hE,KAAK66B,QAAUA,EAMhB,WACC,MAAO,SAQR,QACC,OAAO,IAAI,GAAiB76B,KAAK6qB,SAASa,QAAS1rB,KAAK0hE,QAAS1hE,KAAK66B,QAAS76B,KAAKigE,aAQrF,cACC,OAAO,IAAI,GAAiBjgE,KAAK6qB,SAASa,QAAS1rB,KAAK66B,QAAS76B,KAAK0hE,QAAS1hE,KAAKigE,YAAc,GAMnG,YACC,MAAMrhD,EAAU5e,KAAK6qB,SAASuC,UAE9B,KAAQxO,aAAmB,IAM1B,MAAM,IAAI,KACT,kCACA5e,MAEK,GAAK4e,EAAQ9gB,OAASkC,KAAK0hE,QAMjC,MAAM,IAAI,KACT,8BACA1hE,MAQH,WACiBA,KAAK6qB,SAASuC,UAEtBtvB,KAAOkC,KAAK66B,QAMrB,SACC,MAAM7c,EAAOpe,MAAMk+C,SAInB,OAFA9/B,EAAK6M,SAAW7qB,KAAK6qB,SAASizB,SAEvB9/B,EAMR,uBACC,MAAO,kBAUR,gBAAiBA,EAAMhd,GACtB,OAAO,IAAI,GAAiB,GAAS49C,SAAU5gC,EAAK6M,SAAU7pB,GAAYgd,EAAK0jD,QAAS1jD,EAAK6c,QAAS7c,EAAKiiD,cC3H9F,MAAM,WAA+BC,GAYnD,YAAarjE,EAAMiC,EAAK+oB,EAAU7c,EAAUi1D,GAC3CrgE,MAAOqgE,GAQPjgE,KAAKnD,KAAOA,EAQZmD,KAAKlB,IAAMA,EAQXkB,KAAK6nB,SAAWA,EAQhB7nB,KAAKgL,SAAWA,EAMjB,WACC,OAAuB,OAAlBhL,KAAK6nB,SACF,mBACsB,OAAlB7nB,KAAKgL,SACT,sBAEA,sBAST,QACC,OAAO,IAAI,GAAwBhL,KAAKnD,KAAMmD,KAAKlB,IAAKkB,KAAK6nB,SAAU7nB,KAAKgL,SAAUhL,KAAKigE,aAQ5F,cACC,OAAO,IAAI,GAAwBjgE,KAAKnD,KAAMmD,KAAKlB,IAAKkB,KAAKgL,SAAUhL,KAAK6nB,SAAU7nB,KAAKigE,YAAc,GAM1G,YACC,GAAKjgE,KAAKnD,MAAQmD,KAAKnD,KAAKA,MAAQmD,KAAKnD,KAAKsD,GAAI,oBASjD,MAAM,IAAI,KACT,qCACAH,KACA,CAAEnD,KAAMmD,KAAKnD,KAAMiC,IAAKkB,KAAKlB,MAI/B,GAAuB,OAAlBkB,KAAK6nB,UAAqB7nB,KAAKnD,KAAKuiB,aAAcpf,KAAKlB,OAAUkB,KAAK6nB,SAS1E,MAAM,IAAI,KACT,0CACA7nB,KACA,CAAEnD,KAAMmD,KAAKnD,KAAMiC,IAAKkB,KAAKlB,MAI/B,GAAuB,OAAlBkB,KAAK6nB,UAAuC,OAAlB7nB,KAAKgL,UAAqBhL,KAAKnD,KAAKqiB,aAAclf,KAAKlB,KAQrF,MAAM,IAAI,KACT,2CACAkB,KACA,CAAEnD,KAAMmD,KAAKnD,KAAMiC,IAAKkB,KAAKlB,MAQhC,WACwB,OAAlBkB,KAAKgL,SACThL,KAAKnD,KAAK66B,cAAe13B,KAAKlB,IAAKkB,KAAKgL,UAExChL,KAAKnD,KAAK86B,iBAAkB33B,KAAKlB,KAOnC,SACC,MAAMkf,EAAOpe,MAAMk+C,SAInB,OAFA9/B,EAAKnhB,KAAOmD,KAAKnD,KAAKihD,SAEf9/B,EAMR,uBACC,MAAO,yBAUR,gBAAiBA,EAAMhd,GACtB,IAAMA,EAAS+7C,QAAS/+B,EAAKnhB,MAO5B,MAAM,IAAI,KAAe,2CAA4CmD,KAAM,CAAEuqB,SAAUvM,EAAKnhB,OAG7F,OAAO,IAAI,GAAwBmE,EAAS+7C,QAAS/+B,EAAKnhB,MAAQmhB,EAAKlf,IAAKkf,EAAK6J,SAAU7J,EAAKhT,SAAUgT,EAAKiiD,cC/KlG,MAAM,WAAuBC,GAY3C,YAAajgB,EAAgBh5B,EAASqR,EAAgBgoB,EAAmB2f,GACxErgE,MAAOqgE,GAOPjgE,KAAKigD,eAAiBA,EAAev0B,QAErC1rB,KAAKigD,eAAepB,WAAa,aAOjC7+C,KAAKinB,QAAUA,EAOfjnB,KAAKs4B,eAAiBA,EAAe5M,QAGrC1rB,KAAKs4B,eAAeumB,WAAa,SAOjC7+C,KAAKsgD,kBAAoBA,EAAkB50B,QAM5C,WACC,MAAO,QASR,uBACC,OAAO,IAAI,GAAU1rB,KAAKigD,eAAepjD,KAAMmD,KAAKigD,eAAepwC,KAAKpI,MAAO,GAAI,IAUpF,iBACC,MAAMqZ,EAAM9gB,KAAKigD,eAAe3xB,aAAcpT,OAAOkhB,mBAErD,OAAO,IAAI,GAAOp8B,KAAKigD,eAAgBn/B,GAQxC,QACC,OAAO,IAAI9gB,KAAK0H,YAAa1H,KAAKigD,eAAgBjgD,KAAKinB,QAASjnB,KAAKs4B,eAAgBt4B,KAAKsgD,kBAAmBtgD,KAAKigE,aAQnH,cAIC,MAAM3nC,EAAiBt4B,KAAKs4B,eAAewnB,gCAAiC9/C,MAEtE6P,EAAO7P,KAAKigD,eAAepwC,KAAKpI,MAAO,GAAI,GAC3C8xB,EAAoB,IAAI,GAAUv5B,KAAKigD,eAAepjD,KAAMgT,GAAOiwC,gCAAiC9/C,MAEpGuP,EAAQ,IAAI,GAAgB+oB,EAAgBt4B,KAAKinB,QAASjnB,KAAKsgD,kBAAmBtgD,KAAKigE,YAAc,GAG3G,OAFA1wD,EAAMgqB,kBAAoBA,EAEnBhqB,EAMR,YACC,MAAM0xD,EAAgBjhE,KAAKigD,eAAeljC,OACpCmkD,EAAgBlhE,KAAKs4B,eAAevb,OAG1C,IAAMkkD,EAAclkD,OAMnB,MAAM,IAAI,KAAe,0CAA2C/c,MAC9D,IAAMkhE,EAAcnkD,OAM1B,MAAM,IAAI,KAAe,0CAA2C/c,MAC9D,GAAKA,KAAKinB,SAAWg6C,EAAc/iB,UAMzC,MAAM,IAAI,KAAe,mCAAoCl+C,MAO/D,WACC,MAAM2hE,EAAgB3hE,KAAKigD,eAAeljC,OAG1CwjD,GAFoB,GAAM3vC,UAAW+wC,GAEjB3hE,KAAKs4B,gBACzBioC,GAAO,GAAM1vC,UAAW8wC,GAAiB3hE,KAAKsgD,mBAM/C,SACC,MAAMtiC,EAAOpe,MAAMk+C,SAMnB,OAJA9/B,EAAKiiC,eAAiBjiC,EAAKiiC,eAAenC,SAC1C9/B,EAAKsa,eAAiBta,EAAKsa,eAAewlB,SAC1C9/B,EAAKsiC,kBAAoBtiC,EAAKsiC,kBAAkBxC,SAEzC9/B,EAMR,uBACC,MAAO,iBAUR,gBAAiBA,EAAMhd,GACtB,MAAMi/C,EAAiB,GAASrB,SAAU5gC,EAAKiiC,eAAgBj/C,GACzDs3B,EAAiB,GAASsmB,SAAU5gC,EAAKsa,eAAgBt3B,GACzDs/C,EAAoB,GAAS1B,SAAU5gC,EAAKsiC,kBAAmBt/C,GAErE,OAAO,IAAIhB,KAAMigD,EAAgBjiC,EAAKiJ,QAASqR,EAAgBgoB,EAAmBtiC,EAAKiiD,cC1L1E,MAAM,WAAuBC,GAW3C,YAAa9f,EAAen5B,EAASq5B,EAAmB2f,GACvDrgE,MAAOqgE,GAOPjgE,KAAKogD,cAAgBA,EAAc10B,QAGnC1rB,KAAKogD,cAAcvB,WAAa,SAOhC7+C,KAAKinB,QAAUA,EAOfjnB,KAAKu5B,kBAAoB,GAAeqoC,qBAAsBxhB,GAC9DpgD,KAAKu5B,kBAAkBslB,WAAa,SAUpC7+C,KAAKsgD,kBAAoBA,EAAoBA,EAAkB50B,QAAU,KAEpE1rB,KAAKsgD,oBACTtgD,KAAKsgD,kBAAkBzB,WAAa,UAOtC,WACC,MAAO,QAWR,yBACC,MAAMhvC,EAAO7P,KAAKu5B,kBAAkB1pB,KAAKpI,QAGzC,OAFAoI,EAAK5M,KAAM,GAEJ,IAAI,GAAUjD,KAAKu5B,kBAAkB18B,KAAMgT,GAUnD,iBACC,MAAMiR,EAAM9gB,KAAKogD,cAAc9xB,aAAcpT,OAAOkhB,mBAEpD,OAAO,IAAI,GAAOp8B,KAAKogD,cAAet/B,GAQvC,QACC,MAAMvR,EAAQ,IAAIvP,KAAK0H,YAAa1H,KAAKogD,cAAepgD,KAAKinB,QAASjnB,KAAKsgD,kBAAmBtgD,KAAKigE,aAGnG,OAFA1wD,EAAMgqB,kBAAoBv5B,KAAKu5B,kBAExBhqB,EAQR,cACC,MAAMsxC,EAAY7gD,KAAKogD,cAAcvjD,KAAKmE,SAAS6/C,UAC7CP,EAAoB,IAAI,GAAUO,EAAW,CAAE,IAErD,OAAO,IAAI,GAAgB7gD,KAAKqgD,mBAAoBrgD,KAAKinB,QAASjnB,KAAKogD,cAAeE,EAAmBtgD,KAAKigE,YAAc,GAM7H,YACC,MAAMrhD,EAAU5e,KAAKogD,cAAcrjC,OAC7BzQ,EAAStM,KAAKogD,cAAc9zC,OAGlC,IAAMsS,GAAWA,EAAQs/B,UAAY5xC,EAMpC,MAAM,IAAI,KAAe,mCAAoCtM,MACvD,IAAM4e,EAAQ7B,OAMpB,MAAM,IAAI,KAAe,gCAAiC/c,MACpD,GAAKA,KAAKinB,SAAWrI,EAAQs/B,UAAYl+C,KAAKogD,cAAc9zC,OAMlE,MAAM,IAAI,KAAe,mCAAoCtM,MACvD,GAAKA,KAAKsgD,oBAAsBtgD,KAAKsgD,kBAAkBlzB,UAM7D,MAAM,IAAI,KAAe,6CAA8CptB,MAOzE,WACC,MAAM6hE,EAAe7hE,KAAKogD,cAAcrjC,OAExC,GAAK/c,KAAKsgD,kBACTigB,GAAO,GAAM9xC,4BAA6BzuB,KAAKsgD,kBAAmB,GAAKtgD,KAAKu5B,uBACtE,CACN,MAAMnB,EAAaypC,EAAal7C,SAEhCsZ,GAASjgC,KAAKu5B,kBAAmBnB,GAQlCmoC,GALoB,IAAI,GACvB,GAASz1C,UAAW+2C,EAAc7hE,KAAKogD,cAAc9zC,QACrD,GAASwe,UAAW+2C,EAAcA,EAAa3jB,YAG5Bl+C,KAAKqgD,oBAM1B,SACC,MAAMriC,EAAOpe,MAAMk+C,SASnB,OAPA9/B,EAAKoiC,cAAgBpgD,KAAKogD,cAActC,SACxC9/B,EAAKub,kBAAoBv5B,KAAKu5B,kBAAkBukB,SAE3C99C,KAAKsgD,oBACTtiC,EAAKsiC,kBAAoBtgD,KAAKsgD,kBAAkBxC,UAG1C9/B,EAMR,uBACC,MAAO,iBAUR,4BAA6BoiC,GAC5B,MAAMvwC,EAAOuwC,EAAcvwC,KAAKpI,MAAO,GAAI,GAG3C,OAFAoI,EAAMA,EAAK9N,OAAS,KAEb,IAAI,GAAUq+C,EAAcvjD,KAAMgT,GAU1C,gBAAiBmO,EAAMhd,GACtB,MAAMo/C,EAAgB,GAASxB,SAAU5gC,EAAKoiC,cAAep/C,GACvDu4B,EAAoB,GAASqlB,SAAU5gC,EAAKub,kBAAmBv4B,GAC/Ds/C,EAAoBtiC,EAAKsiC,kBAAoB,GAAS1B,SAAU5gC,EAAKsiC,kBAAmBt/C,GAAa,KAErGuO,EAAQ,IAAIvP,KAAMogD,EAAepiC,EAAKiJ,QAASq5B,EAAmBtiC,EAAKiiD,aAG7E,OAFA1wD,EAAMgqB,kBAAoBA,EAEnBhqB,GC3OM,MAAM,WAAoB,GASxC,YAAavO,EAAUlD,EAAMysB,EAAW,QACvC3qB,MAAO9B,GAQPkC,KAAKq3B,UAAYr2B,EAQjBhB,KAAKuqB,SAAWA,EASjB,eACC,OAAOvqB,KAAKq3B,UA2Bb,GAAIp3B,EAAMnC,GACT,OAAMA,EAOCA,IAASkC,KAAKlC,OACX,gBAATmC,GAAmC,sBAATA,GAEjB,YAATA,GAA+B,kBAATA,GATN,gBAATA,GAAmC,sBAATA,GAEvB,YAATA,GAA+B,kBAATA,GACb,SAATA,GAA4B,eAATA,EAetB,SACC,OAAOD,KAAKuqB,UC/CC,MAAM,GAWpB,YAAay+B,EAAOmC,GAOnBnrD,KAAKgpD,MAAQA,EAQbhpD,KAAKmrD,MAAQA,EAad,WAAYxrD,EAAM2D,GACjB,OAAO,IAAI,GAAM3D,EAAM2D,GAaxB,cAAexF,EAAMwF,GACpB,OAAO,IAAI,GAASxF,EAAMwF,GAQ3B,yBACC,OAAO,IAAI,GAWZ,aAAcsb,EAAS2H,GAAO,GAC7B,OAAO3H,EAAQ+H,OAAQJ,GA2CxB,OAAQlkB,EAAM0qB,EAAgBzgB,EAAS,GAGtC,GAFAtM,KAAK8hE,6BAEAz/D,aAAgB,IAAqB,IAAbA,EAAK1C,KACjC,OAGD,MAAMkrB,EAAW,GAASC,UAAWiC,EAAgBzgB,GAGrD,GAAKjK,EAAK0a,OAAS,CAElB,GAAKglD,GAAY1/D,EAAKxF,KAAMguB,EAAShuB,MAIpC,YAFAmD,KAAKu4B,KAAM,GAAM1H,UAAWxuB,GAAQwoB,GAMpC,GAAKxoB,EAAKxF,KAAKmE,SAOd,MAAM,IAAI,KACT,qCACAhB,MAKDA,KAAKmE,OAAQ9B,GAKhB,MAAM87D,EAAUtzC,EAAShuB,KAAKmE,SAAW6pB,EAAShuB,KAAKmE,SAASm9D,QAAU,KAEpEx6D,EAAS,IAAI,GAAiBknB,EAAUxoB,EAAM87D,GAUpD,GARK97D,aAAgB,KACpBsB,EAAO09D,yBAA0B,GAGlCrhE,KAAKmrD,MAAM6W,aAAcr+D,GACzB3D,KAAKgpD,MAAMiZ,eAAgBt+D,GAGtBtB,aAAgB,GACpB,IAAM,MAAQ6gD,EAAY8C,KAAiB3jD,EAAK8iD,QAAU,CAEzD,MAAM+c,EAAoB,GAASp3C,UAAWk7B,EAAYnpD,KAAM,GAM1DqF,EAAU,CAAE+sB,MALJ,IAAI,GACjB+2B,EAAYnlC,MAAMs/B,aAAc+hB,EAAmBr3C,GACnDm7B,EAAYllC,IAAIq/B,aAAc+hB,EAAmBr3C,IAGzBs3C,gBAAgB,EAAMX,aAAa,GAEvDxhE,KAAKgpD,MAAM7D,QAAQz7C,IAAKw5C,GAC5BljD,KAAKoiE,aAAclf,EAAYhhD,GAE/BlC,KAAKqiE,UAAWnf,EAAYhhD,IA8BhC,WAAYqwC,EAAMjvC,EAAYypB,EAAgBzgB,GACxChJ,aAAsB,IAAoBA,aAAsB,IAAWA,aAAsB,GACrGtD,KAAK2D,OAAQ3D,KAAKw0D,WAAYjiB,GAAQjvC,EAAYypB,GAElD/sB,KAAK2D,OAAQ3D,KAAKw0D,WAAYjiB,EAAMjvC,GAAcypB,EAAgBzgB,GA4BpE,cAAexO,EAAMwF,EAAYypB,EAAgBzgB,GAC3ChJ,aAAsB,IAAoBA,aAAsB,IAAWA,aAAsB,GACrGtD,KAAK2D,OAAQ3D,KAAKqD,cAAevF,GAAQwF,EAAYypB,GAErD/sB,KAAK2D,OAAQ3D,KAAKqD,cAAevF,EAAMwF,GAAcypB,EAAgBzgB,GAmBvE,OAAQjK,EAAM0a,GACb/c,KAAK2D,OAAQtB,EAAM0a,EAAQ,OAa5B,WAAYw1B,EAAMjvC,EAAYyZ,GACxBzZ,aAAsB,IAAoBA,aAAsB,GACpEtD,KAAK2D,OAAQ3D,KAAKw0D,WAAYjiB,GAAQjvC,EAAY,OAElDtD,KAAK2D,OAAQ3D,KAAKw0D,WAAYjiB,EAAMjvC,GAAcyZ,EAAQ,OAc5D,cAAejf,EAAMwF,EAAYyZ,GAC3BzZ,aAAsB,IAAoBA,aAAsB,GACpEtD,KAAK2D,OAAQ3D,KAAKqD,cAAevF,GAAQwF,EAAY,OAErDtD,KAAK2D,OAAQ3D,KAAKqD,cAAevF,EAAMwF,GAAcyZ,EAAQ,OAa/D,aAAcje,EAAKN,EAAO8jE,GAGzB,GAFAtiE,KAAK8hE,6BAEAQ,aAAuB,GAAQ,CACnC,MAAMz0C,EAASy0C,EAAY7K,uBAE3B,IAAM,MAAMxoC,KAASpB,EACpB00C,GAAqBviE,KAAMlB,EAAKN,EAAOywB,QAGxCuzC,GAAoBxiE,KAAMlB,EAAKN,EAAO8jE,GAiBxC,cAAeh/D,EAAYg/D,GAC1B,IAAM,MAAQxjE,EAAKoR,KAASoO,GAAOhb,GAClCtD,KAAK0D,aAAc5E,EAAKoR,EAAKoyD,GAY/B,gBAAiBxjE,EAAKwjE,GAGrB,GAFAtiE,KAAK8hE,6BAEAQ,aAAuB,GAAQ,CACnC,MAAMz0C,EAASy0C,EAAY7K,uBAE3B,IAAM,MAAMxoC,KAASpB,EACpB00C,GAAqBviE,KAAMlB,EAAK,KAAMmwB,QAGvCuzC,GAAoBxiE,KAAMlB,EAAK,KAAMwjE,GAUvC,gBAAiBA,GAChBtiE,KAAK8hE,6BAEL,MAAMW,EAA2BpgE,IAChC,IAAM,MAAM8c,KAAa9c,EAAKmzB,mBAC7Bx1B,KAAK4E,gBAAiBua,EAAW9c,IAInC,GAAQigE,aAAuB,GAG9B,IAAM,MAAMjgE,KAAQigE,EAAYhb,WAC/Bmb,EAA0BpgE,QAH3BogE,EAA0BH,GAmC5B,KAAMrzC,EAAOlC,EAAgBzgB,GAG5B,GAFAtM,KAAK8hE,+BAEG7yC,aAAiB,IAMxB,MAAM,IAAI,KAAe,4BAA6BjvB,MAGvD,IAAMivB,EAAM1gB,OAMX,MAAM,IAAI,KAAe,6BAA8BvO,MAGxD,MAAM6qB,EAAW,GAASC,UAAWiC,EAAgBzgB,GAGrD,GAAKue,EAASyB,QAAS2C,EAAMpO,OAC5B,OAMD,GAFA7gB,KAAK0iE,gCAAiC,OAAQzzC,IAExC8yC,GAAY9yC,EAAMpyB,KAAMguB,EAAShuB,MAOtC,MAAM,IAAI,KAAe,iCAAkCmD,MAG5D,MAAMm+D,EAAUlvC,EAAMpyB,KAAKmE,SAAWiuB,EAAMpyB,KAAKmE,SAASm9D,QAAU,KAC9Dze,EAAY,IAAI,GAAezwB,EAAMpO,MAAOoO,EAAMnO,IAAIxU,OAAS2iB,EAAMpO,MAAMvU,OAAQue,EAAUszC,GAEnGn+D,KAAKmrD,MAAM6W,aAActiB,GACzB1/C,KAAKgpD,MAAMiZ,eAAgBviB,GAQ5B,OAAQ4iB,GACPtiE,KAAK8hE,6BAEL,MACMj0C,GADgBy0C,aAAuB,GAAQA,EAAc,GAAMzxC,UAAWyxC,IACvD7K,uBAAuB33B,UAEpD,IAAM,MAAM6iC,KAAQ90C,EAEnB7tB,KAAK0iE,gCAAiC,OAAQC,GAE9CC,GAAsBD,EAAK9hD,MAAO8hD,EAAK7hD,IAAIxU,OAASq2D,EAAK9hD,MAAMvU,OAAQtM,KAAKmrD,MAAOnrD,KAAKgpD,OAY1F,MAAOn+B,GACN7qB,KAAK8hE,6BAEL,MAAMx0C,EAAazC,EAASyC,WACtBF,EAAYvC,EAASuC,UAK3B,GAFAptB,KAAK0iE,gCAAiC,QAAS73C,KAEvCyC,aAAsB,IAM7B,MAAM,IAAI,KAAe,iCAAkCttB,MAG5D,KAAQotB,aAAqB,IAM5B,MAAM,IAAI,KAAe,gCAAiCptB,MAGrD6qB,EAAShuB,KAAKmE,SAGnBhB,KAAK6iE,OAAQh4C,GAFb7qB,KAAK8iE,eAAgBj4C,GAevB,uBAAwBhuB,EAAMgT,EAAMgvC,GACnC,OAAO7+C,KAAKgpD,MAAM+Z,uBAAwBlmE,EAAMgT,EAAMgvC,GAWvD,iBAAkB9xB,EAAgBzgB,GACjC,OAAOtM,KAAKgpD,MAAMoI,iBAAkBrkC,EAAgBzgB,GASrD,oBAAqBjK,GACpB,OAAOrC,KAAKgpD,MAAM2T,oBAAqBt6D,GASxC,qBAAsBA,GACrB,OAAOrC,KAAKgpD,MAAMsT,qBAAsBj6D,GAUzC,YAAawe,EAAOC,GACnB,OAAO9gB,KAAKgpD,MAAM1iB,YAAazlB,EAAOC,GASvC,cAAelC,GACd,OAAO5e,KAAKgpD,MAAM0L,cAAe91C,GASlC,cAAeA,GACd,OAAO5e,KAAKgpD,MAAMjC,cAAenoC,GAYlC,gBAAiB+P,EAAYC,EAAe1sB,GAC3C,OAAOlC,KAAKgpD,MAAMsL,gBAAiB3lC,EAAYC,EAAe1sB,GAS/D,eAAgB2oB,GACf,MAAMyC,EAAazC,EAASyC,WACtBF,EAAYvC,EAASuC,UAE3BptB,KAAKu4B,KAAM,GAAM3H,UAAWxD,GAAa,GAAStC,UAAWwC,EAAY,QACzEttB,KAAKmE,OAAQipB,GASd,OAAQvC,GACP,MAAMyN,EAAiB,GAASxN,UAAWD,EAASyC,WAAY,OAC1D2yB,EAAiB,GAASn1B,UAAWD,EAASuC,UAAW,GAEzDyzB,EAAYh2B,EAAShuB,KAAKmE,SAAS6/C,UACnCP,EAAoB,IAAI,GAAUO,EAAW,CAAE,IAE/Csd,EAAUtzC,EAAShuB,KAAKmE,SAASm9D,QAEjC6E,EAAQ,IAAI,GAAgB/iB,EAAgBp1B,EAASuC,UAAU8wB,UAAW5lB,EAAgBgoB,EAAmB6d,GAEnHn+D,KAAKmrD,MAAM6W,aAAcgB,GACzBhjE,KAAKgpD,MAAMiZ,eAAgBe,GAS5B,OAAQpkD,EAASic,GAGhB,GAFA76B,KAAK8hE,+BAEGljD,aAAmB,IAM1B,MAAM,IAAI,KACT,qCACA5e,MAIF,MAAMm+D,EAAUv/C,EAAQ/hB,KAAKmE,SAAW4d,EAAQ/hB,KAAKmE,SAASm9D,QAAU,KAClE8E,EAAkB,IAAI,GAAiB,GAAS92C,cAAevN,GAAWA,EAAQ9gB,KAAM+8B,EAASsjC,GAEvGn+D,KAAKmrD,MAAM6W,aAAciB,GACzBjjE,KAAKgpD,MAAMiZ,eAAgBgB,GAiB5B,MAAOp4C,EAAUitC,GAChB93D,KAAK8hE,6BAEL,IA4BIoB,EAAmBC,EA5BnBtB,EAAeh3C,EAAS9N,OAE5B,IAAM8kD,EAAa9kD,OAMlB,MAAM,IAAI,KAAe,iCAAkC/c,MAQ5D,GAJM83D,IACLA,EAAe+J,EAAa9kD,SAGvB8N,EAAS9N,OAAOS,aAAc,CAAEJ,aAAa,IAAShE,SAAU0+C,GAMrE,MAAM,IAAI,KAAe,qCAAsC93D,MAQhE,EAAG,CACF,MAAMm+D,EAAU0D,EAAahlE,KAAKmE,SAAW6gE,EAAahlE,KAAKmE,SAASm9D,QAAU,KAC5El3C,EAAU46C,EAAa3jB,UAAYrzB,EAASve,OAC5CiD,EAAQ,IAAI,GAAgBsb,EAAU5D,EAAS,KAAMk3C,GAE3Dn+D,KAAKmrD,MAAM6W,aAAczyD,GACzBvP,KAAKgpD,MAAMiZ,eAAgB1yD,GAGrB2zD,GAAsBC,IAC3BD,EAAoBrB,EACpBsB,EAAmBt4C,EAAS9N,OAAOmR,aAIpC2zC,GADAh3C,EAAW7qB,KAAK28D,oBAAqB9xC,EAAS9N,SACtBA,aACf8kD,IAAiB/J,GAE3B,MAAO,CACNjtC,WACAoE,MAAO,IAAI,GAAO,GAASnE,UAAWo4C,EAAmB,OAAS,GAASp4C,UAAWq4C,EAAkB,KAa1G,KAAMl0C,EAAOm0C,GAGZ,GAFApjE,KAAK8hE,8BAEC7yC,EAAM1gB,OAMX,MAAM,IAAI,KAAe,6BAA8BvO,MAGxD,MAAM4e,EAAUwkD,aAA2B,GAAUA,EAAkB,IAAI,GAASA,GAEpF,GAAKxkD,EAAQkI,WAAa,EAMzB,MAAM,IAAI,KAAe,gCAAiC9mB,MAG3D,GAAwB,OAAnB4e,EAAQ7B,OAMZ,MAAM,IAAI,KAAe,+BAAgC/c,MAG1DA,KAAK2D,OAAQib,EAASqQ,EAAMpO,OAG5B,MAAMwiD,EAAe,IAAI,GAAOp0C,EAAMpO,MAAMyN,aAAc,GAAKW,EAAMnO,IAAIwN,aAAc,IAEvFtuB,KAAKu4B,KAAM8qC,EAAc,GAASv4C,UAAWlM,EAAS,IASvD,OAAQA,GAGP,GAFA5e,KAAK8hE,6BAEmB,OAAnBljD,EAAQ7B,OAMZ,MAAM,IAAI,KAAe,kCAAmC/c,MAG7DA,KAAKu4B,KAAM,GAAM3H,UAAWhS,GAAW5e,KAAK28D,oBAAqB/9C,IACjE5e,KAAKmE,OAAQya,GA0Cd,UAAW9gB,EAAMoE,GAGhB,GAFAlC,KAAK8hE,8BAEC5/D,GAA4C,kBAA1BA,EAAQigE,eAM/B,MAAM,IAAI,KAAe,qCAAsCniE,MAGhE,MAAMmiE,EAAiBjgE,EAAQigE,eACzBlzC,EAAQ/sB,EAAQ+sB,MAChBuyC,OAAsCl7D,IAAxBpE,EAAQs/D,aAAoCt/D,EAAQs/D,YAExE,GAAKxhE,KAAKgpD,MAAM7D,QAAQz7C,IAAK5L,GAM5B,MAAM,IAAI,KAAe,iCAAkCkC,MAG5D,IAAMivB,EAML,MAAM,IAAI,KAAe,4BAA6BjvB,MAGvD,OAAMmiE,GAINmB,GAAsBtjE,KAAMlC,EAAM,KAAMmxB,EAAOuyC,GAExCxhE,KAAKgpD,MAAM7D,QAAQ/mD,IAAKN,IALvBkC,KAAKgpD,MAAM7D,QAAQoe,KAAMzlE,EAAMmxB,EAAOkzC,EAAgBX,GA6E/D,aAAcgC,EAActhE,GAC3BlC,KAAK8hE,6BAEL,MAAM5e,EAAoC,iBAAhBsgB,EAA2BA,EAAeA,EAAa1lE,KAC3E2lE,EAAgBzjE,KAAKgpD,MAAM7D,QAAQ/mD,IAAK8kD,GAE9C,IAAMugB,EAML,MAAM,IAAI,KAAe,wCAAyCzjE,MAGnE,IAAMkC,EAGL,YAFAlC,KAAKgpD,MAAM7D,QAAQue,SAAUD,GAK9B,MAAME,EAA4D,kBAA1BzhE,EAAQigE,eAC1CyB,EAAmD,kBAAvB1hE,EAAQs/D,YAGpCA,EAAcoC,EAAqB1hE,EAAQs/D,YAAciC,EAAcjC,YAE7E,IAAMmC,IAA6BzhE,EAAQ+sB,QAAU20C,EAMpD,MAAM,IAAI,KAAe,oCAAqC5jE,MAG/D,MAAM6jE,EAAeJ,EAAcxd,WAC7B6d,EAAe5hE,EAAQ+sB,MAAQ/sB,EAAQ+sB,MAAQ40C,EAEhDF,GAA4BzhE,EAAQigE,iBAAmBsB,EAAcM,uBAEpE7hE,EAAQigE,eAGZmB,GAAsBtjE,KAAMkjD,EAAY,KAAM4gB,EAActC,IAI5D8B,GAAsBtjE,KAAMkjD,EAAY2gB,EAAc,KAAMrC,GAG5DxhE,KAAKgpD,MAAM7D,QAAQoe,KAAMrgB,EAAY4gB,OAAcx9D,EAAWk7D,IAO3DiC,EAAcM,uBAClBT,GAAsBtjE,KAAMkjD,EAAY2gB,EAAcC,EAActC,GAEpExhE,KAAKgpD,MAAM7D,QAAQoe,KAAMrgB,EAAY4gB,OAAcx9D,EAAWk7D,GAWhE,aAAcgC,GACbxjE,KAAK8hE,6BAEL,MAAMhkE,EAA8B,iBAAhB0lE,EAA2BA,EAAeA,EAAa1lE,KAE3E,IAAMkC,KAAKgpD,MAAM7D,QAAQz7C,IAAK5L,GAM7B,MAAM,IAAI,KAAe,gCAAiCkC,MAG3D,MAAMonD,EAASpnD,KAAKgpD,MAAM7D,QAAQ/mD,IAAKN,GAEvC,IAAMspD,EAAO2c,uBAGZ,YAFA/jE,KAAKgpD,MAAM7D,QAAQjvC,QAASpY,GAO7BwlE,GAAsBtjE,KAAMlC,EAFXspD,EAAOnB,WAEoB,KAAMmB,EAAOoa,aAsD1D,aAAc7yC,EAAYC,EAAe1sB,GACxClC,KAAK8hE,6BAEL9hE,KAAKgpD,MAAMhoD,SAASopB,UAAU8M,OAAQvI,EAAYC,EAAe1sB,GAalE,kBAAmB6qB,EAAgBzgB,GAClCtM,KAAK8hE,6BAEL9hE,KAAKgpD,MAAMhoD,SAASopB,UAAU+M,UAAWpK,EAAgBzgB,GAsB1D,sBAAuB03D,EAAuBxlE,GAG7C,GAFAwB,KAAK8hE,6BAEiC,iBAA1BkC,EACXhkE,KAAKikE,uBAAwBD,EAAuBxlE,QAEpD,IAAM,MAAQM,EAAKN,KAAW8f,GAAO0lD,GACpChkE,KAAKikE,uBAAwBnlE,EAAKN,GAkBrC,yBAA0B0lE,GAGzB,GAFAlkE,KAAK8hE,6BAE+B,iBAAxBoC,EACXlkE,KAAKmkE,0BAA2BD,QAEhC,IAAM,MAAMplE,KAAOolE,EAClBlkE,KAAKmkE,0BAA2BrlE,GAyBnC,2BACC,OAAOkB,KAAKgpD,MAAMhoD,SAASopB,UAAUg6C,mBAYtC,wBAAyBz6D,GACxB3J,KAAKgpD,MAAMhoD,SAASopB,UAAUi6C,gBAAiB16D,GAQhD,uBAAwB7K,EAAKN,GAC5B,MAAM4rB,EAAYpqB,KAAKgpD,MAAMhoD,SAASopB,UAGtC,GAAKA,EAAUqD,aAAerD,EAAU+E,OAAOpS,OAAO0F,QAAU,CAC/D,MAAM6hD,EAAW,GAAkBC,sBAAuBzlE,GAE1DkB,KAAK0D,aAAc4gE,EAAU9lE,EAAO4rB,EAAU+E,OAAOpS,QAGtDqN,EAAUsN,cAAe54B,EAAKN,GAO/B,0BAA2BM,GAC1B,MAAMsrB,EAAYpqB,KAAKgpD,MAAMhoD,SAASopB,UAGtC,GAAKA,EAAUqD,aAAerD,EAAU+E,OAAOpS,OAAO0F,QAAU,CAC/D,MAAM6hD,EAAW,GAAkBC,sBAAuBzlE,GAE1DkB,KAAK4E,gBAAiB0/D,EAAUl6C,EAAU+E,OAAOpS,QAGlDqN,EAAUuN,iBAAkB74B,GAQ7B,6BAUC,GAAKkB,KAAKgpD,MAAMwb,iBAAmBxkE,KAClC,MAAM,IAAI,KAAe,uBAAwBA,MAcnD,gCAAiCC,EAAMg4B,GACtC,IAAM,MAAMmvB,KAAUpnD,KAAKgpD,MAAM7D,QAAU,CAC1C,IAAMiC,EAAO2c,uBACZ,SAGD,MAAM/d,EAAcoB,EAAOnB,WAC3B,IAAIwe,GAAa,EAEjB,GAAc,SAATxkE,EACJwkE,EACCxsC,EAAgBtK,iBAAkBq4B,EAAYnlC,QAC9CoX,EAAgBpX,MAAMyL,QAAS05B,EAAYnlC,QAC3CoX,EAAgBtK,iBAAkBq4B,EAAYllC,MAC9CmX,EAAgBnX,IAAIwL,QAAS05B,EAAYllC,SACpC,CAEN,MAAM4jD,EAAgBzsC,EAAgB3K,WAChCq3C,EAAe1sC,EAAgB7K,UAM/Bw3C,EAAwB5e,EAAYnlC,MAAM9D,QAAU2nD,GAAiB1e,EAAYnlC,MAAM+K,QAMvFi5C,EAAyB7e,EAAYllC,IAAI/D,QAAU4nD,GAA0C,GAA1B3e,EAAYllC,IAAIxU,OAMnFw4D,EAA2B9e,EAAYllC,IAAIsM,WAAau3C,EAMxDI,EAA6B/e,EAAYnlC,MAAMuM,WAAau3C,EAElEF,EAAaG,GAAyBC,GAA0BC,GAA4BC,EAGxFN,GACJzkE,KAAKoiE,aAAchb,EAAOtpD,KAAM,CAAEmxB,MAAO+2B,MAkB7C,SAASuc,GAAqBvwC,EAAQlzB,EAAKN,EAAOywB,GACjD,MAAM+5B,EAAQh3B,EAAOg3B,MACf5hB,EAAM4hB,EAAMhoD,SAGlB,IAII6pB,EAGAm6C,EAGAC,EAVAC,EAAoBj2C,EAAMpO,MAY9B,IAAM,MAAM3Q,KAAO+e,EAAMgL,UAAW,CAAEjP,SAAS,IAC9Ci6C,EAAa/0D,EAAI7N,KAAK+c,aAActgB,GAI/B+rB,GAAYm6C,GAAeC,IAE1BD,GAAexmE,GACnBwjE,IAGDkD,EAAoBr6C,GAGrBA,EAAW3a,EAAImc,aACf24C,EAAcC,EASf,SAASjD,IACR,MAAM/yC,EAAQ,IAAI,GAAOi2C,EAAmBr6C,GACtCszC,EAAUlvC,EAAMpyB,KAAKmE,SAAWomC,EAAI+2B,QAAU,KAC9Cze,EAAY,IAAI,GAAoBzwB,EAAOnwB,EAAKkmE,EAAaxmE,EAAO2/D,GAE1EnsC,EAAOm5B,MAAM6W,aAActiB,GAC3BsJ,EAAMiZ,eAAgBviB,GAVlB70B,aAAoB,IAAYA,GAAYq6C,GAAqBF,GAAexmE,GACpFwjE,IAoBF,SAASQ,GAAoBxwC,EAAQlzB,EAAKN,EAAO6D,GAChD,MAAM2mD,EAAQh3B,EAAOg3B,MACf5hB,EAAM4hB,EAAMhoD,SACZmkE,EAAgB9iE,EAAK+c,aAActgB,GACzC,IAAImwB,EAAOywB,EAEX,GAAKylB,GAAiB3mE,EAAQ,CAG7B,GAFsB6D,EAAKxF,OAASwF,EAEf,CAEpB,MAAM87D,EAAU97D,EAAKrB,SAAWomC,EAAI+2B,QAAU,KAE9Cze,EAAY,IAAI,GAAwBr9C,EAAMvD,EAAKqmE,EAAe3mE,EAAO2/D,OACnE,CACNlvC,EAAQ,IAAI,GAAO,GAAS9C,cAAe9pB,GAAQ2vB,EAAO2qC,oBAAqBt6D,IAE/E,MAAM87D,EAAUlvC,EAAMpyB,KAAKmE,SAAWomC,EAAI+2B,QAAU,KAEpDze,EAAY,IAAI,GAAoBzwB,EAAOnwB,EAAKqmE,EAAe3mE,EAAO2/D,GAGvEnsC,EAAOm5B,MAAM6W,aAActiB,GAC3BsJ,EAAMiZ,eAAgBviB,IAYxB,SAAS4jB,GAAsBtxC,EAAQl0B,EAAMkqD,EAAUrtB,EAAU6mC,GAChE,MAAMxY,EAAQh3B,EAAOg3B,MACf5hB,EAAM4hB,EAAMhoD,SAEZ0+C,EAAY,IAAI,GAAiB5hD,EAAMkqD,EAAUrtB,EAAUquB,EAAM7D,QAASqc,EAAap6B,EAAI+2B,SAEjGnsC,EAAOm5B,MAAM6W,aAActiB,GAC3BsJ,EAAMiZ,eAAgBviB,GAWvB,SAASkjB,GAAsB/3C,EAAU5D,EAASkkC,EAAOnC,GACxD,IAAItJ,EAEJ,GAAK70B,EAAShuB,KAAKmE,SAAW,CAC7B,MAAMomC,EAAM4hB,EAAMhoD,SACZs/C,EAAoB,IAAI,GAAUlZ,EAAIyZ,UAAW,CAAE,IAEzDnB,EAAY,IAAI,GAAe70B,EAAU5D,EAASq5B,EAAmBlZ,EAAI+2B,cAEzEze,EAAY,IAAI,GAAiB70B,EAAU5D,GAG5CkkC,EAAM6W,aAActiB,GACpBsJ,EAAMiZ,eAAgBviB,GAUvB,SAASqiB,GAAYqD,EAAOC,GAE3B,OAAKD,IAAUC,GAKVD,aAAiB,IAAeC,aAAiB,GC1gDxC,MAAM,GAMpB,YAAaC,GAOZtlE,KAAKulE,kBAAoBD,EAWzBtlE,KAAKwlE,kBAAoB,IAAI1xD,IAU7B9T,KAAKylE,kBAAoB,IAAI3xD,IAY7B9T,KAAK0lE,gBAAkB,IAAI5xD,IAS3B9T,KAAK2lE,aAAe,EAYpB3lE,KAAK4lE,eAAiB,KAYtB5lE,KAAK6lE,4BAA8B,KASpC,cACC,OAAsC,GAA/B7lE,KAAKwlE,kBAAkBx8D,MAA0C,GAA7BhJ,KAAK0lE,gBAAgB18D,KASjE,YAAa3G,GACZ,GAAKrC,KAAK8lE,qBAAsBzjE,EAAK0a,QACpC,OAGD/c,KAAK+lE,YAAa1jE,EAAK0a,OAAQ1a,EAAK+pB,YAAa/pB,EAAKmsB,YACtDxuB,KAAKgmE,YAAa3jE,EAAK0a,OAAQ1a,EAAK+pB,YAAa/pB,EAAKmsB,YAEtD,MAAMS,EAAQ,GAAM4B,UAAWxuB,GAE/B,IAAM,MAAM+kD,KAAUpnD,KAAKulE,kBAAkBU,4BAA6Bh3C,GAAU,CACnF,MAAM+2B,EAAcoB,EAAOnB,WAE3BjmD,KAAKkmE,mBAAoB9e,EAAOtpD,KAAMkoD,EAAaA,EAAaoB,EAAOoa,aAIxExhE,KAAK4lE,eAAiB,KAWvB,gBAAiBlmB,GAKhB,OAASA,EAAUz/C,MAClB,IAAK,SACJ,GAAKD,KAAK8lE,qBAAsBpmB,EAAU70B,SAAS9N,QAClD,OAGD/c,KAAKgmE,YAAatmB,EAAU70B,SAAS9N,OAAQ2iC,EAAU70B,SAASve,OAAQozC,EAAU34B,MAAMm3B,WAExF,MAED,IAAK,eACL,IAAK,kBACL,IAAK,kBACJ,IAAM,MAAM77C,KAAQq9C,EAAUzwB,MAAMq4B,SAAU,CAAEt8B,SAAS,IACnDhrB,KAAK8lE,qBAAsBzjE,EAAK0a,SAIrC/c,KAAKmmE,eAAgB9jE,GAGtB,MAED,IAAK,SACL,IAAK,OACL,IAAK,WAAY,CAGhB,GACCq9C,EAAUO,eAAe3zB,QAASozB,EAAUpnB,iBAC5ConB,EAAUO,eAAe3xB,aAAcoxB,EAAUz4B,SAAUqF,QAASozB,EAAUpnB,gBAE9E,OAGD,MAAM8tC,EAAuBpmE,KAAK8lE,qBAAsBpmB,EAAUO,eAAeljC,QAC3EspD,EAAuBrmE,KAAK8lE,qBAAsBpmB,EAAUpnB,eAAevb,QAE3EqpD,GACLpmE,KAAK+lE,YAAarmB,EAAUO,eAAeljC,OAAQ2iC,EAAUO,eAAe3zC,OAAQozC,EAAUz4B,SAGzFo/C,GACLrmE,KAAKgmE,YAAatmB,EAAUpnB,eAAevb,OAAQ2iC,EAAUshB,qBAAqB10D,OAAQozC,EAAUz4B,SAGrG,MAED,IAAK,SAAU,CACd,GAAKjnB,KAAK8lE,qBAAsBpmB,EAAU70B,SAAS9N,QAClD,OAGD/c,KAAK+lE,YAAarmB,EAAU70B,SAAS9N,OAAQ2iC,EAAU70B,SAASve,OAAQ,GACxEtM,KAAKgmE,YAAatmB,EAAU70B,SAAS9N,OAAQ2iC,EAAU70B,SAASve,OAAQ,GAExE,MAAM2iB,EAAQ,GAAMR,4BAA6BixB,EAAU70B,SAAU,GAErE,IAAM,MAAMu8B,KAAUpnD,KAAKulE,kBAAkBU,4BAA6Bh3C,GAAU,CACnF,MAAM+2B,EAAcoB,EAAOnB,WAE3BjmD,KAAKkmE,mBAAoB9e,EAAOtpD,KAAMkoD,EAAaA,EAAaoB,EAAOoa,aAGxE,MAED,IAAK,QAAS,CACb,MAAMK,EAAeniB,EAAUU,cAAcrjC,OAGvC/c,KAAK8lE,qBAAsBjE,IAChC7hE,KAAK+lE,YAAalE,EAAcniB,EAAUU,cAAc9zC,OAAQozC,EAAUz4B,SAIrEjnB,KAAK8lE,qBAAsBpmB,EAAUnmB,kBAAkBxc,SAC5D/c,KAAKgmE,YAAatmB,EAAUnmB,kBAAkBxc,OAAQ2iC,EAAUnmB,kBAAkBjtB,OAAQ,GAItFozC,EAAUY,mBACdtgD,KAAK+lE,YAAarmB,EAAUY,kBAAkBvjC,OAAQ2iC,EAAUY,kBAAkBh0C,OAAQ,GAG3F,MAED,IAAK,QAAS,CAEb,MAAMq1D,EAAgBjiB,EAAUO,eAAeljC,OAEzC/c,KAAK8lE,qBAAsBnE,EAAc5kD,SAC9C/c,KAAK+lE,YAAapE,EAAc5kD,OAAQ4kD,EAAcv1C,YAAa,GAIpE,MAAMk6C,EAAkB5mB,EAAUY,kBAAkBvjC,OAEpD/c,KAAKgmE,YAAaM,EAAiB5mB,EAAUY,kBAAkBh0C,OAAQ,GAGvE,MAAMi6D,EAAoB7mB,EAAUpnB,eAAevb,OAE7C/c,KAAK8lE,qBAAsBS,IAChCvmE,KAAKgmE,YAAaO,EAAmB7mB,EAAUpnB,eAAehsB,OAAQq1D,EAAczjB,WAGrF,OAKFl+C,KAAK4lE,eAAiB,KAYvB,mBAAoB1iB,EAAY8E,EAAUrtB,EAAU6mC,GACnD,MAAMgF,EAAWxmE,KAAK0lE,gBAAgBtnE,IAAK8kD,GAErCsjB,GAOLA,EAAS7rC,SAAWA,EACpB6rC,EAAShF,YAAcA,EAEG,MAArBgF,EAASxe,UAAyC,MAArBwe,EAAS7rC,UAG1C36B,KAAK0lE,gBAAgB3xD,OAAQmvC,IAZ9BljD,KAAK0lE,gBAAgBj8D,IAAKy5C,EAAY,CACrC8E,WACArtB,WACA6mC,gBAmBH,qBACC,MAAM1/D,EAAS,GAEf,IAAM,MAAQhE,EAAMs/C,KAAYp9C,KAAK0lE,gBACZ,MAAnBtoB,EAAO4K,UACXlmD,EAAOmB,KAAM,CAAEnF,OAAMmxB,MAAOmuB,EAAO4K,WAIrC,OAAOlmD,EAQR,kBACC,MAAMA,EAAS,GAEf,IAAM,MAAQhE,EAAMs/C,KAAYp9C,KAAK0lE,gBACZ,MAAnBtoB,EAAOziB,UACX74B,EAAOmB,KAAM,CAAEnF,OAAMmxB,MAAOmuB,EAAOziB,WAIrC,OAAO74B,EAQR,oBACC,OAAOqH,MAAMiK,KAAMpT,KAAK0lE,iBAAkBr7D,IAAKhI,IAAQ,CAErDvE,KAAMuE,EAAM,GACZ1C,KAAM,CACLqoD,SAAU3lD,EAAM,GAAI2lD,SACpBrtB,SAAUt4B,EAAM,GAAIs4B,aAiBxB,iBACC,IAAM,MAAQ,CAAEyiB,KAAYp9C,KAAK0lE,gBAChC,GAAKtoB,EAAOokB,YACX,OAAO,EAKT,OAAOxhE,KAAKwlE,kBAAkBx8D,KAAO,EAmBtC,WAAY9G,EAAU,CAAEukE,2BAA2B,IAElD,GAAKzmE,KAAK4lE,eACT,OAAK1jE,EAAQukE,0BACLzmE,KAAK6lE,4BAA4Bp+D,QAEjCzH,KAAK4lE,eAAen+D,QAK7B,MAAMi/D,EAAU,GAGhB,IAAM,MAAM9nD,KAAW5e,KAAKwlE,kBAAkBhiE,OAAS,CAEtD,MAAM8hD,EAAUtlD,KAAKwlE,kBAAkBpnE,IAAKwgB,GAAUsF,KAAM,CAAEvH,EAAGC,IAC3DD,EAAErQ,SAAWsQ,EAAEtQ,OACdqQ,EAAE1c,MAAQ2c,EAAE3c,KAIC,UAAV0c,EAAE1c,MAAoB,EAAI,EAG3B,EAGD0c,EAAErQ,OAASsQ,EAAEtQ,QAAU,EAAI,GAI7Bq6D,EAAmB3mE,KAAKylE,kBAAkBrnE,IAAKwgB,GAE/CgoD,EAAkBC,GAAsBjoD,EAAQ8H,eAGhDkc,EAAUkkC,GAA6BH,EAAiB5kE,OAAQujD,GAEtE,IAAI/nD,EAAI,EACJ6jD,EAAI,EAGR,IAAM,MAAMpe,KAAUJ,EACrB,GAAgB,MAAXI,EAEJ0jC,EAAQzjE,KAAMjD,KAAK+mE,eAAgBnoD,EAASrhB,EAAGqpE,EAAiBrpE,GAAIO,OAEpEP,SACM,GAAgB,MAAXylC,EAEX0jC,EAAQzjE,KAAMjD,KAAKgnE,eAAgBpoD,EAASrhB,EAAGopE,EAAkBvlB,GAAItjD,OAErEsjD,SACM,GAAgB,MAAXpe,EAAiB,CAE5B,MAAMikC,EAAoBL,EAAiBrpE,GAAI+F,WACzC4jE,EAAqBP,EAAkBvlB,GAAI99C,WACjD,IAAI2rB,EAEJ,GAAkC,SAA7B23C,EAAiBrpE,GAAIO,KACzBmxB,EAAQ,IAAI,GAAO,GAASnE,UAAWlM,EAASrhB,GAAK,GAASutB,UAAWlM,EAASrhB,EAAI,QAChF,CACN,MAAMmF,EAAQkc,EAAQ4/B,cAAejhD,GACrC0xB,EAAQ,IAAI,GAAO,GAASnE,UAAWlM,EAASrhB,GAAK,GAASutB,UAAWlM,EAAQ1B,SAAUxa,GAAS,IAKrGgkE,EAAQzjE,QAASjD,KAAKmnE,mBAAoBl4C,EAAOi4C,EAAoBD,IAErE1pE,IACA6jD,SAGA7jD,IACA6jD,IAMHslB,EAAQxiD,KAAM,CAAEvH,EAAGC,IAIbD,EAAEkO,SAAShuB,MAAQ+f,EAAEiO,SAAShuB,KAC3B8f,EAAEkO,SAAShuB,KAAK0tB,SAAW3N,EAAEiO,SAAShuB,KAAK0tB,UAAY,EAAI,EAI9D5N,EAAEkO,SAASyB,QAAS1P,EAAEiO,UAEnBlO,EAAEyqD,YAAcxqD,EAAEwqD,YAInBzqD,EAAEkO,SAAShN,SAAUjB,EAAEiO,WAAc,EAAI,GAIjD,IAAM,IAAIttB,EAAI,EAAGA,EAAImpE,EAAQ3kE,OAAQxE,IAAM,CAC1C,MAAM8pE,EAAWX,EAASnpE,EAAI,GACxB+pE,EAAWZ,EAASnpE,GAGpBgqE,EACY,UAAjBF,EAASpnE,MAAqC,UAAjBqnE,EAASrnE,MACrB,SAAjBonE,EAASvpE,MAAoC,SAAjBwpE,EAASxpE,MACrCupE,EAASx8C,SAASyB,QAASg7C,EAASz8C,UAG/B28C,EACY,UAAjBH,EAASpnE,MAAqC,UAAjBqnE,EAASrnE,MACrB,SAAjBonE,EAASvpE,MAAoC,SAAjBwpE,EAASxpE,MACrCupE,EAASx8C,SAAS9N,QAAUuqD,EAASz8C,SAAS9N,QAC9CsqD,EAASx8C,SAASve,OAAS+6D,EAAStlE,QAAUulE,EAASz8C,SAASve,OAG3Dm7D,EACY,aAAjBJ,EAASpnE,MAAwC,aAAjBqnE,EAASrnE,MACzConE,EAASx8C,SAAS9N,QAAUuqD,EAASz8C,SAAS9N,QAC9CsqD,EAASp4C,MAAM1gB,QAAU+4D,EAASr4C,MAAM1gB,QACxC84D,EAASx8C,SAASve,OAAS+6D,EAAStlE,QAAUulE,EAASz8C,SAASve,QAChE+6D,EAASzhB,cAAgB0hB,EAAS1hB,cAClCyhB,EAASxhB,mBAAqByhB,EAASzhB,mBACvCwhB,EAASvhB,mBAAqBwhB,EAASxhB,mBAEnCyhB,GAA2BC,GAAwBC,KACvDf,EAASnpE,EAAI,GAAIwE,SAEZ0lE,IACJf,EAASnpE,EAAI,GAAI0xB,MAAMnO,IAAM4lD,EAASnpE,EAAI,GAAI0xB,MAAMnO,IAAIwN,aAAc,IAGvEo4C,EAAQ5gE,OAAQvI,EAAG,GACnBA,KAKF,IAAM,MAAM8E,KAAQqkE,SACZrkE,EAAK+kE,YAEM,aAAb/kE,EAAKpC,cACFoC,EAAKwoB,gBACLxoB,EAAKN,QAUd,OANA/B,KAAK2lE,aAAe,EAGpB3lE,KAAK6lE,4BAA8Ba,EAAQj/D,QAC3CzH,KAAK4lE,eAAiBc,EAAQj/D,QAAQzD,OAAQ0jE,IAEzCxlE,EAAQukE,0BACLzmE,KAAK6lE,4BAEL7lE,KAAK4lE,eAOd,QACC5lE,KAAKwlE,kBAAkBj8D,QACvBvJ,KAAKylE,kBAAkBl8D,QACvBvJ,KAAK0lE,gBAAgBn8D,QACrBvJ,KAAK4lE,eAAiB,KAWvB,YAAa7oD,EAAQzQ,EAAQ2a,GAC5B,MAAM0gD,EAAa,CAAE1nE,KAAM,SAAUqM,SAAQ2a,UAASzkB,MAAOxC,KAAK2lE,gBAElE3lE,KAAK4nE,YAAa7qD,EAAQ4qD,GAW3B,YAAa5qD,EAAQzQ,EAAQ2a,GAC5B,MAAM0gD,EAAa,CAAE1nE,KAAM,SAAUqM,SAAQ2a,UAASzkB,MAAOxC,KAAK2lE,gBAElE3lE,KAAK4nE,YAAa7qD,EAAQ4qD,GAE1B3nE,KAAK6nE,wBAAyB9qD,EAAQzQ,EAAQ2a,GAS/C,eAAgB5kB,GACf,MAAMslE,EAAa,CAAE1nE,KAAM,YAAaqM,OAAQjK,EAAK+pB,YAAanF,QAAS5kB,EAAKmsB,WAAYhsB,MAAOxC,KAAK2lE,gBAExG3lE,KAAK4nE,YAAavlE,EAAK0a,OAAQ4qD,GAUhC,YAAa5qD,EAAQ4qD,GAEpB3nE,KAAK8nE,cAAe/qD,GAGpB,MAAMuoC,EAAUtlD,KAAK+nE,sBAAuBhrD,GAG5C/c,KAAKgoE,cAAeL,EAAYriB,GAGhCA,EAAQriD,KAAM0kE,GAId,IAAM,IAAIpqE,EAAI,EAAGA,EAAI+nD,EAAQvjD,OAAQxE,IAC/B+nD,EAAS/nD,GAAI0pB,QAAU,IAC3Bq+B,EAAQx/C,OAAQvI,EAAG,GAEnBA,KAYH,sBAAuBqhB,GACtB,IAAI0mC,EAUJ,OARKtlD,KAAKwlE,kBAAkB97D,IAAKkV,GAChC0mC,EAAUtlD,KAAKwlE,kBAAkBpnE,IAAKwgB,IAEtC0mC,EAAU,GAEVtlD,KAAKwlE,kBAAkB/7D,IAAKmV,EAAS0mC,IAG/BA,EASR,cAAe1mC,GACR5e,KAAKylE,kBAAkB/7D,IAAKkV,IACjC5e,KAAKylE,kBAAkBh8D,IAAKmV,EAASioD,GAAsBjoD,EAAQ8H,gBAYrE,cAAeuhD,EAAK3iB,GAiBnB2iB,EAAIC,cAAgBD,EAAIhhD,QAExB,IAAM,MAAMkhD,KAAO7iB,EAAU,CAC5B,MAAM8iB,EAASH,EAAI37D,OAAS27D,EAAIhhD,QAC1BohD,EAASF,EAAI77D,OAAS67D,EAAIlhD,QAEhC,GAAiB,UAAZghD,EAAIhoE,OACS,UAAZkoE,EAAIloE,OACHgoE,EAAI37D,QAAU67D,EAAI77D,OACtB67D,EAAI77D,QAAU27D,EAAIhhD,QACPghD,EAAI37D,OAAS+7D,IACxBF,EAAIlhD,SAAWghD,EAAIC,cACnBD,EAAIC,cAAgB,IAIL,UAAZC,EAAIloE,MACHgoE,EAAI37D,OAAS67D,EAAI77D,SACrB67D,EAAI77D,QAAU27D,EAAIhhD,SAIH,aAAZkhD,EAAIloE,MACR,GAAKgoE,EAAI37D,QAAU67D,EAAI77D,OACtB67D,EAAI77D,QAAU27D,EAAIhhD,aACZ,GAAKghD,EAAI37D,OAAS+7D,EAAS,CAWjC,MAAMphD,EAAUkhD,EAAIlhD,QAEpBkhD,EAAIlhD,QAAUghD,EAAI37D,OAAS67D,EAAI77D,OAI/Bg5C,EAAQnoC,QAAS,CAChBld,KAAM,YACNqM,OAAQ87D,EACRnhD,QAASA,EAAUkhD,EAAIlhD,QACvBzkB,MAAOxC,KAAK2lE,iBAMhB,GAAiB,UAAZsC,EAAIhoE,KAAmB,CAC3B,GAAiB,UAAZkoE,EAAIloE,KACR,GAAKmoE,GAAUD,EAAI77D,OAClB67D,EAAI77D,QAAU27D,EAAIhhD,aACZ,GAAKmhD,GAAUC,EACrB,GAAKJ,EAAI37D,OAAS67D,EAAI77D,OAAS,CAC9B,MAAMg8D,EAAqBF,EAASD,EAAI77D,OAExC67D,EAAI77D,OAAS27D,EAAI37D,OAEjB67D,EAAIlhD,SAAWqhD,EACfL,EAAIC,eAAiBI,OAErBH,EAAIlhD,SAAWghD,EAAIC,cACnBD,EAAIC,cAAgB,OAGrB,GAAKD,EAAI37D,QAAU67D,EAAI77D,OACtB27D,EAAIC,eAAiBC,EAAIlhD,QACzBkhD,EAAIlhD,QAAU,OACR,GAAKghD,EAAI37D,OAAS+7D,EAAS,CACjC,MAAMC,EAAqBD,EAASJ,EAAI37D,OAExC67D,EAAIlhD,SAAWqhD,EACfL,EAAIC,eAAiBI,EAcxB,GATiB,UAAZH,EAAIloE,OACHmoE,GAAUD,EAAI77D,OAClB67D,EAAI77D,QAAU27D,EAAIhhD,QACPghD,EAAI37D,OAAS67D,EAAI77D,SAC5B27D,EAAIC,eAAiBC,EAAIlhD,QACzBkhD,EAAIlhD,QAAU,IAIC,aAAZkhD,EAAIloE,KACR,GAAKmoE,GAAUD,EAAI77D,OAClB67D,EAAI77D,QAAU27D,EAAIhhD,aACZ,GAAKghD,EAAI37D,OAAS67D,EAAI77D,OAAS,CACrC,MAAMg8D,EAAqBF,EAASD,EAAI77D,OAExC67D,EAAI77D,OAAS27D,EAAI37D,OACjB67D,EAAIlhD,SAAWqhD,OACT,GAAKL,EAAI37D,OAAS+7D,EACxB,GAAKD,GAAUC,EAAS,CAMvB,MAAMphD,EAAUkhD,EAAIlhD,QAEpBkhD,EAAIlhD,QAAUghD,EAAI37D,OAAS67D,EAAI77D,OAE/B,MAAMi8D,EAAethD,EAAUkhD,EAAIlhD,QAAUghD,EAAIC,cAIjD5iB,EAAQnoC,QAAS,CAChBld,KAAM,YACNqM,OAAQ27D,EAAI37D,OACZ2a,QAASshD,EACT/lE,MAAOxC,KAAK2lE,sBAGbwC,EAAIlhD,SAAWohD,EAASJ,EAAI37D,OAMhC,GAAiB,aAAZ27D,EAAIhoE,KAAsB,CAE9B,GAAiB,UAAZkoE,EAAIloE,KACR,GAAKgoE,EAAI37D,OAAS67D,EAAI77D,QAAU87D,EAASD,EAAI77D,OAAS,CACrD,GAAK87D,EAASC,EAAS,CAOtB,MAAMG,EAAgB,CACrBvoE,KAAM,YACNqM,OAAQ+7D,EACRphD,QAASmhD,EAASC,EAClB7lE,MAAOxC,KAAK2lE,gBAGb3lE,KAAKgoE,cAAeQ,EAAeljB,GAEnCA,EAAQriD,KAAMulE,GAGfP,EAAIC,cAAgBC,EAAI77D,OAAS27D,EAAI37D,OACrC27D,EAAIhhD,QAAUghD,EAAIC,mBACPD,EAAI37D,QAAU67D,EAAI77D,QAAU27D,EAAI37D,OAAS+7D,IAC/CD,EAASC,GACbJ,EAAIC,cAAgBE,EAASC,EAC7BJ,EAAI37D,OAAS+7D,GAEbJ,EAAIC,cAAgB,GAKvB,GAAiB,UAAZC,EAAIloE,MAGHgoE,EAAI37D,OAAS67D,EAAI77D,QAAU87D,EAASD,EAAI77D,OAAS,CACrD,MAAMk8D,EAAgB,CACrBvoE,KAAM,YACNqM,OAAQ67D,EAAI77D,OACZ2a,QAASmhD,EAASD,EAAI77D,OACtB9J,MAAOxC,KAAK2lE,gBAGb3lE,KAAKgoE,cAAeQ,EAAeljB,GAEnCA,EAAQriD,KAAMulE,GAEdP,EAAIC,cAAgBC,EAAI77D,OAAS27D,EAAI37D,OACrC27D,EAAIhhD,QAAUghD,EAAIC,cAIH,aAAZC,EAAIloE,OAEHgoE,EAAI37D,QAAU67D,EAAI77D,QAAU87D,GAAUC,GAE1CJ,EAAIC,cAAgB,EACpBD,EAAIhhD,QAAU,EACdghD,EAAI37D,OAAS,GACF27D,EAAI37D,QAAU67D,EAAI77D,QAAU87D,GAAUC,IAEjDF,EAAIlhD,QAAU,KAMlBghD,EAAIhhD,QAAUghD,EAAIC,qBACXD,EAAIC,cAYZ,eAAgBnrD,EAAQzQ,EAAQxO,GAC/B,MAAO,CACNmC,KAAM,SACN4qB,SAAU,GAASC,UAAW/N,EAAQzQ,GACtCxO,OACAiE,OAAQ,EACRqlE,YAAapnE,KAAK2lE,gBAapB,eAAgB5oD,EAAQzQ,EAAQxO,GAC/B,MAAO,CACNmC,KAAM,SACN4qB,SAAU,GAASC,UAAW/N,EAAQzQ,GACtCxO,OACAiE,OAAQ,EACRqlE,YAAapnE,KAAK2lE,gBAapB,mBAAoB12C,EAAOs9B,EAAeF,GAEzC,MAAMoc,EAAQ,GAGdpc,EAAgB,IAAIv4C,IAAKu4C,GAGzB,IAAM,MAAQvtD,EAAK+oB,KAAc0kC,EAAgB,CAEhD,MAAMvhD,EAAWqhD,EAAc3iD,IAAK5K,GAAQutD,EAAcjuD,IAAKU,GAAQ,KAGlEkM,IAAa6c,GAEjB4gD,EAAMxlE,KAAM,CACXhD,KAAM,YACN4qB,SAAUoE,EAAMpO,MAChBoO,MAAOA,EAAMvD,QACb3pB,OAAQ,EACR6jD,aAAc9mD,EACd+mD,kBAAmBh+B,EACnBi+B,kBAAmB96C,EACnBo8D,YAAapnE,KAAK2lE,iBAKpBtZ,EAAct4C,OAAQjV,GAIvB,IAAM,MAAQA,EAAKkM,KAAcqhD,EAEhCoc,EAAMxlE,KAAM,CACXhD,KAAM,YACN4qB,SAAUoE,EAAMpO,MAChBoO,MAAOA,EAAMvD,QACb3pB,OAAQ,EACR6jD,aAAc9mD,EACd+mD,kBAAmB,KACnBC,kBAAmB96C,EACnBo8D,YAAapnE,KAAK2lE,iBAIpB,OAAO8C,EAUR,qBAAsB7pD,GACrB,MAAM7B,EAAS6B,EAAQ7B,OAEvB,IAAMA,EACL,OAAO,EAGR,MAAMuoC,EAAUtlD,KAAKwlE,kBAAkBpnE,IAAK2e,GACtCzQ,EAASsS,EAAQwN,YAEvB,GAAKk5B,EACJ,IAAM,MAAMlI,KAAUkI,EACrB,GAAoB,UAAflI,EAAOn9C,MAAoBqM,GAAU8wC,EAAO9wC,QAAUA,EAAS8wC,EAAO9wC,OAAS8wC,EAAOn2B,QAC1F,OAAO,EAKV,OAAOjnB,KAAK8lE,qBAAsB/oD,GAYnC,wBAAyBA,EAAQzQ,EAAQ2a,GACxC,MAAMgI,EAAQ,IAAI,GAAO,GAASnE,UAAW/N,EAAQzQ,GAAU,GAASwe,UAAW/N,EAAQzQ,EAAS2a,IAEpG,IAAM,MAAM5kB,KAAQ4sB,EAAMq4B,SAAU,CAAEt8B,SAAS,IACzC3oB,EAAKlC,GAAI,aACbH,KAAKylE,kBAAkB1xD,OAAQ1R,GAC/BrC,KAAKwlE,kBAAkBzxD,OAAQ1R,GAE/BrC,KAAK6nE,wBAAyBxlE,EAAM,EAAGA,EAAK67C,aAQhD,SAAS2oB,GAAsB/+D,GAC9B,MAAM4gE,EAAW,GAEjB,IAAM,MAAMjiD,KAAS3e,EACpB,GAAK2e,EAAMtmB,GAAI,SACd,IAAM,IAAI5C,EAAI,EAAGA,EAAIkpB,EAAM9mB,KAAKoC,OAAQxE,IACvCmrE,EAASzlE,KAAM,CACdnF,KAAM,QACNwF,WAAY,IAAIwQ,IAAK2S,EAAMsU,wBAI7B2tC,EAASzlE,KAAM,CACdnF,KAAM2oB,EAAM3oB,KACZwF,WAAY,IAAIwQ,IAAK2S,EAAMsU,mBAK9B,OAAO2tC,EAgDR,SAAS5B,GAA6B6B,EAAmBrjB,GACxD,MAAM1iB,EAAU,GAEhB,IAAIt2B,EAAS,EACTs8D,EAAqB,EAGzB,IAAM,MAAMxrB,KAAUkI,EAAU,CAE/B,GAAKlI,EAAO9wC,OAASA,EAAS,CAC7B,IAAM,IAAI/O,EAAI,EAAGA,EAAI6/C,EAAO9wC,OAASA,EAAQ/O,IAC5CqlC,EAAQ3/B,KAAM,KAGf2lE,GAAsBxrB,EAAO9wC,OAASA,EAIvC,GAAoB,UAAf8wC,EAAOn9C,KAAmB,CAC9B,IAAM,IAAI1C,EAAI,EAAGA,EAAI6/C,EAAOn2B,QAAS1pB,IACpCqlC,EAAQ3/B,KAAM,KAIfqJ,EAAS8wC,EAAO9wC,OAAS8wC,EAAOn2B,aAC1B,GAAoB,UAAfm2B,EAAOn9C,KAAmB,CACrC,IAAM,IAAI1C,EAAI,EAAGA,EAAI6/C,EAAOn2B,QAAS1pB,IACpCqlC,EAAQ3/B,KAAM,KAIfqJ,EAAS8wC,EAAO9wC,OAEhBs8D,GAAsBxrB,EAAOn2B,aAE7B2b,EAAQ3/B,QAAS,IAAI4lE,OAAQzrB,EAAOn2B,SAAU1X,MAAO,KAGrDjD,EAAS8wC,EAAO9wC,OAAS8wC,EAAOn2B,QAEhC2hD,GAAsBxrB,EAAOn2B,QAM/B,GAAK2hD,EAAqBD,EACzB,IAAM,IAAIprE,EAAI,EAAGA,EAAIorE,EAAoBC,EAAqBt8D,EAAQ/O,IACrEqlC,EAAQ3/B,KAAM,KAIhB,OAAO2/B,EAIR,SAAS8kC,GAA2Bl+D,GACnC,MAAMs/D,EAAUt/D,EAAMqhB,UAA4C,cAAhCrhB,EAAMqhB,SAAShuB,KAAK0tB,SAChDw+C,EAAYv/D,EAAMylB,OAAsC,cAA7BzlB,EAAMylB,MAAMpyB,KAAK0tB,SAElD,OAAQu+C,IAAYC,EChoCN,MAAMC,GAIpB,cAOChpE,KAAKipE,YAAc,GAYnBjpE,KAAKkpE,WAAa,IAAIp1D,IAQtB9T,KAAKmpE,kBAAoB,IAAI9wD,IAQ9B,aAAcqnC,GACR1/C,KAAKipE,YAAY7vD,SAAUsmC,IAIhC1/C,KAAKipE,YAAYhmE,KAAMy8C,GAYxB,cAAetsC,EAAO8H,OAAOg/B,kBAAmBtmC,EAAKsH,OAAOkhB,mBAC3D,MAAM8kB,EAAa,GAEnB,IAAM,MAAMxB,KAAa1/C,KAAKipE,YACxBvpB,EAAUugB,aAAe7sD,GAAQssC,EAAUugB,YAAcrsD,GAC7DstC,EAAWj+C,KAAMy8C,GAInB,OAAOwB,EAUR,aAAc+e,GACb,IAAM,MAAMvgB,KAAa1/C,KAAKipE,YAC7B,GAAKvpB,EAAUugB,aAAeA,EAC7B,OAAOvgB,EAYV,qBAAsB0pB,EAAiBC,GACtCrpE,KAAKkpE,WAAWz/D,IAAK4/D,EAAkBD,GACvCppE,KAAKmpE,kBAAkBv6D,IAAKw6D,GAS7B,mBAAoB1pB,GACnB,OAAO1/C,KAAKkpE,WAAWx/D,IAAKg2C,GAS7B,kBAAmBA,GAClB,OAAO1/C,KAAKmpE,kBAAkBz/D,IAAKg2C,GAUpC,mBAAoB2pB,GACnB,OAAOrpE,KAAKkpE,WAAW9qE,IAAKirE,IChFvB,SAASC,GAAuB1uD,EAAQtO,GAC9C,SAzBoCi9D,EAyBR3uD,EAAOuI,OAAQ7W,EAAS,KAxBV,GAApBi9D,EAAUxnE,QAAe,kBAAkBoI,KAAMo/D,IAYjE,SAA6BA,GACnC,QAASA,GAAiC,GAApBA,EAAUxnE,QAAe,kBAAkBoI,KAAMo/D,GAWVC,CAAoB5uD,EAAOuI,OAAQ7W,IAzB1F,IAA8Bi9D,EAmC9B,SAASE,GAAwB7uD,EAAQtO,GAC/C,SAlDgCi9D,EAkDR3uD,EAAOuI,OAAQ7W,KAhDG,GAApBi9D,EAAUxnE,QAAe,sEAAsEoI,KAAMo/D,GAFrH,IAA0BA,ECuBlB,MAAM,GAKpB,YAAavgB,GAOZhpD,KAAKgpD,MAAQA,EAWbhpD,KAAKm+D,QAAU,EAQfn+D,KAAK0pE,QAAU,IAAIV,GAAShpE,MAQ5BA,KAAKoqB,UAAY,IAAI,GAAmBpqB,MASxCA,KAAK6xB,MAAQ,IAAI,GAAY,CAAEzc,WAAY,aAQ3CpV,KAAKklD,OAAS,IAAI,GAAQ8D,EAAM7D,SAQhCnlD,KAAK8xB,YAAc,IAAIzZ,IAQvBrY,KAAK2pE,4CAA6C,EAGlD3pE,KAAK4pE,WAAY,QA7FG,cAgGpB5pE,KAAKmR,SAAU63C,EAAO,iBAAkB,CAAElyC,EAAKzF,KAC9C,MAAMquC,EAAYruC,EAAM,GAExB,GAAKquC,EAAU8J,qBAAuB9J,EAAUugB,cAAgBjgE,KAAKm+D,QAOpE,MAAM,IAAI,KAAe,8CAA+Cn+D,KAAM,CAAE0/C,eAE/E,CAAEjvC,SAAU,YAGfzQ,KAAKmR,SAAU63C,EAAO,iBAAkB,CAAElyC,EAAKzF,KAC9C,MAAMquC,EAAYruC,EAAM,GAEnBquC,EAAU8J,qBACdxpD,KAAKklD,OAAO2kB,gBAAiBnqB,IAE5B,CAAEjvC,SAAU,SAGfzQ,KAAKmR,SAAU63C,EAAO,iBAAkB,CAAElyC,EAAKzF,KAC9C,MAAMquC,EAAYruC,EAAM,GAEnBquC,EAAU8J,sBACdxpD,KAAKm+D,UACLn+D,KAAK0pE,QAAQ1H,aAActiB,KAE1B,CAAEjvC,SAAU,QAGfzQ,KAAKmR,SAAUnR,KAAKoqB,UAAW,SAAU,KACxCpqB,KAAK2pE,4CAA6C,IAMnD3pE,KAAKmR,SAAU63C,EAAM7D,QAAS,SAAU,CAAEruC,EAAKswC,EAAQY,EAAUrtB,KAEhE36B,KAAKklD,OAAOghB,mBAAoB9e,EAAOtpD,KAAMkqD,EAAUrtB,EAAUysB,EAAOoa,aAEtD,OAAbxZ,GAEJZ,EAAOl+B,GAAI,SAAU,CAAEpS,EAAKkxC,KAC3BhoD,KAAKklD,OAAOghB,mBAAoB9e,EAAOtpD,KAAMkqD,EAAUZ,EAAOnB,WAAYmB,EAAOoa,iBAYrF,gBACC,OAAOxhE,KAAK+8C,QA7JQ,cAwKrB,WAAY8K,EAAc,QAASt9B,EAAW,QAC7C,GAAKvqB,KAAK6xB,MAAMzzB,IAAKmsB,GAQpB,MAAM,IAAI,KAAe,wCAAyCvqB,KAAM,CAAElC,KAAMysB,IAGjF,MAAM1tB,EAAO,IAAI,GAAamD,KAAM6nD,EAAat9B,GAGjD,OAFAvqB,KAAK6xB,MAAMjjB,IAAK/R,GAETA,EAMR,UACCmD,KAAKoqB,UAAUlQ,UACfla,KAAKsR,gBAUN,QAASxT,EAAO,QACf,OAAOkC,KAAK6xB,MAAMzzB,IAAKN,GAQxB,eACC,OAAOqL,MAAMiK,KAAMpT,KAAK6xB,MAAOh1B,GAAQA,EAAK0tB,UAAWvmB,OAAQlG,GAnN3C,cAmNmDA,GAsCxE,kBAAmBi0B,GAClB/xB,KAAK8xB,YAAYljB,IAAKmjB,GAQvB,SACC,MAAM/T,EAAO,GAAOhe,MAMpB,OAHAge,EAAKoM,UAAY,mCACjBpM,EAAKgrC,MAAQ,uBAENhrC,EAaR,mBAAoBgU,GACdhyB,KAAK8pE,8CACT9pE,KAAKy9C,gBAAiBzrB,GAGtBhyB,KAAKoqB,UAAU2/C,UAEV/pE,KAAKklD,OAAO8kB,iBAChBhqE,KAAKqU,KAAM,cAAe2d,EAAOm5B,OAEjCnrD,KAAKqU,KAAM,SAAU2d,EAAOm5B,OAK7BnrD,KAAKoqB,UAAU2/C,UAEf/pE,KAAKklD,OAAO+kB,SAGbjqE,KAAK2pE,4CAA6C,EAWnD,4CACC,OAAQ3pE,KAAKklD,OAAOziC,SAAWziB,KAAK2pE,2CAUrC,kBACC,IAAM,MAAM9sE,KAAQmD,KAAK6xB,MACxB,GAAKh1B,IAASmD,KAAK6gD,UAClB,OAAOhkD,EAIT,OAAOmD,KAAK6gD,UAUb,mBACC,MAAMqpB,EAAclqE,KAAKmqE,kBACnBnhB,EAAQhpD,KAAKgpD,MACbC,EAASD,EAAMC,OAGfp+B,EAAWm+B,EAAM+Z,uBAAwBmH,EAAa,CAAE,IAI9D,OAHqBjhB,EAAO8D,yBAA0BliC,IAG/Bm+B,EAAM1iB,YAAazb,GAW3C,wBAAyBoE,GACxB,OAAOm7C,GAA0Bn7C,EAAMpO,QAAWupD,GAA0Bn7C,EAAMnO,KASnF,gBAAiBkR,GAChB,IAAIC,GAAW,EAEf,GACC,IAAM,MAAM/gB,KAAYlR,KAAK8xB,YAW5B,GAJA9xB,KAAKoqB,UAAU2/C,UAEf93C,EAAW/gB,EAAU8gB,GAEhBC,EACJ,YAGOA,IA8DZ,SAASm4C,GAA0BC,GAClC,MAAMlsD,EAAWksD,EAAclsD,SAE/B,GAAKA,EAAW,CACf,MAAMxe,EAAOwe,EAASxe,KAChB2M,EAAS+9D,EAAc/9D,OAAS6R,EAASiO,YAE/C,OAAQk9C,GAAuB3pE,EAAM2M,KAAam9D,GAAwB9pE,EAAM2M,GAGjF,OAAO,EAdRkI,GAAK,GAAU,ICvbA,MAAM,GAIpB,cAOCxU,KAAKyhE,SAAW,IAAI3tD,IAUrB,CAAExV,OAAOiW,YACR,OAAOvU,KAAKyhE,SAASp1D,SAStB,IAAK62C,GACJ,OAAOljD,KAAKyhE,SAAS/3D,IAAKw5C,GAU3B,IAAKA,GACJ,OAAOljD,KAAKyhE,SAASrjE,IAAK8kD,IAAgB,KAqB3C,KAAMsgB,EAAcv0C,EAAO80C,GAAyB,EAAOvC,GAAc,GACxE,MAAMte,EAAasgB,aAAwB,GAASA,EAAa1lE,KAAO0lE,EAExE,GAAKtgB,EAAW9pC,SAAU,KAMzB,MAAM,IAAI,KAAe,yCAA0CpZ,MAGpE,MAAMsqE,EAAYtqE,KAAKyhE,SAASrjE,IAAK8kD,GAErC,GAAKonB,EAAY,CAChB,MAAMtiB,EAAWsiB,EAAUrkB,WAC3B,IAAIskB,GAAa,EAqBjB,OAnBMviB,EAAS17B,QAAS2C,KACvBq7C,EAAUE,iBAAkB,GAAU3e,UAAW58B,IACjDs7C,GAAa,GAGTxG,GAA0BuG,EAAUvG,yBACxCuG,EAAUG,wBAA0B1G,EACpCwG,GAAa,GAGc,kBAAhB/I,GAA6BA,GAAe8I,EAAU9I,cACjE8I,EAAUI,aAAelJ,EACzB+I,GAAa,GAGTA,GACJvqE,KAAKqU,KAAM,UAAY6uC,EAAYonB,EAAWtiB,EAAU/4B,GAGlDq7C,EAGR,MAAM3e,EAAY,GAAUE,UAAW58B,GACjCm4B,EAAS,IAAI,GAAQlE,EAAYyI,EAAWoY,EAAwBvC,GAK1E,OAHAxhE,KAAKyhE,SAASh4D,IAAKy5C,EAAYkE,GAC/BpnD,KAAKqU,KAAM,UAAY6uC,EAAYkE,EAAQ,KAAMn4B,GAE1Cm4B,EAWR,QAASoc,GACR,MAAMtgB,EAAasgB,aAAwB,GAASA,EAAa1lE,KAAO0lE,EAClE8G,EAAYtqE,KAAKyhE,SAASrjE,IAAK8kD,GAErC,QAAKonB,IACJtqE,KAAKyhE,SAAS1tD,OAAQmvC,GACtBljD,KAAKqU,KAAM,UAAY6uC,EAAYonB,EAAWA,EAAUrkB,WAAY,MAEpEjmD,KAAK2qE,eAAgBL,IAEd,GAeT,SAAU9G,GACT,MAAMtgB,EAAasgB,aAAwB,GAASA,EAAa1lE,KAAO0lE,EAClEpc,EAASpnD,KAAKyhE,SAASrjE,IAAK8kD,GAElC,IAAMkE,EAML,MAAM,IAAI,KAAe,6CAA8CpnD,MAGxE,MAAMivB,EAAQm4B,EAAOnB,WAErBjmD,KAAKqU,KAAM,UAAY6uC,EAAYkE,EAAQn4B,EAAOA,EAAOm4B,EAAO2c,uBAAwB3c,EAAOoa,aAShG,sBAAwB32C,GACvB,IAAM,MAAMu8B,KAAUpnD,KAChBonD,EAAOnB,WAAWt4B,iBAAkB9C,WAClCu8B,GAWT,6BAA+Bn4B,GAC9B,IAAM,MAAMm4B,KAAUpnD,KAC+B,OAA/ConD,EAAOnB,WAAWpN,gBAAiB5pB,WACjCm4B,GAQT,UACC,IAAM,MAAMA,KAAUpnD,KAAKyhE,SAASp1D,SACnCrM,KAAK2qE,eAAgBvjB,GAGtBpnD,KAAKyhE,SAAW,KAEhBzhE,KAAKsR,gBAgBN,iBAAmBs5D,GAClB,IAAM,MAAMxjB,KAAUpnD,KAAKyhE,SAASp1D,SAC9B+6C,EAAOtpD,KAAK2sD,WAAYmgB,EAAS,aAC/BxjB,GAWT,eAAgBA,GACfA,EAAO91C,gBACP81C,EAAOyjB,oBAeTr2D,GAAK,GAAkB,IAqEvB,MAAM,GAUL,YAAa1W,EAAM6tD,EAAWoY,EAAwBvC,GAOrDxhE,KAAKlC,KAAOA,EAQZkC,KAAK8qE,WAAa9qE,KAAKwqE,iBAAkB7e,GAQzC3rD,KAAKyqE,wBAA0B1G,EAS/B/jE,KAAK0qE,aAAelJ,EAUrB,6BACC,IAAMxhE,KAAK8qE,WACV,MAAM,IAAI,KAAe,mBAAoB9qE,MAG9C,OAAOA,KAAKyqE,wBAQb,kBACC,IAAMzqE,KAAK8qE,WACV,MAAM,IAAI,KAAe,mBAAoB9qE,MAG9C,OAAOA,KAAK0qE,aAQb,WACC,IAAM1qE,KAAK8qE,WACV,MAAM,IAAI,KAAe,mBAAoB9qE,MAG9C,OAAOA,KAAK8qE,WAAWjqD,MAAM6K,QAQ9B,SACC,IAAM1rB,KAAK8qE,WACV,MAAM,IAAI,KAAe,mBAAoB9qE,MAG9C,OAAOA,KAAK8qE,WAAWhqD,IAAI4K,QAe5B,WACC,IAAM1rB,KAAK8qE,WACV,MAAM,IAAI,KAAe,mBAAoB9qE,MAG9C,OAAOA,KAAK8qE,WAAWjhB,UAiBxB,GAAI5pD,GACH,MAAgB,WAATA,GAA8B,iBAATA,EAU7B,iBAAkB0rD,GAWjB,OAVK3rD,KAAK8qE,YACT9qE,KAAK6qE,mBAINlf,EAAUp6B,SAAU,gBAAiB3d,GAAI5T,MACzC2rD,EAAUp6B,SAAU,kBAAmB3d,GAAI5T,MAE3CA,KAAK8qE,WAAanf,EAEXA,EAQR,mBACC3rD,KAAK8qE,WAAWC,eAAgB,eAAgB/qE,MAChDA,KAAK8qE,WAAWC,eAAgB,iBAAkB/qE,MAClDA,KAAK8qE,WAAW5+B,SAChBlsC,KAAK8qE,WAAa,MAgCpBt2D,GAAK,GAAQ,IC5gBE,MAAM,WAAoB0rD,GACxC,WACC,MAAO,OAQR,QACC,OAAO,IAAI,GAAalgE,KAAKigE,aAQ9B,cACC,OAAO,IAAI,GAAajgE,KAAKigE,YAAc,GAG5C,YAMA,uBACC,MAAO,eC/BT,MAAM,GAAa,GACnB,GAAY,GAAmB75C,WAAc,GAC7C,GAAY,GAAgBA,WAAc,GAC1C,GAAY,GAAgBA,WAAc,GAC1C,GAAY,GAAcA,WAAc,GACxC,GAAY,GAAYA,WAAc,GACtC,GAAY85C,GAAU95C,WAAc85C,GACpC,GAAY,GAAgB95C,WAAc,GAC1C,GAAY,GAAuBA,WAAc,GACjD,GAAY,GAAeA,WAAc,GACzC,GAAY,GAAeA,WAAc,GCD1B,MAAM,WAAqB,GASzC,YAAavpB,EAAMgT,EAAMgvC,EAAa,UAGrC,GAFAj/C,MAAO/C,EAAMgT,EAAMgvC,IAEb7+C,KAAKnD,KAAKsD,GAAI,eAMnB,MAAM,IAAI,KAAe,0CAA2CtD,GAGrE,GAAiBa,KAAMsC,MAQxB,SACCA,KAAKsR,gBAmBN,GAAIrR,GACH,MAAgB,iBAATA,GAAoC,uBAATA,GAEzB,YAARA,GAA+B,mBAATA,EAQxB,aACC,OAAO,IAAI,GAAUD,KAAKnD,KAAMmD,KAAK6P,KAAKpI,QAASzH,KAAK6+C,YAUzD,oBAAqBh0B,EAAUg0B,GAC9B,OAAO,IAAI7+C,KAAM6qB,EAAShuB,KAAMguB,EAAShb,KAAKpI,QAASo3C,GAA0Bh0B,EAASg0B,aA8C5F,SAAS,KACR7+C,KAAKmR,SACJnR,KAAKnD,KAAKmE,SAASgoD,MACnB,iBACA,CAAE/3C,EAAOI,KACR,MAAMquC,EAAYruC,EAAM,GAElBquC,EAAU8J,qBAIhB,GAAU9rD,KAAMsC,KAAM0/C,IAEvB,CAAEjvC,SAAU,QAQd,SAAS,GAAWivC,GACnB,MAAM59C,EAAS9B,KAAKmhD,0BAA2BzB,GAE/C,IAAM1/C,KAAKssB,QAASxqB,GAAW,CAC9B,MAAMkpE,EAAchrE,KAAKirE,aAEzBjrE,KAAK6P,KAAO/N,EAAO+N,KACnB7P,KAAKnD,KAAOiF,EAAOjF,KAEnBmD,KAAKqU,KAAM,SAAU22D,IAIvBx2D,GAAK,GAAc,IC/EnB,MAAM,GACL,YAAaw0C,EAAOh3B,EAAQnH,GAM3B7qB,KAAKgpD,MAAQA,EAObhpD,KAAKgyB,OAASA,EAOdhyB,KAAK6qB,SAAWA,EAahB7qB,KAAKkrE,aAAe,IAAI7yD,IAAK,CAAErY,KAAK6qB,SAAS9N,SAO7C/c,KAAKipD,OAASD,EAAMC,OAEpBjpD,KAAKmrE,oBAAsB,GAQ3BnrE,KAAKorE,eAAiB,KAQtBprE,KAAKqrE,aAAe,KAUrB,YAAatkD,EAAOukD,GACnBvkD,EAAQ5d,MAAMiK,KAAM2T,GAEpB,IAAM,IAAIxpB,EAAI,EAAGA,EAAIwpB,EAAMhlB,OAAQxE,IAAM,CACxC,MAAMgV,EAAOwU,EAAOxpB,GAEpByC,KAAKurE,YAAah5D,EAAM,CACvBi5D,QAAe,IAANjuE,GAAW+tE,EAAcE,QAClCC,OAAUluE,IAAQwpB,EAAMhlB,OAAS,GAASupE,EAAcG,SAK1DzrE,KAAKipD,OAAOyiB,2BAA4B1rE,KAAKmrE,oBAAqBnrE,KAAKgyB,QACvEhyB,KAAKmrE,oBAAsB,GAS5B,oBACC,OAAKnrE,KAAK2rE,aACF,GAAM96C,UAAW7wB,KAAK2rE,cAGvB3rE,KAAKgpD,MAAMC,OAAO8D,yBAA0B/sD,KAAK6qB,UASzD,mBACC,OAAM7qB,KAAKorE,eAIJ,IAAI,GAAOprE,KAAKorE,eAAgBprE,KAAKqrE,cAHpC,KAST,UACMrrE,KAAKorE,gBACTprE,KAAKorE,eAAel/B,SAGhBlsC,KAAKqrE,cACTrrE,KAAKqrE,aAAan/B,SAapB,YAAa35B,EAAM7S,GAIlB,GAAKM,KAAKipD,OAAO6D,SAAUv6C,GAG1B,YAFAvS,KAAK4rE,cAAer5D,EAAM7S,GAQTM,KAAK6rE,gCAAiCt5D,EAAM7S,IAQ9DM,KAAKigC,QAAS1tB,GAcdvS,KAAK8rE,iBAAkBv5D,EAAM7S,IAnB5BM,KAAK+rE,sBAAuBx5D,EAAM7S,GA2BpC,cAAe6S,EAAM7S,GAEfM,KAAK6rE,gCAAiCt5D,GAC1CvS,KAAKigC,QAAS1tB,GAIdvS,KAAKgsE,qBAAsBz5D,EAAM7S,GASnC,sBAAuB6S,EAAM7S,GAEvB6S,EAAKpS,GAAI,WACbH,KAAKisE,YAAa15D,EAAKmU,cAAehnB,GAItCM,KAAKgsE,qBAAsBz5D,EAAM7S,GAQnC,QAAS6S,GAER,IAAMvS,KAAKipD,OAAOiH,WAAYlwD,KAAK6qB,SAAUtY,GAW5C,MAAM,IAAI,KACT,+BACAvS,KACA,CAAEuS,OAAMsY,SAAU7qB,KAAK6qB,WAIzB,MAAMqhD,EAAU,GAAaC,aAAcnsE,KAAK6qB,SAAU,UAE1D7qB,KAAKosE,uBAAwBpsE,KAAK6qB,UAClC7qB,KAAKgyB,OAAOruB,OAAQ4O,EAAMvS,KAAK6qB,UAE/B7qB,KAAK6qB,SAAWqhD,EAAQjB,aACxBiB,EAAQhgC,SAGHlsC,KAAKipD,OAAO6D,SAAUv6C,KAAWvS,KAAKipD,OAAOiH,WAAYlwD,KAAK6qB,SAAU,SAC5E7qB,KAAK2rE,aAAep5D,EAEpBvS,KAAK2rE,aAAe,KAGrB3rE,KAAKmrE,oBAAoBloE,KAAMsP,GAahC,uBAAwBsY,GAIjB7qB,KAAKorE,iBACVprE,KAAKorE,eAAiB,GAAae,aAActhD,EAAU,eAOtD7qB,KAAKqrE,eAAgBrrE,KAAKqrE,aAAaxtD,SAAUgN,KACjD7qB,KAAKqrE,cACTrrE,KAAKqrE,aAAan/B,SAGnBlsC,KAAKqrE,aAAe,GAAac,aAActhD,EAAU,WAS3D,iBAAkBtY,EAAM7S,GACvB,KAAQ6S,aAAgB,IACvB,OAGD,MAAM85D,EAAYrsE,KAAKssE,cAAe/5D,EAAM7S,GACtC6sE,EAAavsE,KAAKwsE,eAAgBj6D,EAAM7S,GACxC+sE,EAAe,GAAatgD,cAAe5Z,GACjDk6D,EAAa5tB,WAAa,SAC1B,MAAM6tB,EAAgB,GAAa7gD,aAActZ,GAGjD,GAFAm6D,EAAc7tB,WAAa,SAEtBwtB,EAAY,CAChB,MAAMM,EAAe,GAAaR,aAAcnsE,KAAK6qB,UACrD8hD,EAAa9tB,WAAa,SAcrB7+C,KAAKorE,eAAe9+C,QAASmgD,KACjCzsE,KAAKorE,eAAel/B,SACpBlsC,KAAKorE,eAAiB,GAAatgD,UAAW2hD,EAAan/C,WAAY,MAAO,eAG/EttB,KAAKgyB,OAAOgxC,MAAOyJ,GAUdA,EAAangD,QAAStsB,KAAKqrE,eAAkB3rE,EAAQ+rE,SACzDzrE,KAAKqrE,aAAan/B,SAClBlsC,KAAKqrE,aAAe,GAAavgD,UAAW2hD,EAAan/C,WAAY,MAAO,WAG7EttB,KAAK6qB,SAAW8hD,EAAa1B,aAC7B0B,EAAazgC,SAGd,GAAKqgC,EAAa,CAEjB,IAAMvsE,KAAK6qB,SAASyB,QAASogD,GAa5B,MAAM,IAAI,KAAe,2CAA4C1sE,MAKtEA,KAAK6qB,SAAW,GAASC,UAAW4hD,EAAcp/C,WAAY,OAI9D,MAAMq/C,EAAe,GAAaR,aAAcnsE,KAAK6qB,SAAU,cAG1D7qB,KAAKqrE,aAAa/+C,QAASogD,KAC/B1sE,KAAKqrE,aAAan/B,SAClBlsC,KAAKqrE,aAAe,GAAavgD,UAAW4hD,EAAcp/C,WAAY,MAAO,WAG9EttB,KAAKgyB,OAAOgxC,MAAO0J,GAGdA,EAAcp+C,cAAe,GAAIhC,QAAStsB,KAAKorE,iBAAoB1rE,EAAQ8rE,UAC/ExrE,KAAKorE,eAAel/B,SACpBlsC,KAAKorE,eAAiB,GAAatgD,UAAW4hD,EAAcp/C,WAAY,EAAG,eAG5EttB,KAAK6qB,SAAW8hD,EAAa1B,aAC7B0B,EAAazgC,UAGTmgC,GAAaE,IAGjBvsE,KAAKmrE,oBAAoBloE,KAAMjD,KAAK6qB,SAAS9N,QAG9C0vD,EAAavgC,SACbwgC,EAAcxgC,SAWf,cAAe35B,EAAM7S,GACpB,MAAMyuB,EAAkB5b,EAAK4b,gBAE7B,OAAOzuB,EAAQ8rE,SACZr9C,aAA2B,IAC7BnuB,KAAKkrE,aAAaxhE,IAAKykB,IACvBnuB,KAAKgpD,MAAMC,OAAOkO,WAAYhpC,EAAiB5b,GAWjD,eAAgBA,EAAM7S,GACrB,MAAMwuB,EAAc3b,EAAK2b,YAEzB,OAAOxuB,EAAQ+rE,QACZv9C,aAAuB,IACzBluB,KAAKkrE,aAAaxhE,IAAKwkB,IACvBluB,KAAKgpD,MAAMC,OAAOkO,WAAY5kD,EAAM2b,GAUtC,qBAAsB3b,EAAM7S,GAC3B,MAAMyxD,EAAYnxD,KAAKgyB,OAAO3uB,cAAe,aAKxCrD,KAAK4sE,cAAezb,EAAWnxD,KAAK6qB,SAAS9N,SAAY/c,KAAKipD,OAAOiH,WAAYiB,EAAW5+C,KAChG4+C,EAAUt4B,aAActmB,GACxBvS,KAAKurE,YAAapa,EAAWzxD,IAU/B,gCAAiC6S,GAChC,MAAMkoD,EAAYz6D,KAAK4sE,cAAer6D,EAAMvS,KAAK6qB,SAAS9N,QAE1D,IAAM09C,EACL,OAAO,EAGR,KAAQA,GAAaz6D,KAAK6qB,SAAS9N,QAAS,CAE3C,GAAK/c,KAAKipD,OAAOG,QAASppD,KAAK6qB,SAAS9N,QACvC,OAAO,EAGR,GAAK/c,KAAK6qB,SAASqB,UAAY,CAG9B,MAAMnP,EAAS/c,KAAK6qB,SAAS9N,OAE7B/c,KAAK6qB,SAAW7qB,KAAKgyB,OAAOsqC,qBAAsBv/C,GAW7CA,EAAO0F,SAAW1F,EAAOA,SAAW09C,GACxCz6D,KAAKgyB,OAAO7tB,OAAQ4Y,QAEf,GAAK/c,KAAK6qB,SAASe,QAGzB5rB,KAAK6qB,SAAW7qB,KAAKgyB,OAAO2qC,oBAAqB38D,KAAK6qB,SAAS9N,YACzD,CACN,MAAM8vD,EAAU7sE,KAAKgyB,OAAO2qC,oBAAqB38D,KAAK6qB,SAAS9N,QAE/D/c,KAAKosE,uBAAwBpsE,KAAK6qB,UAClC7qB,KAAKgyB,OAAOziB,MAAOvP,KAAK6qB,UAExB7qB,KAAK6qB,SAAWgiD,EAEhB7sE,KAAKkrE,aAAat8D,IAAK5O,KAAK6qB,SAASuC,YAIvC,OAAO,EAWR,cAAe7a,EAAMqM,GACpB,OAAK5e,KAAKipD,OAAOiH,WAAYtxC,EAASrM,GAC9BqM,EAGHA,EAAQ7B,OACL/c,KAAK4sE,cAAer6D,EAAMqM,EAAQ7B,QAGnC,MChjBM,SAAS+vD,GAAe9jB,EAAO5+B,EAAWloB,EAAU,IAClE,GAAKkoB,EAAUqD,YACd,OAGD,MAAMs/C,EAAW3iD,EAAUmF,gBAG3B,GAA+B,cAA1Bw9C,EAASlwE,KAAK0tB,SAClB,OAGD,MAAM0+B,EAASD,EAAMC,OAErBD,EAAM5L,OAAQprB,IAGb,IAAM9vB,EAAQ8qE,yBA8ZhB,SAAqD/jB,EAAQ7+B,GAC5D,MAAM0tC,EAAe7O,EAAOgkB,gBAAiB7iD,GAE7C,IAAMA,EAAU6/B,sBAAuB6N,GACtC,OAAO,EAGR,MAAM7oC,EAAQ7E,EAAUmF,gBAExB,GAAKN,EAAMpO,MAAM9D,QAAUkS,EAAMnO,IAAI/D,OACpC,OAAO,EAGR,OAAOksC,EAAOiH,WAAY4H,EAAc,aA3aEoV,CAA4CjkB,EAAQ7+B,GAG5F,YAgZH,SAA4C4H,EAAQ5H,GACnD,MAAM0tC,EAAe9lC,EAAOg3B,MAAMC,OAAOgkB,gBAAiB7iD,GAE1D4H,EAAO7tB,OAAQ6tB,EAAO0iC,cAAeoD,IACrCqV,GAAiBn7C,EAAQA,EAAOo/B,iBAAkB0G,EAAc,GAAK1tC,GAtZnEgjD,CAAmCp7C,EAAQ5H,GAM5C,MAAQO,EAAe8O,GAgDzB,SAA4CxK,GAC3C,MAAM+5B,EAAQ/5B,EAAMpyB,KAAKmE,SAASgoD,MAE5Br+B,EAAgBsE,EAAMpO,MAC5B,IAAI4Y,EAAcxK,EAAMnO,IAIxB,GAAKkoC,EAAM0U,WAAYzuC,EAAO,CAAEo+C,eAAe,IAAW,CACzD,MAAM1kB,EAsBR,SAAyB99B,GACxB,MAAMjM,EAAUiM,EAAS9N,OACnBksC,EAASrqC,EAAQ/hB,KAAKmE,SAASgoD,MAAMC,OACrC3rC,EAAYsB,EAAQpB,aAAc,CAAEH,aAAa,EAAMD,aAAa,IAE1E,IAAM,MAAMwB,KAAWtB,EAAY,CAClC,GAAK2rC,EAAOG,QAASxqC,GACpB,OAAO,KAGR,GAAKqqC,EAAOC,QAAStqC,GACpB,OAAOA,GAjCS,CAAgB6a,GAEjC,GAAKkvB,GAAYlvB,EAAYsnB,WAAYiI,EAAMoI,iBAAkBzI,EAAU,IAAQ,CAElF,MAAMv+B,EAAY4+B,EAAMsL,gBAAiBrlC,GAIzC+5B,EAAMskB,gBAAiBljD,EAAW,CAAEQ,UAAW,aAE/C6O,EAAcrP,EAAUqH,mBAI1B,MAAO,CACN,GAAa06C,aAAcxhD,EAAe,cAC1C,GAAawhD,aAAc1yC,EAAa,WAzED8zC,CAAmCR,GAGpEpiD,EAAco2B,WAAYtnB,IAC/BzH,EAAO7tB,OAAQ6tB,EAAOsU,YAAa3b,EAAe8O,IAW7Cv3B,EAAQsrE,iBAkFhB,SAAwBx7C,EAAQrH,EAAe8O,GAC9C,MAAMuvB,EAAQh3B,EAAOg3B,MAGrB,IAAMykB,GAAkBz7C,EAAOg3B,MAAMC,OAAQt+B,EAAe8O,GAC3D,OA4BD,MAAQi0C,EAAeC,GA4NxB,SAA8CC,EAAWC,GACxD,MAAMtwD,EAAaqwD,EAAUpwD,eACvBC,EAAaowD,EAAUrwD,eAE7B,IAAIjgB,EAAI,EAER,KAAQggB,EAAYhgB,IAAOggB,EAAYhgB,IAAOkgB,EAAYlgB,IACzDA,IAGD,MAAO,CAAEggB,EAAYhgB,GAAKkgB,EAAYlgB,IAtOCuwE,CAAqCnjD,EAAe8O,GAU3F,IAAMi0C,IAAkBC,EACvB,QAGK3kB,EAAM0U,WAAYgQ,EAAe,CAAEL,eAAe,KAAYrkB,EAAM0U,WAAYiQ,EAAa,CAAEN,eAAe,IAmGrH,SAASU,EAAoB/7C,EAAQrH,EAAe8O,EAAau0C,GAChE,MAAM5/C,EAAezD,EAAc5N,OAC7BsR,EAAaoL,EAAY1c,OAG/B,GAAKqR,GAAgB4/C,GAAkB3/C,GAAc2/C,EACpD,OAIDrjD,EAAgBqH,EAAO2qC,oBAAqBvuC,IAC5CqL,EAAczH,EAAOsqC,qBAAsBjuC,IAGzB/B,QAAS3B,IAS1BqH,EAAOruB,OAAQyqB,EAAcqL,GAY9B,KAAQ9O,EAAc5N,OAAO0F,SAAU,CACtC,MAAMwrD,EAAiBtjD,EAAc5N,OAErC4N,EAAgBqH,EAAOsqC,qBAAsB2R,GAE7Cj8C,EAAO7tB,OAAQ8pE,GAoBhB,GAhBAx0C,EAAczH,EAAOsqC,qBAAsBjuC,GAyB5C,SAAqB2D,EAAQnH,GAC5B,MAAMuD,EAAevD,EAASyC,WACxBe,EAAaxD,EAASuC,UAEvBgB,EAAatwB,MAAQuwB,EAAWvwB,MACpCk0B,EAAOk8C,OAAQ9/C,EAAcC,EAAWvwB,MAGzCk0B,EAAOm8C,gBAAiB//C,GACxB4D,EAAOo8C,cAAenwE,OAAOowE,YAAahgD,EAAW0M,iBAAmB3M,GAExE4D,EAAOgxC,MAAOn4C,GAvBd,CAAYmH,EAAQyH,IAGdg0C,GAAkBz7C,EAAOg3B,MAAMC,OAAQt+B,EAAe8O,GAC3D,OAIDs0C,EAAoB/7C,EAAQrH,EAAe8O,EAAau0C,GAnKvDD,CAAoB/7C,EAAQrH,EAAe8O,EAAai0C,EAAc3wD,QAmBxE,SAASuxD,EAAmBt8C,EAAQrH,EAAe8O,EAAau0C,GAC/D,MAAM5/C,EAAezD,EAAc5N,OAC7BsR,EAAaoL,EAAY1c,OAG/B,GAAKqR,GAAgB4/C,GAAkB3/C,GAAc2/C,EACpD,OAIDrjD,EAAgBqH,EAAO2qC,oBAAqBvuC,IAC5CqL,EAAczH,EAAOsqC,qBAAsBjuC,IAGzB/B,QAAS3B,IAS1BqH,EAAOruB,OAAQ0qB,EAAY1D,GAe5BqH,EAAOgxC,MAAOr4C,GAWd,KAAQ8O,EAAY1c,OAAO0F,SAAU,CACpC,MAAMwrD,EAAiBx0C,EAAY1c,OAEnC0c,EAAczH,EAAOsqC,qBAAsB2R,GAE3Cj8C,EAAO7tB,OAAQ8pE,GAIhB,IAAMR,GAAkBz7C,EAAOg3B,MAAMC,OAAQt+B,EAAe8O,GAC3D,OAID60C,EAAmBt8C,EAAQrH,EAAe8O,EAAau0C,GAhFtDM,CAAmBt8C,EAAQrH,EAAe8O,EAAai0C,EAAc3wD,QAnIpEwxD,CAAev8C,EAAQrH,EAAe8O,GAQtCwvB,EAAOyiB,2BAA4B/gD,EAAc5N,OAAO2J,cAAesL,IAGxEw8C,GAAqBx8C,EAAQ5H,EAAWO,IAKlCzoB,EAAQusE,oBA2UhB,SAA8BxlB,EAAQp+B,GACrC,MAAM6jD,EAAgBzlB,EAAOiH,WAAYrlC,EAAU,SAC7C8jD,EAAqB1lB,EAAOiH,WAAYrlC,EAAU,aAExD,OAAQ6jD,GAAiBC,EA/UYC,CAAqB3lB,EAAQt+B,IAChEwiD,GAAiBn7C,EAAQrH,EAAeP,GAGzCO,EAAcuhB,SACdzS,EAAYyS,WAmSd,SAASuhC,GAAkBxkB,EAAQt+B,EAAe8O,GACjD,MAAMrL,EAAezD,EAAc5N,OAC7BsR,EAAaoL,EAAY1c,OAI/B,OAAKqR,GAAgBC,KAKhB46B,EAAOG,QAASh7B,KAAkB66B,EAAOG,QAAS/6B,IAqCxD,SAAiCwgD,EAASC,EAAU7lB,GACnD,MAAM8lB,EAAe,IAAI,GAAOF,EAASC,GAEzC,IAAM,MAAMtwE,KAASuwE,EAAa90C,YACjC,GAAKgvB,EAAOG,QAAS5qD,EAAM6D,MAC1B,OAAO,EAIT,OAAO,EAvCA2sE,CAAwBrkD,EAAe8O,EAAawvB,IA0C5D,SAASkkB,GAAiBn7C,EAAQnH,EAAUT,GAC3C,MAAM+mC,EAAYn/B,EAAO3uB,cAAe,aAExC2uB,EAAOruB,OAAQwtD,EAAWtmC,GAE1B2jD,GAAqBx8C,EAAQ5H,EAAW4H,EAAOo/B,iBAAkBD,EAAW,IAgC7E,SAASqd,GAAqBx8C,EAAQ5H,EAAW6N,GAC3C7N,aAAqB,GACzB4H,EAAOyI,aAAcxC,GAErB7N,EAAUnE,MAAOgS,GCnanB,SAASg3C,GAAgBtvE,EAAMnB,GAC9B,MAAM,UAAE0wE,EAAS,OAAEl1C,EAAM,KAAEm1C,EAAI,OAAElmB,GAAWtpD,GACtC,KAAEM,EAAI,KAAEoC,EAAI,aAAEgqB,GAAiB7tB,EAIrC,GAAa,QAARyB,EACJ,MAAmB,SAAdN,EAAKwvE,KA+DZ,SAAsCn1C,EAAQk1C,GAC7C,IAAI/wD,EAAW6b,EAAOnP,SAAS1M,SAE/B,GAAKA,EAAW,CACf,IAAI7R,EAAS0tB,EAAOnP,SAASve,OAAS6R,EAASiO,YAE/C,MAASgjD,GAAkBjxD,EAASxe,KAAM2M,EAAQ4iE,KAAgBG,GAAkBlxD,EAAU7R,EAAQ4iE,IAAc,CACnHl1C,EAAOzO,OAKP,MAAMghB,EAAW2iC,EAAYl1C,EAAOnP,SAASuC,UAAY4M,EAAOnP,SAASyC,WAGzE,GAAKif,GAAYA,EAASpsC,GAAI,SAAY,CAEzC,MAAMmvE,EAAe/iC,EAAS5sC,KAAKwjB,OAAQ+rD,EAAY,EAAI3iC,EAAS5sC,KAAKoC,OAAS,GArKvD,cAwKEqX,SAAUk2D,KAEtCt1C,EAAOzO,OAEPpN,EAAW6b,EAAOnP,SAAS1M,UAI7B7R,EAAS0tB,EAAOnP,SAASve,OAAS6R,EAASiO,aAI7C,OAAO4N,EAAOnP,SA9FL0kD,CAA6Bv1C,EAAQk1C,GAwC/C,SAA6Bl1C,EAAQm1C,GACpC,MAAMhxD,EAAW6b,EAAOnP,SAAS1M,SAEjC,GAAKA,EAAW,CACf,MAAMxe,EAAOwe,EAASxe,KACtB,IAAI2M,EAAS0tB,EAAOnP,SAASve,OAAS6R,EAASiO,YAE/C,KAAQk9C,GAAuB3pE,EAAM2M,IAAsB,aAAR6iE,GAAuB1F,GAAwB9pE,EAAM2M,IACvG0tB,EAAOzO,OAEPjf,EAAS0tB,EAAOnP,SAASve,OAAS6R,EAASiO,YAI7C,OAAO4N,EAAOnP,SAnDN2kD,CAAoBx1C,EAAQm1C,GAIpC,GAAKlvE,IAAUivE,EAAY,eAAiB,cAAiB,CAE5D,GAAKjmB,EAAO4N,aAAcx0D,GACzB,OAAO,GAASyoB,UAAWzoB,EAAM6sE,EAAY,QAAU,UAIxD,GAAKjmB,EAAOiH,WAAY7jC,EAAc,SACrC,OAAOA,MAIJ,CAEJ,GAAK48B,EAAOG,QAAS/mD,GAIpB,YAFA23B,EAAO5O,KAAM,KAAM,GAMpB,GAAK69B,EAAOiH,WAAY7jC,EAAc,SACrC,OAAOA,GAmEV,SAASojD,GAAgB5uD,EAAOquD,GAC/B,MAAMryE,EAAOgkB,EAAMhkB,KACb6yE,EAAY,GAAS5kD,UAAWjuB,EAAMqyE,EAAY,MAAQ,GAEhE,OAAKA,EACG,IAAI,GAAOruD,EAAO6uD,GAElB,IAAI,GAAOA,EAAW7uD,GAS/B,SAASuuD,GAAkBzvE,EAAM2M,EAAQ4iE,GAExC,MAAMS,EAAgBrjE,GAAW4iE,EAAY,GAAK,GAElD,MA3M8B,cA2MA91D,SAAUzZ,EAAKwjB,OAAQwsD,IAQtD,SAASN,GAAkBlxD,EAAU7R,EAAQ4iE,GAC5C,OAAO5iE,KAAa4iE,EAAY/wD,EAASoO,UAAY,GCpHtD,SAASqjD,GAAoB3gD,EAAO+C,GACnC,MAAM69C,EAAiB,GAEvB1mE,MAAMiK,KAAM6b,EAAMq4B,SAAU,CAAE18B,UAAW,cAGvCvgB,IAAKhI,GAAQ2vB,EAAO+0B,cAAe1kD,IAKnC2B,OAAQ8rE,IAGLA,EAAUjvD,MAAMqM,QAAS+B,EAAMpO,QAAWivD,EAAUjvD,MAAMyL,QAAS2C,EAAMpO,UACzEivD,EAAUhvD,IAAIjD,SAAUoR,EAAMnO,MAASgvD,EAAUhvD,IAAIwL,QAAS2C,EAAMnO,OAIvErd,QAASqsE,IACTD,EAAe5sE,KAAM6sE,EAAUjvD,MAAM9D,QAErCiV,EAAO7tB,OAAQ2rE,KAKjBD,EAAepsE,QAASssE,IACvB,IAAIhzD,EAASgzD,EAEb,KAAQhzD,EAAOA,QAAUA,EAAO0F,SAAU,CACzC,MAAMutD,EAAch+C,EAAO+0B,cAAehqC,GAE1CA,EAASA,EAAOA,OAEhBiV,EAAO7tB,OAAQ6rE,MCnFX,SAASC,GAA0BjnB,GACzCA,EAAMhoD,SAASkvE,kBAAmBl+C,GAOnC,SAA6BA,EAAQg3B,GACpC,MAAM5+B,EAAY4+B,EAAMhoD,SAASopB,UAC3B6+B,EAASD,EAAMC,OAEfp7B,EAAS,GAEf,IAAIoE,GAAW,EAEf,IAAM,MAAMwxB,KAAcr5B,EAAU8F,YAAc,CAGjD,MAAMigD,EAAiBC,GAAgB3sB,EAAYwF,GAS9CknB,IAAmBA,EAAe7jD,QAASm3B,IAC/C51B,EAAO5qB,KAAMktE,GACbl+C,GAAW,GAEXpE,EAAO5qB,KAAMwgD,GAKVxxB,GACJD,EAAOyI,aAgKT,SAAkC5M,GACjC,MAAMwiD,EAAwB,GAG9BA,EAAsBptE,KAAM4qB,EAAOpB,SAEnC,IAAM,MAAMwC,KAASpB,EAAS,CAC7B,MAAMyiD,EAAgBD,EAAsBjnE,MAE5C,GAAK6lB,EAAM3C,QAASgkD,GAEnBD,EAAsBptE,KAAMqtE,QACtB,GAAKrhD,EAAMnB,eAAgBwiD,GAAkB,CAEnD,MAAMzvD,EAAQyvD,EAAczvD,MAAMqM,QAAS+B,EAAMpO,OAAUoO,EAAMpO,MAAQyvD,EAAczvD,MACjFC,EAAMwvD,EAAcxvD,IAAIoM,QAAS+B,EAAMnO,KAAQwvD,EAAcxvD,IAAMmO,EAAMnO,IAEzEyvD,EAAS,IAAI,GAAO1vD,EAAOC,GACjCuvD,EAAsBptE,KAAMstE,QAE5BF,EAAsBptE,KAAMqtE,GAC5BD,EAAsBptE,KAAMgsB,GAI9B,OAAOohD,EAzLeG,CAAyB3iD,GAAU,CAAE8C,SAAUvG,EAAU4F,aArCnCygD,CAAoBz+C,EAAQg3B,IA8CzE,SAASonB,GAAgBnhD,EAAOg6B,GAC/B,OAAKh6B,EAAMxB,YAcZ,SAAkCwB,EAAOg6B,GACxC,MAAMynB,EAAmBzhD,EAAMpO,MAEzB8vD,EAAwB1nB,EAAO8D,yBAA0B2jB,GAI/D,IAAMC,EACL,OAAO,KAGR,IAAMA,EAAsBljD,YAC3B,OAAOkjD,EAGR,MAAMC,EAAgBD,EAAsB9vD,MAG5C,GAAK6vD,EAAiBpkD,QAASskD,GAC9B,OAAO,KAGR,OAAO,IAAI,GAAOA,GAnCVC,CAAyB5hD,EAAOg6B,GA2CzC,SAAoCh6B,EAAOg6B,GAC1C,MAAM,MAAEpoC,EAAK,IAAEC,GAAQmO,EAEjB6hD,EAAuB7nB,EAAOiH,WAAYrvC,EAAO,SACjDkwD,EAAqB9nB,EAAOiH,WAAYpvC,EAAK,SAE7CkwD,EAAoB/nB,EAAOgkB,gBAAiBpsD,GAC5CowD,EAAkBhoB,EAAOgkB,gBAAiBnsD,GAGhD,GAAKkwD,IAAsBC,EAAkB,CAI5C,GAAKH,GAAwBC,EAC5B,OAAO,KAQR,GAuEF,SAA2ClwD,EAAOC,EAAKmoC,GACtD,MAAMioB,EAAmBrwD,EAAMuM,YAAc67B,EAAOG,QAASvoC,EAAMuM,YAAiB67B,EAAOiH,WAAYrvC,EAAO,SACxGswD,EAAiBrwD,EAAIwM,aAAe27B,EAAOG,QAAStoC,EAAIwM,aAAkB27B,EAAOiH,WAAYpvC,EAAK,SAGxG,OAAOowD,GAAkBC,EA5EnBC,CAAkCvwD,EAAOC,EAAKmoC,GAAW,CAC7D,MACMooB,EAD0BxwD,EAAMuM,WAAa67B,EAAO4N,aAAch2C,EAAMuM,WACjC,KAAO67B,EAAO8D,yBAA0BlsC,EAAO,WAGtFywD,EADuBxwD,EAAIwM,YAAc27B,EAAO4N,aAAc/1C,EAAIwM,YAChC,KAAO27B,EAAO8D,yBAA0BjsC,EAAK,YAG/Ekc,EAAaq0C,EAAaA,EAAWxwD,MAAQA,EAC7Coc,EAAWq0C,EAAWA,EAASxwD,IAAMA,EAE3C,OAAO,IAAI,GAAOkc,EAAYC,IAIhC,MAAMs0C,EAAiBP,IAAsBA,EAAkB7wE,GAAI,eAC7DqxE,EAAeP,IAAoBA,EAAgB9wE,GAAI,eAI7D,GAAKoxE,GAAkBC,EAAe,CACrC,MAAMC,EAAqB5wD,EAAMuM,WAAatM,EAAIwM,YAAgBzM,EAAMuM,UAAUrQ,SAAW+D,EAAIwM,WAAWvQ,OAEtG20D,EAAcH,KAAqBE,IAAqB5a,GAAch2C,EAAMuM,UAAW67B,IACvF0oB,EAAYH,KAAmBC,IAAqB5a,GAAc/1C,EAAIwM,WAAY27B,IAIxF,IAAIooB,EAAaxwD,EACbywD,EAAWxwD,EAUf,OARK4wD,IACJL,EAAa,GAASllD,cAAeylD,GAA4BZ,EAAmB/nB,KAGhF0oB,IACJL,EAAW,GAASzlD,aAAc+lD,GAA4BX,EAAiBhoB,KAGzE,IAAI,GAAOooB,EAAYC,GAI/B,OAAO,KA1GAO,CAA2B5iD,EAAOg6B,GAmH1C,SAAS2oB,GAA4BE,EAAc7oB,GAClD,IAAI8oB,EAAcD,EACd/0D,EAASg1D,EAGb,KAAQ9oB,EAAOG,QAASrsC,IAAYA,EAAOA,QAC1Cg1D,EAAch1D,EACdA,EAASA,EAAOA,OAGjB,OAAOg1D,EAsDR,SAASlb,GAActkD,EAAM02C,GAC5B,OAAO12C,GAAQ02C,EAAO4N,aAActkD,GChQtB,MAAM,GACpB,cAOCvS,KAAKmlD,QAAU,IAAI,GAQnBnlD,KAAKgB,SAAW,IAAI,GAAUhB,MAQ9BA,KAAKipD,OAAS,IAAI,GASlBjpD,KAAKgyE,gBAAkB,GAQvBhyE,KAAKwkE,eAAiB,KAEtB,CAAE,gBAAiB,gBAAiB,kBAAmB,qBAAsB,kBAC3E/gE,QAASulB,GAAchpB,KAAKm2D,SAAUntC,IAIxChpB,KAAKkpB,GAAI,iBAAkB,CAAEpS,EAAKzF,KACfA,EAAM,GAEd4gE,aACR,CAAExhE,SAAU,YAGfzQ,KAAKipD,OAAOipB,SAAU,QAAS,CAC9B9oB,SAAS,IAEVppD,KAAKipD,OAAOipB,SAAU,SAAU,CAC/BhZ,QAAS,QACThQ,SAAS,IAEVlpD,KAAKipD,OAAOipB,SAAU,QAAS,CAC9BhZ,QAAS,SACTrM,UAAU,EACViK,WAAW,IAEZ92D,KAAKipD,OAAOipB,SAAU,mBAAoB,CACzCxY,eAAgB,QAChBtQ,SAAS,IAEVppD,KAAKipD,OAAOlyB,OAAQ,QAAS,CAAEmiC,QAAS,qBAMxCl5D,KAAKipD,OAAOipB,SAAU,WACtBlyE,KAAKipD,OAAOkpB,cAAe,CAAEzyE,EAAS0yE,KACrC,GAA8B,YAAzBA,EAAgBt0E,KACpB,OAAO,IAITmyE,GAA0BjwE,MAG1BA,KAAKgB,SAASkvE,kBAAmBtf,IA0ClC,OAAQ1/C,GACP,IACC,OAAqC,IAAhClR,KAAKgyE,gBAAgBjwE,QAEzB/B,KAAKgyE,gBAAgB/uE,KAAM,CAAEkoD,MAAO,IAAI4U,GAAS7uD,aAE1ClR,KAAKqyE,qBAAsB,IAG3BnhE,EAAUlR,KAAKwkE,gBAEtB,MAAQtkE,GAGT,KAAcyT,uBAAwBzT,EAAKF,OAyC7C,cAAesyE,EAAaphE,GAC3B,IAC6B,iBAAhBohE,EACXA,EAAc,IAAIvS,GAAOuS,GACQ,mBAAfA,IAClBphE,EAAWohE,EACXA,EAAc,IAAIvS,IAGnB//D,KAAKgyE,gBAAgB/uE,KAAM,CAAEkoD,MAAOmnB,EAAaphE,aAEb,GAA/BlR,KAAKgyE,gBAAgBjwE,QACzB/B,KAAKqyE,qBAEL,MAAQnyE,GAGT,KAAcyT,uBAAwBzT,EAAKF,OAe7C,eAAgB0/C,GAefA,EAAU6yB,WAkJX,cAAerrE,EAASynB,EAAYC,GACnC,OLzXa,SAAwBo6B,EAAO9hD,EAASynB,EAAYC,GAClE,OAAOo6B,EAAM5L,OAAQprB,IACpB,IAAI5H,EAKHA,EAHKuE,EAEMA,aAAsB,IAAaA,aAAsB,GACxDA,EAEAqD,EAAOsiC,gBAAiB3lC,EAAYC,GAJpCo6B,EAAMhoD,SAASopB,UAOtBA,EAAUqD,aACfu7B,EAAM8jB,cAAe1iD,EAAW,CAAEqkD,oBAAoB,IAGvD,MAAM+D,EAAY,IAAI,GAAWxpB,EAAOh3B,EAAQ5H,EAAU+E,QAE1D,IAAIsjD,EAGHA,EADIvrE,EAAQ/G,GAAI,oBACA+G,EAAQwf,cAER,CAAExf,GAGnBsrE,EAAUvG,YAAawG,EAAe,CAGrCjH,SAAS,EACTC,QAAQ,IAGT,MAAM9wC,EAAW63C,EAAUE,oBAGtB/3C,IACCvQ,aAAqB,GACzB4H,EAAOyI,aAAcE,GAErBvQ,EAAUnE,MAAO0U,IASnB,MAAMg4C,EAAgBH,EAAUI,oBAAsB5pB,EAAM1iB,YAAalc,EAAU+E,QAInF,OAFAqjD,EAAUt4D,UAEHy4D,IKoUAE,CAAe7yE,KAAMkH,EAASynB,EAAYC,GAoDlD,cAAexE,EAAWloB,GACzB4qE,GAAe9sE,KAAMoqB,EAAWloB,GAgCjC,gBAAiBkoB,EAAWloB,IHlcd,SAA0B8mD,EAAO5+B,EAAWloB,EAAU,IACpE,MAAM+mD,EAASD,EAAMC,OACfimB,EAAiC,YAArBhtE,EAAQ0oB,UACpBukD,EAAOjtE,EAAQitE,KAAOjtE,EAAQitE,KAAO,YAErCt/C,EAAQzF,EAAUyF,MAElBmK,EAAS,IAAI,GAAY,CAC9BtP,WAAY+kD,GAAgB5/C,EAAOq/C,GACnCnkD,kBAAkB,EAClBH,UAAWskD,EAAY,UAAY,aAG9BvvE,EAAO,CAAEq6B,SAAQivB,SAAQimB,YAAWC,QAE1C,IAAI5jD,EAEJ,KAAUA,EAAOyO,EAAOzO,QAAW,CAClC,GAAKA,EAAKF,KACT,OAGD,MAAMR,EAAWokD,GAAgBtvE,EAAM4rB,EAAK/sB,OAE5C,GAAKqsB,EASJ,YARKT,aAAqB,GACzB4+B,EAAM5L,OAAQprB,IACbA,EAAO8gD,kBAAmBjoD,KAG3BT,EAAUwH,SAAU/G,KGqatByiD,CAAiBttE,KAAMoqB,EAAWloB,GAgCnC,mBAAoBkoB,GACnB,OF1fa,SAA6B4+B,EAAO5+B,GAClD,OAAO4+B,EAAM5L,OAAQprB,IACpB,MAAM+gD,EAAO/gD,EAAOkX,yBACdja,EAAQ7E,EAAUmF,gBAExB,IAAMN,GAASA,EAAMxB,YACpB,OAAOslD,EAGR,MAAMl2E,EAAOoyB,EAAMpO,MAAMhkB,KACnBm2E,EAAa/jD,EAAMpO,MAAMmgC,cAAe/xB,EAAMnO,KAC9CmyD,EAAep2E,EAAKq2E,cAAeF,GAezC,IAAIG,EAIHA,EAFIlkD,EAAMpO,MAAM9D,QAAUkS,EAAMnO,IAAI/D,OAEjBkS,EAEA+C,EAAOsU,YACzBtU,EAAOo/B,iBAAkB6hB,EAAchkD,EAAMpO,MAAMhR,KAAMmjE,EAAWjxE,SACpEiwB,EAAOo/B,iBAAkB6hB,EAAchkD,EAAMnO,IAAIjR,KAAMmjE,EAAWjxE,QAAW,IAI/E,MAAMklB,EAAUksD,EAAiBryD,IAAIxU,OAAS6mE,EAAiBtyD,MAAMvU,OAGrE,IAAM,MAAMjK,KAAQ8wE,EAAiB7rB,SAAU,CAAEt8B,SAAS,IACpD3oB,EAAKlC,GAAI,cACb6xB,EAAOohD,WAAY/wE,EAAK1C,KAAM0C,EAAK04B,gBAAiBg4C,GAEpD/gD,EAAO6pC,OAAQ7pC,EAAOqhD,aAAchxE,GAAM,GAAQ0wE,GAmBpD,GAAKI,GAAoBlkD,EAAQ,CAEhC,MAAM0L,EAAW1L,EAAM+wB,sBAAuBmzB,EAAiBtyD,MAAOmR,EAAOo/B,iBAAkB2hB,EAAM,GAAK9rD,GAAW,GAE/GqsD,EAAkBthD,EAAOsU,YAAatU,EAAOo/B,iBAAkB2hB,EAAM,GAAKp4C,EAAS9Z,OAGzF+uD,GAFyB59C,EAAOsU,YAAa3L,EAAS7Z,IAAKkR,EAAOo/B,iBAAkB2hB,EAAM,QAEpD/gD,GACtC49C,GAAoB0D,EAAiBthD,GAGtC,OAAO+gD,IE+aAQ,CAAoBvzE,KAAMoqB,GAyBlC,WAAYopD,EAAgBtxE,EAAU,IACrC,MAAM+sB,EAAQukD,aAA0B,GAAe,GAAW5iD,UAAW4iD,GAAmBA,EAEhG,GAAKvkD,EAAMxB,YACV,OAAO,EAGR,MAAM,kBAAEkwC,GAAoB,EAAK,cAAE0P,GAAgB,GAAUnrE,EAG7D,IAAMmrE,EACL,IAAM,MAAMoG,KAAsBzzE,KAAKmlD,QAAQ8gB,4BAA6Bh3C,GAC3E,GAAKwkD,EAAmBjS,YACvB,OAAO,EAKV,IAAM,MAAMn/D,KAAQ4sB,EAAMq4B,WACzB,GAAKtnD,KAAKipD,OAAO6N,UAAWz0D,GAAS,CACpC,IAAKA,EAAKlC,GAAI,cAOb,OAAO,EANP,IAAMw9D,EACL,OAAO,EACD,IAAmC,IAA9Bt7D,EAAK1C,KAAKuzB,OAAQ,MAC7B,OAAO,EAQX,OAAO,EAeR,uBAAwBr2B,EAAMgT,EAAMgvC,GACnC,OAAO,IAAI,GAAehiD,EAAMgT,EAAMgvC,GAwBvC,iBAAkB9xB,EAAgBzgB,GACjC,OAAO,GAAcwe,UAAWiC,EAAgBzgB,GAYjD,oBAAqBjK,GACpB,OAAO,GAAcwpB,aAAcxpB,GAYpC,qBAAsBA,GACrB,OAAO,GAAc8pB,cAAe9pB,GAkBrC,YAAawe,EAAOC,GACnB,OAAO,IAAI,GAAYD,EAAOC,GAiB/B,cAAelC,GACd,OAAO,GAAWgS,UAAWhS,GAgB9B,cAAevc,GACd,OAAO,GAAWwuB,UAAWxuB,GA0D9B,gBAAiBssB,EAAYC,EAAe1sB,GAC3C,OAAO,IAAI,GAAgBysB,EAAYC,EAAe1sB,GAcvD,YAAajC,GACZ,OAAO,IAAI8/D,GAAO9/D,GAWnB,wBAAyB+d,GACxB,OP3vBa,MAQd,gBAAiBA,EAAMhd,GACtB,OAAO,GAAYgd,EAAKmiD,aAAcvhB,SAAU5gC,EAAMhd,KOkvB9B49C,SAAU5gC,EAAMhe,KAAKgB,UAM9C,UACChB,KAAKgB,SAASkZ,UACdla,KAAKsR,gBAUN,qBACC,MAAMoiE,EAAM,GAIZ,IAFA1zE,KAAKqU,KAAM,kBAEHrU,KAAKgyE,gBAAgBjwE,QAAS,CAErC,MAAM4xE,EAAe3zE,KAAKgyE,gBAAiB,GAAI7mB,MAC/CnrD,KAAKwkE,eAAiB,IAAI,GAAQxkE,KAAM2zE,GAGxC,MAAMC,EAAsB5zE,KAAKgyE,gBAAiB,GAAI9gE,SAAUlR,KAAKwkE,gBACrEkP,EAAIzwE,KAAM2wE,GAEV5zE,KAAKgB,SAAS6yE,mBAAoB7zE,KAAKwkE,gBAEvCxkE,KAAKgyE,gBAAgBvlD,QACrBzsB,KAAKwkE,eAAiB,KAKvB,OAFAxkE,KAAKqU,KAAM,iBAEJq/D,GAoFTl/D,GAAK,GAAO,ICj3BG,MAAM,GAIpB,cAOCxU,KAAK8zE,UAAY71E,OAAOY,OAAQ,IAQjC,SAAU0S,GAUTvR,KAAK8zE,UAAU3iE,SAAUI,EAAS,UAAW,CAAEuF,EAAKi9D,KACnD/zE,KAAK8zE,UAAUz/D,KAAM,YAAcigB,GAASy/C,GAAcA,KAiB5D,IAAKn/C,EAAW1jB,EAAUhP,EAAU,IACnC,MAAMqyB,EAAUI,GAAgBC,GAC1BnkB,EAAWvO,EAAQuO,SAIzBzQ,KAAK8zE,UAAU3iE,SAAUnR,KAAK8zE,UAAW,YAAcv/C,EAAS,CAAEzd,EAAKi9D,KACtE7iE,EAAU6iE,EAAY,KAGrBA,EAAWngC,iBACXmgC,EAAWlgC,kBAIX/8B,EAAIhH,SAILgH,EAAIpD,QAAS,GACX,CAAEjD,aASN,MAAOsjE,GACN,QAAS/zE,KAAK8zE,UAAUz/D,KAAM,YAAcigB,GAASy/C,GAAcA,GAMpE,UACC/zE,KAAK8zE,UAAUxiE,iBCvGF,MAAM,WAAgC,GAMpD,YAAaiL,GACZ3c,QAQAI,KAAKuc,OAASA,EAoBf,IAAKqY,EAAW1jB,EAAUhP,EAAU,IACnC,GAAwB,iBAAZgP,EAAuB,CAClC,MAAM6jD,EAAc7jD,EAEpBA,EAAW,CAAE8iE,EAAS99B,KACrBl2C,KAAKuc,OAAO04C,QAASF,GACrB7e,KAIFt2C,MAAM6J,IAAKmrB,EAAW1jB,EAAUhP,ICxBnB,MAAM,GAQpB,YAAa2Z,EAAS,IAQrB7b,KAAKyX,SAAWoE,EAAOnc,SAAW,IAAI,GAAS,CAAE6a,SAAUsB,EAAOtB,WAClEva,KAAKyX,SAASw8D,WAAYj0E,MAAO6b,EAAOnc,SAIxC,MAAM6X,EAAmBpO,MAAMiK,KAAMpT,KAAK0H,YAAYqU,gBAAkB,IAWxE/b,KAAK6b,OAAS,IAAI,GAAQA,EAAQ7b,KAAK0H,YAAYoU,eACnD9b,KAAK6b,OAAO5e,OAAQ,UAAWsa,GAC/BvX,KAAK6b,OAAO5e,OAAQ+C,KAAKyX,SAASy8D,oBAUlCl0E,KAAKiY,QAAU,IAAI,GAAkBjY,KAAMuX,EAAkBvX,KAAKyX,SAASQ,SAQ3EjY,KAAKic,OAASjc,KAAKyX,SAASwE,OAQ5Bjc,KAAKvB,EAAIuB,KAAKic,OAAOxd,EAgBrBuB,KAAKk1D,SAAW,IAAI,GAgBpBl1D,KAAKyJ,IAAK,QAAS,gBACnBzJ,KAAKm0E,KAAM,QAAS,IAAQn0E,KAAKo0E,MAAQ,QAAW,CAAE3jE,SAAU,SAChEzQ,KAAKm0E,KAAM,UAAW,IAAQn0E,KAAKo0E,MAAQ,YAAe,CAAE3jE,SAAU,SAetEzQ,KAAKyJ,IAAK,cAAc,GAUxBzJ,KAAKgpD,MAAQ,IAAI,GAEjB,MAAMhjC,EAAkB,IAAI,GAS5BhmB,KAAKL,KAAO,IAAI,GAAgBK,KAAKgpD,MAAOhjC,GAS5ChmB,KAAKq0E,QAAU,IAAI,GAAmBr0E,KAAKgpD,MAAOhjC,GAClDhmB,KAAKq0E,QAAQ3+C,KAAK10B,SAASjC,KAAM,cAAe6U,GAAI5T,MAUpDA,KAAKs0E,WAAa,IAAI,GAAY,CAAEt0E,KAAKq0E,QAAQrgB,mBAAoBh0D,KAAKL,KAAKq0D,oBAAsBh0D,KAAKL,KAAK29D,kBAC/Gt9D,KAAKs0E,WAAWC,SAAU,eAAgBv0E,KAAKL,KAAKq0D,oBACpDh0D,KAAKs0E,WAAWC,SAAU,kBAAmBv0E,KAAKq0E,QAAQrgB,oBA2B1Dh0D,KAAKw0E,WAAa,IAAI,GAAyBx0E,MAC/CA,KAAKw0E,WAAWrjE,SAAUnR,KAAKq0E,QAAQ3+C,KAAK10B,UAS7C,cACC,MAAM6a,EAAS7b,KAAK6b,OACd5D,EAAU4D,EAAOzd,IAAK,WACtB8Z,EAAgB2D,EAAOzd,IAAK,kBAAqB,GACjDq2E,EAAe54D,EAAOzd,IAAK,iBAAoB,GAErD,OAAO4B,KAAKiY,QAAQqE,KAAMrE,EAAQxV,OAAQgyE,GAAgBv8D,GAY3D,UACC,IAAIw8D,EAAe37D,QAAQ/L,UAM3B,MAJmB,gBAAdhN,KAAKo0E,QACTM,EAAe,IAAI37D,QAAS/L,GAAWhN,KAAKm0E,KAAM,QAASnnE,KAGrD0nE,EACLx7D,KAAM,KACNlZ,KAAKqU,KAAM,WACXrU,KAAKsR,gBACLtR,KAAKk1D,SAASh7C,YAEdhB,KAAM,IAAMlZ,KAAKiY,QAAQiC,WACzBhB,KAAM,KACNlZ,KAAKgpD,MAAM9uC,UACXla,KAAKL,KAAKua,UACVla,KAAKq0E,QAAQn6D,UACbla,KAAKw0E,WAAWt6D,YAIhBhB,KAAM,IAAMlZ,KAAKyX,SAASk9D,cAAe30E,OAc5C,WAAYqR,GACX,IACC,OAAOrR,KAAKk1D,SAASD,WAAY5jD,GAChC,MAAQnR,GAGT,KAAcyT,uBAAwBzT,EAAKF,OAa7C,QACCA,KAAKq0E,QAAQ3+C,KAAK7F,SAoBpBrb,GAAK,GAAQ,ICzSE,OAhBM,CAIpB,QAAS7U,GACRK,KAAKL,KAAK8J,IAAK9J,IAMhB,QAASuC,GACR,OAAOlC,KAAKL,KAAKvB,IAAK8D,KCeT,OAxBS,CAIvB,sBACC,IAAMlC,KAAKihE,cASV,MAAM,IAAI,KACT,+BACAjhE,MCjBW,IAA2B40E,EAAIj1E,EAAJi1E,EDqBtB50E,KAAKihE,cCrBqBthE,EDqBNK,KAAKL,KAAKvB,MCpB5Cw2E,aAAcC,sBAClBD,EAAGp2E,MAAQmB,GAGZi1E,EAAGtqC,UAAY3qC,ICLD,MAAMm1E,GAOpB,QAASC,GACR,MACM17C,EADMr4B,SAASg0E,eAAeC,mBAAoB,IAClC5xE,cAAe,OAGrC,OAFAg2B,EAAUz1B,YAAamxE,GAEhB17C,EAAUiR,WCTJ,MAAM,GAMpB,YAAatpC,GAOZhB,KAAKk1E,WAAa,IAAIC,UAQtBn1E,KAAKo1E,cAAgB,IAAI,GAAcp0E,EAAU,CAAEmnC,gBAAiB,SAQpEnoC,KAAKq1E,YAAc,IAAIP,GAUxB,OAAQ/rC,GAEP,MAAMD,EAAc9oC,KAAKo1E,cAAcnxC,UAAW8E,EAAc/nC,UAGhE,OAAOhB,KAAKq1E,YAAYC,QAASxsC,GASlC,OAAQnpC,GAEP,MAAMmpC,EAAc9oC,KAAKu1E,OAAQ51E,GAGjC,OAAOK,KAAKo1E,cAAcxwC,UAAWkE,GAatC,0BAA2BrqB,GAC1Bze,KAAKo1E,cAAcI,0BAA2B/2D,GAW/C,OAAQ9e,GACP,MAAMqB,EAAWhB,KAAKk1E,WAAWO,gBAAiB91E,EAAM,aAClDo1E,EAAW/zE,EAASkoC,yBACpBniB,EAAQ/lB,EAASq5C,KAAK71C,WAE5B,KAAQuiB,EAAMhlB,OAAS,GACtBgzE,EAASnxE,YAAamjB,EAAO,IAG9B,OAAOguD,GC/EM,MAAM,GAOpB,YAAax4D,GAOZvc,KAAKuc,OAASA,EAQdvc,KAAK01E,YAAc,IAAI5hE,IAQxB,SACC,IAAM,MAAMtV,KAASwB,KAAK01E,YAAYrpE,eAC/B7N,EAAMm3E,aAad,IAAK73E,EAAMoT,GACVlR,KAAK01E,YAAYjsE,IAAKsa,GAAejmB,GAAQ,CAAEoT,WAAUykE,aAAc73E,IAaxE,OAAQA,GACP,IAAMkC,KAAK0J,IAAK5L,GASf,MAAM,IAAI,KACT,gCACAkC,KACA,CAAElC,SAIJ,OAAOkC,KAAK01E,YAAYt3E,IAAK2lB,GAAejmB,IAASoT,SAAUlR,KAAKuc,OAAON,QAS5E,IAAKne,GACJ,OAAOkC,KAAK01E,YAAYhsE,IAAKqa,GAAejmB,KAU9C,SAASimB,GAAejmB,GACvB,OAAOgO,OAAQhO,GAAO20B,cCnGR,MAAM,GACpB,cAQCzyB,KAAKyJ,IAAK,aAAa,GAavBzJ,KAAKyJ,IAAK,iBAAkB,MAQ5BzJ,KAAK41E,UAAY,IAAIv9D,IAQrBrY,KAAK61E,sBAAwB,KAQ9B,IAAKj3D,GACJ,GAAK5e,KAAK41E,UAAUlsE,IAAKkV,GAMxB,MAAM,IAAI,KAAe,yCAA0C5e,MAGpEA,KAAKmR,SAAUyN,EAAS,QAAS,IAAM5e,KAAK81E,OAAQl3D,GAAW,CAAEgwB,YAAY,IAC7E5uC,KAAKmR,SAAUyN,EAAS,OAAQ,IAAM5e,KAAK+1E,QAAS,CAAEnnC,YAAY,IAClE5uC,KAAK41E,UAAUhnE,IAAKgQ,GAQrB,OAAQA,GACFA,IAAY5e,KAAKg2E,gBACrBh2E,KAAK+1E,MAAOn3D,GAGR5e,KAAK41E,UAAUlsE,IAAKkV,KACxB5e,KAAKsR,cAAesN,GACpB5e,KAAK41E,UAAU7hE,OAAQ6K,IASzB,UACC5e,KAAKsR,gBASN,OAAQsN,GACPq3B,aAAcj2C,KAAK61E,uBAEnB71E,KAAKg2E,eAAiBp3D,EACtB5e,KAAKmqB,WAAY,EAUlB,QACC8rB,aAAcj2C,KAAK61E,uBAEnB71E,KAAK61E,sBAAwBrgC,WAAY,KACxCx1C,KAAKg2E,eAAiB,KACtBh2E,KAAKmqB,WAAY,GACf,IAYL3V,GAAK,GAAc,IACnBA,GAAK,GAAc,ICtIJ,MAAM,GAMpB,YAAa+H,GAOZvc,KAAKuc,OAASA,EASdvc,KAAKi2E,iBAAmB,IAAI,GAAkB15D,GAS9Cvc,KAAKk2E,aAAe,IAAI,GAQxBl2E,KAAKm2E,qBAAuB,IAAIriE,IAGhC9T,KAAKmR,SAAUoL,EAAO83D,QAAQ3+C,KAAK10B,SAAU,gBAAiB,IAAMhB,KAAKmF,UAkB1E,cACC,OAAO,KASR,SACCnF,KAAKqU,KAAM,UAMZ,UACCrU,KAAKsR,gBAELtR,KAAKk2E,aAAah8D,UAGlB,IAAM,MAAMqb,KAAcv1B,KAAKm2E,qBAAqB9pE,SACnDkpB,EAAW6gD,iBAAmB,KAG/Bp2E,KAAKm2E,qBAAuB,IAAIriE,IAUjC,mBAAoByW,EAAUgL,GAC7Bv1B,KAAKm2E,qBAAqB1sE,IAAK8gB,EAAUgL,GAMnCA,EAAW6gD,mBAChB7gD,EAAW6gD,iBAAmBp2E,KAAKuc,QAUrC,mBAAoBgO,EAAW,QAC9B,OAAOvqB,KAAKm2E,qBAAqB/3E,IAAKmsB,GAQvC,2BACC,OAAOvqB,KAAKm2E,qBAAqB3yE,OAUlC,wBAcC,OALAhD,QAAQC,KACP,8IAEA,CAAE41E,SAAUr2E,OAENA,KAAKm2E,sBAqBd3hE,GAAK,GAAU,I,MCpLf,MAAM8hE,GAAuB,IAAIhhE,QAoB1B,SAASihE,GAAmBr0E,GAClC,MAAM,KAAEwzB,EAAI,QAAE9W,EAAO,KAAE2zB,EAAI,aAAEikC,GAAe,GAASt0E,EAC/CklC,EAAM1R,EAAK10B,SAGXs1E,GAAqB5sE,IAAK09B,KAC/BkvC,GAAqB7sE,IAAK29B,EAAK,IAAItzB,KAInCszB,EAAI8oC,kBAAmBl+C,GAAUykD,GAA4BrvC,EAAKpV,KAInEskD,GAAqBl4E,IAAKgpC,GAAM39B,IAAKmV,EAAS,CAC7C2zB,OACAikC,iBAID9gD,EAAK0nB,OAAQprB,GAAUykD,GAA4BrvC,EAAKpV,IAsElD,SAAS0kD,GAAiB1kD,EAAQpT,GACxC,QAAKA,EAAQW,SAAU,oBACtByS,EAAO6K,YAAa,iBAAkBje,IAE/B,GAoDT,SAAS63D,GAA4BrvC,EAAKpV,GACzC,MAAM2kD,EAAeL,GAAqBl4E,IAAKgpC,GAC/C,IAAIwvC,GAAkB,EAEtB,IAAM,MAAQh4D,EAAS/C,KAAY86D,EAC7BE,GAAmB7kD,EAAQpT,EAAS/C,KACxC+6D,GAAkB,GAIpB,OAAOA,EAYR,SAASC,GAAmB7kD,EAAQpT,EAAS/C,GAC5C,MAAM,KAAE02B,EAAI,aAAEikC,GAAiB36D,EAEzBkuB,EAAcysC,EAAe53D,EAsCpC,SAA4C7B,GAC3C,GAA2B,IAAtBA,EAAO+J,WAAmB,CAC9B,MAAM9hB,EAAa+X,EAAOG,SAAU,GAEpC,GAAKlY,EAAW7E,GAAI,aAAgB6E,EAAW7E,GAAI,aAClD,OAAO6E,EAIT,OAAO,KA/CsC8xE,CAAmCl4D,GAChF,IAAIg4D,GAAkB,EAItB,QAAM7sC,IAONluB,EAAOkuB,YAAcA,EAGhBA,EAAY3qB,aAAc,sBAAyBmzB,IACvDvgB,EAAOtuB,aAAc,mBAAoB6uC,EAAMxI,GAC/C6sC,GAAkB,IA3Eb,SAA2Bh4D,GACjC,IAAMA,EAAQ+1C,aACb,OAAO,EAIR,MAAMoiB,GAAc5tE,MAAMiK,KAAMwL,EAAQ8H,eACtCyS,KAAMva,IAAYA,EAAQze,GAAI,cAE1BinC,EAAMxoB,EAAQ5d,SAGpB,IAAMomC,EAAIjd,WAAa4sD,EACtB,OAAO,EAGR,MACMC,EADgB5vC,EAAIhd,UACY+E,OAGtC,SAAK4nD,IAAcC,GAAmBA,EAAgBj6D,SAAW6B,GA0D5Dq4D,CAAkBltC,GAIX2sC,GAAiB1kD,EAAQ+X,KACpC6sC,GAAkB,GAjIb,SAA0B5kD,EAAQpT,GACxC,OAAMA,EAAQW,SAAU,oBACvByS,EAAO2K,SAAU,iBAAkB/d,IAE5B,GAyHFs4D,CAAiBllD,EAAQ+X,KAC7B6sC,GAAkB,GAMbA,GC1NO,MAAMO,GACpB,cAOCn3E,KAAKo3E,kBAAoB,GAW1B,QAASx4D,EAASwZ,GACjBp4B,KAAKo3E,kBAAkBn0E,KAAM,CAAE2b,UAASwZ,eAExCxZ,EAAQxb,MAAMi0E,QAAU,OAEnBj/C,GACJxZ,EAAQvZ,WAAWX,aAAc0zB,EAAYxZ,EAAQsP,aAOvD,UACCluB,KAAKo3E,kBAAkB3zE,QAAS,EAAImb,UAASwZ,iBAC5CxZ,EAAQxb,MAAMi0E,QAAU,GAEnBj/C,GACJA,EAAWj0B,WAIbnE,KAAKo3E,kBAAoB,IClCZ,MAAM,WAAwB,GAO5C,YAAa76D,EAAQmZ,GCGP,IAAiC7Z,EDF9Cjc,MAAO2c,GAQPvc,KAAK01B,KAAOA,EAQZ11B,KAAKs3E,gBCdyCz7D,EDcAU,EAAOV,OAAOzd,IAAK,WCb7D+K,MAAMgC,QAAS0Q,GACZ,CACNlG,MAAOkG,GAIHA,EAMC5d,OAAO4nC,OAAQ,CACrBlwB,MAAO,IACLkG,GAPK,CACNlG,MAAO,KDaR3V,KAAKu3E,iBAAmB,IAAIJ,GAM7B,cACC,OAAOn3E,KAAK01B,KAAK9W,QAQlB,KAAM44D,GACL,MAAMj7D,EAASvc,KAAKuc,OACdmZ,EAAO11B,KAAK01B,KACZ+hD,EAAcl7D,EAAO83D,QAAQ3+C,KAC7BlJ,EAAWkJ,EAAKlJ,SAChBkrD,EAAcD,EAAYz2E,SAAS+7C,UAIzCvwB,EAAS1uB,KAAO45E,EAAYntD,SAE5BmL,EAAK8B,SAIL,MAAMnN,EAAkBmC,EAAS5N,QAIjC5e,KAAK23E,mBAAoBnrD,EAAS1uB,KAAMusB,GAKxCrqB,KAAKk2E,aAAatnE,IAAKyb,GASvBqL,EAAKlJ,SAASztB,KAAM,aAAc6U,GAAI5T,KAAKk2E,cAI3CuB,EAAYG,cAAevtD,GAKtBmtD,GACJx3E,KAAKu3E,iBAAiBrtE,QAASstE,EAAoBx3E,KAAK4e,SAGzD5e,KAAK63E,mBACL73E,KAAK83E,eACL93E,KAAKqU,KAAM,SAMZ,UACC,MAAMqhB,EAAO11B,KAAK01B,KACZ+hD,EAAcz3E,KAAKuc,OAAO83D,QAAQ3+C,KAExC11B,KAAKu3E,iBAAiBQ,UACtBN,EAAYO,cAAetiD,EAAKlJ,SAAS1uB,MACzC43B,EAAKxb,UAELta,MAAMsa,UAQP,eACC,MAAMqC,EAASvc,KAAKuc,OACdmZ,EAAO11B,KAAK01B,KACZ+hD,EAAcl7D,EAAO83D,QAAQ3+C,KAGnCA,EAAKuiD,YAAYl5E,KAAM,YAAa6U,GAAI5T,KAAKk2E,aAAc,aAC3DxgD,EAAKuiD,YAAYC,eAAiBxiD,EAAK9W,QAElC5e,KAAKs3E,eAAea,oBACxBziD,EAAKuiD,YAAYE,kBAAoBn4E,KAAKs3E,eAAea,mBAG1DziD,EAAK0iD,QAAQC,eAAgBr4E,KAAKs3E,eAAe3hE,MAAO3V,KAAKi2E,kBE5HhD,UAAqC,OACnDqC,EAAM,uBACNC,EAAsB,mBACtBC,EAAkB,QAClBJ,EAAO,YACPK,EAAW,UACXC,IAIAF,EAAmB5pE,IAAKwpE,EAAQx5D,SAGhC25D,EAAuB9uE,IAAK,UAAW,CAAE9J,EAAMu2C,KACzCsiC,EAAmBruD,YAAciuD,EAAQlC,aAAa/rD,YACrDsuD,GACJA,IAGDL,EAAQvoD,QAERqmB,OAKFkiC,EAAQ5D,WAAW/qE,IAAK,MAAO,CAAE9J,EAAMu2C,KACjCkiC,EAAQlC,aAAa/rD,YACzBmuD,EAAOzoD,QAEF6oD,GACJA,IAGDxiC,OF4FDyiC,CAA4B,CAC3BL,OAAQb,EACRe,mBAAoBx4E,KAAKk2E,aACzBqC,uBAAwBh8D,EAAOi4D,WAC/B4D,QAAS1iD,EAAK0iD,UAShB,mBACC,MAAM77D,EAASvc,KAAKuc,OACdk7D,EAAcl7D,EAAO83D,QAAQ3+C,KAC7BgiD,EAAcD,EAAYz2E,SAAS+7C,UACnCkkB,EAAgB1kD,EAAO0kD,cAEvB2X,EAAkBr8D,EAAOV,OAAOzd,IAAK,gBAC1C6iE,GAAyD,aAAxCA,EAAcp6B,QAAQpU,eAAgCwuC,EAAc7hD,aAAc,eAE/Fw5D,GACJrC,GAAmB,CAClB7gD,KAAM+hD,EACN74D,QAAS84D,EACTnlC,KAAMqmC,EACNpC,cAAc,KGlIH,MAAM,WAAuB,GAM3C,YAAaqC,EAAe,IAC3Bj5E,MAAOi5E,EAAc,CAGpBzjE,WAAY,YAIbpV,KAAKkpB,GAAI,MAAO,CAAEpS,EAAK4e,EAAMhzB,KAC5B1C,KAAK84E,gCAAiCpjD,EAAMhzB,KAI7C1C,KAAKkpB,GAAI,SAAU,CAAEpS,EAAK4e,KACpBA,EAAK9W,SAAW5e,KAAK+4E,gBACzBrjD,EAAK9W,QAAQza,WAUfnE,KAAK+4E,eAAiB,KAOvB,UACC/4E,KAAKqK,IAAKqrB,GAAQA,EAAKxb,WAUxB,UAAW8+D,GACVh5E,KAAK+4E,eAAiBC,EAGtB,IAAM,MAAMtjD,KAAQ11B,KACnBA,KAAK84E,gCAAiCpjD,GAqCxC,YAAa1jB,GACZ,IAAMA,EAAOjQ,SAA0BiQ,EAyF7BkY,MAAOvN,GAAiB,iBAALA,GAnF5B,MAAM,IAAI,KACT,0CACA3c,MAIF,MAAO,CASN4T,GAAIqlE,IAEH,IAAM,MAAMvjD,KAAQ11B,KACnB,IAAM,MAAMk5E,KAAWlnE,EACtB0jB,EAAKnE,SAAU2nD,GAAUtlE,GAAIqlE,GAK/Bj5E,KAAKkpB,GAAI,MAAO,CAAEpS,EAAK4e,KACtB,IAAM,MAAMwjD,KAAWlnE,EACtB0jB,EAAKnE,SAAU2nD,GAAUtlE,GAAIqlE,KAK/Bj5E,KAAKkpB,GAAI,SAAU,CAAEpS,EAAK4e,KACzB,IAAM,MAAMwjD,KAAWlnE,EACtB0jB,EAAKq1C,eAAgBmO,EAASD,OAqBnC,gCAAiCvjD,EAAMhzB,GAChCgzB,EAAKyjD,YACVzjD,EAAK8B,SAGD9B,EAAK9W,SAAW5e,KAAK+4E,gBACzB/4E,KAAK+4E,eAAer0E,aAAcgxB,EAAK9W,QAAS5e,KAAK+4E,eAAejxE,SAAUpF,KCrJlE,MAAM,GAMpB,YAAak0D,GACZ34D,OAAO4nC,OAAQ7lC,KAAM,GAAW,GAAO42D,KAUvC52D,KAAKo5E,aAAc,EAiDnBp5E,KAAKq5E,YAAc,KAYpB,SACC,MAAM9mE,EAAOvS,KAAKs5E,YAAa,CAC9BC,cAAc,IAKf,OAFAv5E,KAAKo5E,aAAc,EAEZ7mE,EA0CR,MAAOA,GASN,OARAvS,KAAKq5E,YAwuCC,CACNvxE,SAAU,GACVmgB,SAAU,GACV3kB,WAAY,IAzuCZtD,KAAKs5E,YAAa,CACjB/mE,OACAinE,YAAY,EACZC,WAAYz5E,KAAKq5E,cAGX9mE,EASR,OAAQA,GACP,IAAMvS,KAAKq5E,YAMV,MAAM,IAAI,KACT,iCACA,CAAEr5E,KAAMuS,IAIVvS,KAAK05E,wBAAyBnnE,EAAMvS,KAAKq5E,aA+B1C,kBACC,SAAUnmD,EAAQ0jC,GACjB,GAAKA,EAAI9uD,SACR,IAAM,MAAM2e,KAASmwC,EAAI9uD,SACnB6xE,GAAQlzD,SACNA,EACKmzD,GAAYnzD,WAChByM,EAAQzM,IAMZyM,CAAQlzB,MAwChB,YAAampB,EAAY5X,GACxB,MAAO,CACNqC,GAAE,CAAEimE,EAAgC3oE,IAC5B,IAAI4oE,GAAmB,CAC7BC,oBAAqBF,EACrB16D,UAAW06D,EACX1wD,aAAY5X,UAASL,aAIvB8oE,GAAE,CAAE76D,EAAW86D,EAAa/oE,IACpB,IAAIgpE,GAAmB,CAC7B/wD,aAAY5X,UAAS4N,YAAW86D,cAAa/oE,cA8DjD,cAAeipE,EAAUvjB,GACxB,GAAKujB,EAASf,YAQb,MAAM,IAAI,KACT,yBACA,CAAEp5E,KAAMm6E,KAi9BZ,SAASC,EAAgBD,EAAUvjB,GAC7BA,EAAItzD,aACF62E,EAAS72E,aACd62E,EAAS72E,WAAa,IAGvB+2E,GAAwBF,EAAS72E,WAAYszD,EAAItzD,aAG7CszD,EAAI0jB,iBACFH,EAASG,iBACdH,EAASG,eAAiB,IAG3BD,GAAwBF,EAASG,eAAgB1jB,EAAI0jB,iBAGjD1jB,EAAIrkB,MACR4nC,EAAS5nC,KAAKtvC,QAAS2zD,EAAIrkB,MAG5B,GAAKqkB,EAAI9uD,UAAY8uD,EAAI9uD,SAAS/F,OAAS,CAC1C,GAAKo4E,EAASryE,SAAS/F,QAAU60D,EAAI9uD,SAAS/F,OAM7C,MAAM,IAAI,KACT,uCACAo4E,GAIF,IAAII,EAAa,EAEjB,IAAM,MAAMnjB,KAAYR,EAAI9uD,SAC3BsyE,EAAgBD,EAASryE,SAAUyyE,KAAgBnjB,IAl/BpDgjB,CAAgBD,EAAU,GAAW,GAAOvjB,KAS7C,YAAaj3D,GACZ,IAAI66E,EAUJ,GANCA,EAFI76E,EAAK4S,KAEGvS,KAAKoI,KAAOpI,KAAKuyC,KAGjBvyC,KAAKoI,IAAMpI,KAAKuyC,MAAQvyC,KAAKuyC,KAGrCioC,EAOJ,MAAM,IAAI,KACT,2BACAx6E,MAIF,OAAKA,KAAKuyC,KACFvyC,KAAKy6E,YAAa96E,GAElBK,KAAK06E,eAAgB/6E,GAU9B,eAAgBA,GACf,IAAI4S,EAAO5S,EAAK4S,KAUhB,OARMA,IACLA,EAAO5S,EAAK4S,KAAOvR,SAASooC,gBAAiBppC,KAAKpB,IAnarC,+BAmaoDoB,KAAKoI,MAGvEpI,KAAK26E,kBAAmBh7E,GACxBK,KAAK46E,uBAAwBj7E,GAC7BK,KAAK66E,gBAAiBl7E,GAEf4S,EASR,YAAa5S,GACZ,IAAI4S,EAAO5S,EAAK4S,KAoChB,OAjCKA,EACJ5S,EAAK85E,WAAWlnC,KAAOhgC,EAAK0zB,YAE5B1zB,EAAO5S,EAAK4S,KAAOvR,SAASuD,eAAgB,IAaxCu2E,GAAoB96E,KAAKuyC,MAC7BvyC,KAAK+6E,kBAAmB,CACvB9xB,OAAQjpD,KAAKuyC,KACbvvC,QAASg4E,GAAgBzoE,GACzB5S,SAUD4S,EAAK0zB,YAAcjmC,KAAKuyC,KAAKtuC,KAAM,IAG7BsO,EASR,kBAAmB5S,GAClB,IAAI8yD,EAAUwoB,EAAWC,EAAcC,EAEvC,IAAMn7E,KAAKsD,WACV,OAGD,MAAMiP,EAAO5S,EAAK4S,KACZknE,EAAa95E,EAAK85E,WAExB,IAAMhnB,KAAYzyD,KAAKsD,WAsCtB,GApCA43E,EAAe3oE,EAAK6M,aAAcqzC,GAGlCwoB,EAAYj7E,KAAKsD,WAAYmvD,GAGxBgnB,IACJA,EAAWn2E,WAAYmvD,GAAayoB,GAUrCC,EAAW,EAAUF,EAAW,KAASA,EAAW,GAAIr8E,GAAOq8E,EAAW,GAAIr8E,GAAK,KAmB9Ek8E,GAAoBG,GAAc,CAQtC,MAAMG,EAAcD,EAASF,EAAW,GAAIz8E,MAAQy8E,EAI/CxB,GAAc4B,GAAc5oB,IAChC2oB,EAAYj+D,QAAS+9D,GAGtBl7E,KAAK+6E,kBAAmB,CACvB9xB,OAAQmyB,EACRp4E,QAASs4E,GAAqB/oE,EAAMkgD,EAAU0oB,GAC9Cx7E,aAWoB,SAAZ8yD,GAAiD,iBAAnBwoB,EAAW,GAClDj7E,KAAKu7E,sBAAuBN,EAAW,GAAKt7E,IAmBvC85E,GAAcyB,GAAgBG,GAAc5oB,IAChDwoB,EAAU99D,QAAS+9D,GAGpBD,EAAYA,EAUV5wE,IAAK6F,GAAOA,GAAQA,EAAI1R,OAAiB0R,GAEzCmH,OAAQ,CAAEyhB,EAAMvN,IAAUuN,EAAKr2B,OAAQ8oB,GAAQ,IAE/ClU,OAAQmkE,GAAmB,IAEvBC,GAASR,IACd1oE,EAAKmpE,eAAgBP,EAAQ1oB,EAAUwoB,IAiC3C,sBAAuBx7D,EAAQ9f,GAC9B,MAAM4S,EAAO5S,EAAK4S,KAElB,IAAM,MAAMopE,KAAal8D,EAAS,CACjC,MAAMm8D,EAAan8D,EAAQk8D,GAQtBb,GAAoBc,GACxB57E,KAAK+6E,kBAAmB,CACvB9xB,OAAQ,CAAE2yB,GACV54E,QAAS64E,GAAiBtpE,EAAMopE,GAChCh8E,SAWD4S,EAAKnP,MAAOu4E,GAAcC,GAW7B,uBAAwBj8E,GACvB,MAAM4S,EAAO5S,EAAK4S,KACZ8mB,EAAY15B,EAAK45E,aAAev4E,SAASkoC,yBAA2B32B,EACpEinE,EAAa75E,EAAK65E,WACxB,IAAIe,EAAa,EAEjB,IAAM,MAAM9zD,KAASzmB,KAAK8H,SACzB,GAAKg0E,GAAkBr1D,IACtB,IAAM+yD,EAAa,CAClB/yD,EAAMs1D,UAAWxpE,GAGjB,IAAM,MAAMmjB,KAAQjP,EACnB4S,EAAUz1B,YAAa8xB,EAAK9W,eAGxB,GAAK+6D,GAAQlzD,GACb+yD,IACC/yD,EAAM0yD,YACX1yD,EAAM+Q,SAGP6B,EAAUz1B,YAAa6iB,EAAM7H,eAExB,GAAKmiB,GAAQta,GACnB4S,EAAUz1B,YAAa6iB,QAEvB,GAAK+yD,EAAa,CACjB,MACMwC,EAktBH,CACNl0E,SAAU,GACVmgB,SAAU,GACV3kB,WAAY,IAttBU3D,EAAK85E,WAGb3xE,SAAS7E,KAAM+4E,GAE1Bv1D,EAAM6yD,YAAa,CAClB/mE,KAAM8mB,EAAU70B,WAAY+1E,KAC5Bf,YAAY,EACZC,WAAYuC,SAGb3iD,EAAUz1B,YAAa6iB,EAAM+Q,UAK3B73B,EAAK45E,cACThnE,EAAK3O,YAAay1B,GAWpB,gBAAiB15B,GAChB,GAAMK,KAAKs6E,eAIX,IAAM,MAAMx7E,KAAOkB,KAAKs6E,eAAiB,CACxC,MAAM2B,EAAiBj8E,KAAKs6E,eAAgBx7E,GAAMuL,IAAK6xE,IACtD,MAAQC,EAAYC,GAAgBt9E,EAAIyQ,MAAO,KAE/C,OAAO2sE,EAAWG,yBAA0BF,EAAYC,EAAaz8E,KAGjEA,EAAK85E,YACT95E,EAAK85E,WAAWxxD,SAAShlB,KAAMg5E,IAkBlC,mBAAmB,OAAEhzB,EAAM,QAAEjmD,EAAO,KAAErD,IACrC,MAAM85E,EAAa95E,EAAK85E,WAGxB6C,GAAsBrzB,EAAQjmD,EAASrD,GAEvC,MAAMs8E,EAAiBhzB,EAErBjlD,OAAQ3B,IAASo5E,GAASp5E,IAE1B2B,OAAQ3B,GAAQA,EAAK8mB,YAIrB9e,IAAKkyE,GAAmBA,EAAgBC,0BAA2BvzB,EAAQjmD,EAASrD,IAEjF85E,GACJA,EAAWxxD,SAAShlB,KAAMg5E,GAa5B,wBAAyB1pE,EAAMknE,GAC9B,IAAM,MAAM5yE,KAAW4yE,EAAWxxD,SAWjC,IAAM,MAAMw0D,KAAiB51E,EAC5B41E,IAIF,GAAKhD,EAAWlnC,KACfhgC,EAAK0zB,YAAcwzC,EAAWlnC,SAD/B,CAMA,IAAM,MAAMkgB,KAAYgnB,EAAWn2E,WAAa,CAC/C,MAAM23E,EAAYxB,EAAWn2E,WAAYmvD,GAGtB,OAAdwoB,EACJ1oE,EAAK3N,gBAAiB6tD,GAEtBlgD,EAAK7O,aAAc+uD,EAAUwoB,GAI/B,IAAM,IAAI19E,EAAI,EAAGA,EAAIk8E,EAAW3xE,SAAS/F,SAAUxE,EAClDyC,KAAK05E,wBAAyBnnE,EAAK/N,WAAYjH,GAAKk8E,EAAW3xE,SAAUvK,MAK5EiX,GAAK,GAAU,IAOR,MAAMkoE,GAMZ,YAAa9lB,GACZ34D,OAAO4nC,OAAQ7lC,KAAM42D,GA0CtB,SAAUrkD,GACT,MAAM/T,EAAQwB,KAAKmpB,WAAYnpB,KAAKmf,WAEpC,OAAOnf,KAAKkR,SAAWlR,KAAKkR,SAAU1S,EAAO+T,GAAS/T,EAavD,0BAA2ByqD,EAAQjmD,EAASrD,GAC3C,MAAMuR,EAAW,IAAMorE,GAAsBrzB,EAAQjmD,EAASrD,GAK9D,OAHAK,KAAKuR,QAAQJ,SAAUnR,KAAKmpB,WAAY,UAAYnpB,KAAKmf,UAAWjO,GAG7D,KACNlR,KAAKuR,QAAQD,cAAetR,KAAKmpB,WAAY,UAAYnpB,KAAKmf,UAAWjO,KAerE,MAAM4oE,WAA0B4C,GAUtC,yBAA0BP,EAAYC,EAAaz8E,GAClD,MAAMuR,EAAW,CAAE4F,EAAKq4B,KACjBitC,IAAejtC,EAAO/tC,OAAOouC,QAAS4sC,KACH,mBAA5Bp8E,KAAK+5E,oBAChB/5E,KAAK+5E,oBAAqB5qC,GAE1BnvC,KAAKmpB,WAAW9U,KAAMrU,KAAK+5E,oBAAqB5qC,KAQnD,OAHAnvC,KAAKuR,QAAQJ,SAAUxR,EAAK4S,KAAM4pE,EAAYjrE,GAGvC,KACNlR,KAAKuR,QAAQD,cAAe3R,EAAK4S,KAAM4pE,EAAYjrE,KAW/C,MAAMgpE,WAA0BwC,GAItC,SAAUnqE,GAGT,OAAOkpE,GAFO77E,MAAM+8E,SAAUpqE,MAEMvS,KAAKi6E,cAAe,IAgB1D,SAASa,GAAoB7xB,GAC5B,QAAMA,IAWDA,EAAOzqD,QACXyqD,EAASA,EAAOzqD,OAGZ2K,MAAMgC,QAAS89C,GACZA,EAAO9vB,KAAM2hD,IACT7xB,aAAkByzB,IAgC/B,SAASJ,GAAsBrzB,EAAQjmD,GAAS,KAAEuP,IACjD,IAAI/T,EAnBL,SAA8ByqD,EAAQ12C,GACrC,OAAO02C,EAAO5+C,IAAK6xE,GAEbA,aAAsBQ,GACnBR,EAAWS,SAAUpqE,GAItB2pE,GAWIU,CAAqB3zB,EAAQ12C,GAOxC/T,EADqB,GAAjByqD,EAAOlnD,QAAeknD,EAAQ,aAAeixB,GACzC17E,EAAO,GAEPA,EAAM6Y,OAAQmkE,GAAmB,IAGrCC,GAASj9E,GACbwE,EAAQmB,SAERnB,EAAQyG,IAAKjL,GAUf,SAASw8E,GAAgBzoE,GACxB,MAAO,CACN,IAAK/T,GACJ+T,EAAK0zB,YAAcznC,GAGpB,SACC+T,EAAK0zB,YAAc,KAatB,SAASq1C,GAAqB1G,EAAIniB,EAAU7zD,GAC3C,MAAO,CACN,IAAKJ,GACJo2E,EAAG8G,eAAgB98E,EAAI6zD,EAAUj0D,IAGlC,SACCo2E,EAAGiI,kBAAmBj+E,EAAI6zD,KAY7B,SAASopB,GAAiBjH,EAAI+G,GAC7B,MAAO,CACN,IAAKn9E,GACJo2E,EAAGxxE,MAAOu4E,GAAcn9E,GAGzB,SACCo2E,EAAGxxE,MAAOu4E,GAAc,OAS3B,SAAS,GAAO/kB,GAkBf,OAjBc,GAAeA,EAAKp4D,IAYjC,GAAKA,IAAWA,aAAiBk+E,IAAmB9C,GAAYp7E,IAAWm7E,GAAQn7E,IAAWs9E,GAAkBt9E,IAC/G,OAAOA,IAiBV,SAAS,GAAWo4D,GAcnB,GAbmB,iBAAPA,EACXA,EA0GF,SAAuCA,GACtC,MAAO,CACNrkB,KAAM,CAAEqkB,IA5GFkmB,CAA8BlmB,GACzBA,EAAIrkB,MA8HjB,SAAkCqkB,GACjCA,EAAIrkB,KAAOl4B,GAASu8C,EAAIrkB,MA9HvBwqC,CAAyBnmB,GAGrBA,EAAI1tC,KACR0tC,EAAI0jB,eAkFN,SAA6B0C,GAC5B,IAAM,MAAMx/E,KAAKw/E,EAChBC,GAAUD,EAAWx/E,GAGtB,OAAOw/E,EAvFeE,CAAoBtmB,EAAI1tC,WAGtC0tC,EAAI1tC,KAGN0tC,EAAIrkB,KAAO,CACXqkB,EAAItzD,YA+CX,SAA8BA,GAC7B,IAAM,MAAMqZ,KAAKrZ,EACXA,EAAYqZ,GAAIne,QACpB8E,EAAYqZ,GAAIne,MAAQ6b,GAAS/W,EAAYqZ,GAAIne,QAGlDy+E,GAAU35E,EAAYqZ,GApDrBwgE,CAAqBvmB,EAAItzD,YAG1B,MAAMwE,EAAW,GAEjB,GAAK8uD,EAAI9uD,SACR,GAAKg0E,GAAkBllB,EAAI9uD,UAC1BA,EAAS7E,KAAM2zD,EAAI9uD,eAEnB,IAAM,MAAM2e,KAASmwC,EAAI9uD,SACnB8xE,GAAYnzD,IAAWkzD,GAAQlzD,IAAWsa,GAAQta,GACtD3e,EAAS7E,KAAMwjB,GAEf3e,EAAS7E,KAAM,IAAI,GAAUwjB,IAMjCmwC,EAAI9uD,SAAWA,EAGhB,OAAO8uD,EA+GR,SAASqmB,GAAUt6E,EAAK7D,GACvB6D,EAAK7D,GAAQub,GAAS1X,EAAK7D,IAS5B,SAAS08E,GAAmB1iD,EAAMskD,GACjC,OAAK3B,GAAS2B,GACNtkD,EACI2iD,GAAS3iD,GACbskD,EAEA,GAAItkD,KAAUskD,IAkBvB,SAAS/C,GAAwB13E,EAAK06E,GACrC,IAAM,MAAM1gE,KAAK0gE,EACX16E,EAAKga,GACTha,EAAKga,GAAI1Z,QAASo6E,EAAK1gE,IAEvBha,EAAKga,GAAM0gE,EAAK1gE,GA0DnB,SAAS8+D,GAASj9E,GACjB,OAAQA,GAAmB,IAAVA,EAOlB,SAASm7E,GAAQt3E,GAChB,OAAOA,aAAgB,GAOxB,SAASu3E,GAAYv3E,GACpB,OAAOA,aAAgB,GAOxB,SAASy5E,GAAkBz5E,GAC1B,OAAOA,aAAgB,GAoBxB,SAASg5E,GAAc5oB,GACtB,MAAmB,SAAZA,GAAmC,SAAZA,E,MC11ChB,MAAM,GAQpB,YAAax2C,GAgCZjc,KAAK4e,QAAU,KAQf5e,KAAKm5E,YAAa,EAUlBn5E,KAAKic,OAASA,EAWdjc,KAAKvB,EAAIwd,GAAUA,EAAOxd,EAQ1BuB,KAAKs9E,iBAAmB,IAAI,GAS5Bt9E,KAAKu9E,iBAAmBv9E,KAAKw9E,mBAG7Bx9E,KAAKs9E,iBAAiBp0D,GAAI,MAAO,CAAEpS,EAAK2mE,KACvCA,EAAWxhE,OAASA,IAkBrBjc,KAAKm2D,SAAU,UA8ChB,mBACC,OAAKn2D,KAAK09E,cACF19E,KAAK09E,cAGJ19E,KAAK09E,cAAgB,GAAS3+E,KAAMiB,KAAMA,MAgCpD,iBAAkB29E,GACjB,MAAMF,EAAa,IAAI,GAAgBE,GAIvC,OAFA39E,KAAKs9E,iBAAiB1uE,IAAK6uE,GAEpBA,EA8DR,cAAe31E,GACRwM,GAAYxM,KACjBA,EAAW,CAAEA,IAGd,IAAM,MAAM2e,KAAS3e,EACpB9H,KAAKu9E,iBAAiB3uE,IAAK6X,GAY7B,gBAAiB3e,GACVwM,GAAYxM,KACjBA,EAAW,CAAEA,IAGd,IAAM,MAAM2e,KAAS3e,EACpB9H,KAAKu9E,iBAAiBp5E,OAAQsiB,GAahC,YAAa8vC,GACZv2D,KAAKm6E,SAAW,IAAI,GAAU5jB,GAgB/B,eAAgBA,GACf,GAASx/B,OAAQ/2B,KAAKm6E,SAAU5jB,GA4DjC,SACC,GAAKv2D,KAAKm5E,WAMT,MAAM,IAAI,KAAe,kCAAmCn5E,MAIxDA,KAAKm6E,WACTn6E,KAAK4e,QAAU5e,KAAKm6E,SAAS3iD,SAG7Bx3B,KAAK49E,cAAe59E,KAAKm6E,SAAS0D,aAGnC79E,KAAKm5E,YAAa,EAWnB,UACCn5E,KAAKsR,gBAELtR,KAAKs9E,iBAAiBjzE,IAAKzM,GAAKA,EAAEsc,WAG7Bla,KAAKm6E,UAAYn6E,KAAKm6E,SAASd,aACnCr5E,KAAKm6E,SAAS7kB,OAAQt1D,KAAK4e,UAc9BpK,GAAK,GAAM,IACXA,GAAK,GAAM,ICheI,OALf,SAAkBhW,GAChB,MAAuB,iBAATA,IACV,GAAQA,IAAU,EAAaA,IArBrB,mBAqB+B,EAAWA,ICQ3C,MAAM,WAAuB,GAO3C,YAAayd,EAAQ48D,EAAe,IACnCj5E,MAAOi5E,GAQP74E,KAAKic,OAASA,EAOf,cAOCjc,KAAK89E,yBAA2B,IAAI,GAAU,CAC7C11E,IAAK,MACL9E,WAAY,CACXy6E,MAAO,CACN,KACA,eACA,UACA,sBAEDp9C,IAAK3gC,KAAKic,OAAOX,qBAElBxT,SAAU9H,OACPw3B,SAEJ,IAAI+E,EAAUv7B,SAASM,cAAe,oBAEhCi7B,IACLA,ECtDY,SAAwB6K,EAAKtpC,EAAMwF,EAAa,GAAIwE,EAAW,IAC7E,MAAMk2E,EAAY16E,GAAcA,EAAW26E,MACrCr/D,EAAUo/D,EAAY52C,EAAIgC,gBAAiB40C,EAAWlgF,GAASspC,EAAI/jC,cAAevF,GAExF,IAAM,MAAMgB,KAAOwE,EAClBsb,EAAQlb,aAAc5E,EAAKwE,EAAYxE,KAGnC,GAAUgJ,IAAewM,GAAYxM,KACzCA,EAAW,CAAEA,IAGd,IAAM,IAAI2e,KAAS3e,EACb,GAAU2e,KACdA,EAAQ2gB,EAAI7iC,eAAgBkiB,IAG7B7H,EAAQhb,YAAa6iB,GAGtB,OAAO7H,EDkCKvb,CAAerC,SAAU,MAAO,CAAE+8E,MAAO,oBACnD/8E,SAASq5C,KAAKz2C,YAAa24B,IAG5BA,EAAQ34B,YAAa5D,KAAK89E,0BAO3B,gBACCl+E,MAAMsa,UAEDla,KAAK89E,0BACT99E,KAAK89E,yBAAyB35E,SAG/B,MAAMo4B,EAAUv7B,SAASM,cAAe,oBAEnCi7B,GAAwC,GAA7BA,EAAQ2hD,mBACvB3hD,EAAQp4B,U,MEnFI,MAAM,WAAqB,GAMzC,YAAa8X,GACZrc,MAAOqc,GASPjc,KAAKq6C,KAAO,IAAI,GAAgBp+B,GAMjC,SACCrc,MAAM43B,SAENx3B,KAAKq6C,KAAK8jC,cAMX,UAGC,OAFAn+E,KAAKq6C,KAAK+jC,gBAEHx+E,MAAMsa,W,MClCA,MAAM,WAAkB,GAItC,YAAa+B,GACZrc,MAAOqc,GAQPjc,KAAKyJ,IAAK,QAQVzJ,KAAKyJ,IAAK,OAQVzJ,KAAKsC,GAAK,oBAAqB,KAE/B,MAAMvD,EAAOiB,KAAKq+E,aAElBr+E,KAAKs+E,YAAa,CACjBl2E,IAAK,QACL9E,WAAY,CACXy6E,MAAO,CACN,KACA,YAEDz7E,GAAItC,KAAKsC,GACT+8D,IAAKtgE,EAAK6U,GAAI,QAEf9L,SAAU,CACT,CACCyqC,KAAMxzC,EAAK6U,GAAI,aC9CL,MAAM,WAA0B,GAM9C,YAAaqI,GACZrc,MAAOqc,GASPjc,KAAK8lC,IAAM9lC,KAAKw9E,mBAShBx9E,KAAKq+D,KAAOr+D,KAAKw9E,mBASjBx9E,KAAKu+E,gBAAkBv+E,KAAKw+E,oBAE5Bx+E,KAAKs+E,YAAa,CACjBl2E,IAAK,MAEL9E,WAAY,CACXy6E,MAAO,CACN,KACA,WACA,YACA,sBAEDU,KAAM,cACN99C,IAAK1kB,EAAOX,oBACZojE,KAAMziE,EAAOb,WACb,kBAAmBpb,KAAKu+E,gBAAgBj8E,IAGzCwF,SAAU,CACT9H,KAAKu+E,gBACL,CACCn2E,IAAK,MACL9E,WAAY,CACXy6E,MAAO,CACN,KACA,iBACA,gBAEDU,KAAM,gBAEP32E,SAAU9H,KAAK8lC,KAEhB,CACC19B,IAAK,MACL9E,WAAY,CACXy6E,MAAO,CACN,KACA,mBAEDU,KAAM,gBAEP32E,SAAU9H,KAAKq+D,SAYnB,oBACC,MAAM5/D,EAAIuB,KAAKvB,EACTkgF,EAAa,IAAI,GAUvB,OARAA,EAAWpsC,KAAO9zC,EAAG,oBAErBkgF,EAAWvE,eAAgB,CAC1B92E,WAAY,CACXy6E,MAAO,oBAIFY,GCrGM,MAAM,WAAuB,GAS3C,YAAa1iE,EAAQw7D,EAAaptD,GACjCzqB,MAAOqc,GAEPjc,KAAKs+E,YAAa,CACjBl2E,IAAK,MACL9E,WAAY,CACXy6E,MAAO,CACN,KACA,aACA,sBACA,sBAEDW,KAAMziE,EAAOZ,gBACbslB,IAAK1kB,EAAOT,4BASdxb,KAAKlC,KAAO,KAQZkC,KAAKyJ,IAAK,aAAa,GAQvBzJ,KAAK4+E,iBAAmBv0D,EASxBrqB,KAAK6+E,sBAAwB7+E,KAAK4+E,iBAalC5+E,KAAK8+E,aAAerH,EAOrB,SACC73E,MAAM43B,SAEDx3B,KAAK6+E,oBACT7+E,KAAKm6E,SAAS9mE,MAAOrT,KAAK4e,QAAU5e,KAAK4+E,kBAEzC5+E,KAAK4+E,iBAAmB5+E,KAAK4e,QAG9B5e,KAAKkpB,GAAI,mBAAoB,IAAMlpB,KAAK++E,2BACxC/+E,KAAK++E,0BAMN,UACM/+E,KAAK6+E,qBACT7+E,KAAKm6E,SAAS7kB,OAAQt1D,KAAK4+E,kBAG5Bh/E,MAAMsa,UASP,0BACC,MAAMu9D,EAAcz3E,KAAK8+E,aAQzB,SAAS35E,EAAQuwB,GAChB+hD,EAAYr6B,OAAQprB,IACnB,MAAM8qB,EAAW26B,EAAYz2E,SAAS+7C,QAASrnB,EAAK53B,MAEpDk0B,EAAO2K,SAAUjH,EAAKvL,UAAY,aAAe,aAAc2yB,GAC/D9qB,EAAO6K,YAAanH,EAAKvL,UAAY,aAAe,aAAc2yB,KAX/D26B,EAAYl6B,sBAoBjB,SAASyhC,EAAmBtpD,GAC3B+hD,EAAYtD,KAAM,+BAAgC,CAAEr9D,EAAKhZ,EAAMU,KACxDA,EAGLwgF,EAAmBtpD,GAFnBvwB,EAAQuwB,KAtBVspD,CAAmBh/E,MAEnBmF,EAAQnF,OChHI,MAAM,WAA6B,GAUjD,YAAaic,EAAQw7D,EAAaptD,GACjCzqB,MAAOqc,EAAQw7D,EAAaptD,GAE5BrqB,KAAKo6E,eAAgB,CACpB92E,WAAY,CACXm7E,KAAM,UACNV,MAAO,gCAQV,SACCn+E,MAAM43B,SAEN,MAAMigD,EAAcz3E,KAAK8+E,aACnBrgF,EAAIuB,KAAKvB,EAEfg5E,EAAYr6B,OAAQprB,IACnB,MAAM8qB,EAAW26B,EAAYz2E,SAAS+7C,QAAS/8C,KAAKlC,MAEpDk0B,EAAOtuB,aAAc,aAAcjF,EAAG,uBAAwBuB,KAAKlC,MAAQg/C,MCjC/D,SAASmiC,GAAQ9P,GAS/B,OAAO3wE,GAASA,EAAQ2wE,E,MCTzB,MAAM+P,GAAOD,GAAQ,MAKN,MAAM,WAAwB,GAI5C,YAAahjE,GACZrc,MAAOqc,GAEP,MAAMld,EAAOiB,KAAKq+E,aASlBr+E,KAAKyJ,IAAK,YAAY,GAStBzJ,KAAKyJ,IAAK,YAAY,GAatBzJ,KAAKyJ,IAAK,iBAAkB,MAY5BzJ,KAAKyJ,IAAK,sBAAuB,IAgBjCzJ,KAAKyJ,IAAK,oBAAqB,GAU/BzJ,KAAKyJ,IAAK,cAAe,MAWzBzJ,KAAKyJ,IAAK,yBAAyB,GAYnCzJ,KAAKyJ,IAAK,yBAAyB,GAQnCzJ,KAAKkH,QAAUlH,KAAKw9E,mBAwBpBx9E,KAAKm/E,yBAA2B,IAAI,GAAU,CAC7C/2E,IAAK,MACL9E,WAAY,CACXy6E,MAAO,CACN,KACA,gCAED36E,MAAO,CACNi0E,QAASt4E,EAAK6U,GAAI,WAAYwrE,GAAYA,EAAW,QAAU,QAC/D1mC,OAAQ35C,EAAK6U,GAAI,WAAYwrE,GACrBA,EAAWF,GAAMl/E,KAAKq/E,WAAW3mC,QAAW,UAInDlhB,SASJx3B,KAAKs/E,cAAgB,IAAI,GAAU,CAClCl3E,IAAK,MAEL9E,WAAY,CACXy6E,MAAO,CACN,KACA,2BAEAh/E,EAAKi7E,GAAI,WAAY,mCACrBj7E,EAAKi7E,GAAI,wBAAyB,iDAEnC52E,MAAO,CACN4iC,MAAOjnC,EAAK6U,GAAI,WAAYwrE,GACpBA,EAAWF,GAAMl/E,KAAKm/E,yBAAyB5mC,wBAAwBvS,OAAU,MAGzFF,IAAK/mC,EAAK6U,GAAI,wBAAyB2rE,GAC/BA,EAAwBL,GAAMl/E,KAAKm4E,mBAAsB,MAGjEvgC,OAAQ74C,EAAK6U,GAAI,wBAAyB4rE,GAClCA,EAAwBN,GAAMl/E,KAAKy/E,qBAAwB,MAGnEC,WAAY3gF,EAAK6U,GAAI,iBAIvB9L,SAAU9H,KAAKkH,UACZswB,SAEJx3B,KAAKs+E,YAAa,CACjBl2E,IAAK,MACL9E,WAAY,CACXy6E,MAAO,CACN,KACA,oBAGFj2E,SAAU,CACT9H,KAAKm/E,yBACLn/E,KAAKs/E,iBAQR,SACC1/E,MAAM43B,SAGNx3B,KAAK2/E,yBAGL3/E,KAAKmR,SAAUpK,GAAO5J,OAAQ,SAAU,KACvC6C,KAAK2/E,2BAIN3/E,KAAKmR,SAAUnR,KAAM,kBAAmB,KACvCA,KAAK2/E,2BAUP,yBACC,MAAMC,EAAY5/E,KAAKq/E,WAAar/E,KAAKs/E,cAAc/mC,wBACvD,IAAIsnC,EAEE7/E,KAAKk4E,gBAGV2H,EAAc7/E,KAAK8/E,aAAe9/E,KAAKk4E,eAAe3/B,wBAGtDv4C,KAAKo/E,SAAWp/E,KAAK+/E,UAEpBF,EAAY/5C,IAAM9lC,KAAKm4E,mBAKvBn4E,KAAKq/E,WAAW3mC,OAAS14C,KAAKy/E,oBAAsBI,EAAYnnC,QAZjE14C,KAAKo/E,UAAW,EAiBZp/E,KAAKo/E,UACTp/E,KAAKw/E,sBACJK,EAAYjoC,OAASgoC,EAAUlnC,OAAS14C,KAAKy/E,oBAAsBz/E,KAAKm4E,kBACzEn4E,KAAKu/E,uBAAyBv/E,KAAKw/E,yBAA2Bx/E,KAAKm4E,kBACnEn4E,KAAKggF,YAAchgF,KAAKw/E,sBAAwB,KAAON,IAAOn4E,GAAO5J,OAAOmuC,WAI5EtrC,KAAKw/E,uBAAwB,EAC7Bx/E,KAAKu/E,uBAAwB,EAC7Bv/E,KAAKggF,YAAc,OC9NP,MAAMC,GAUpB,YAAa/9E,GA4CZ,GA3CAjE,OAAO4nC,OAAQ7lC,KAAMkC,GA2ChBA,EAAQ0gC,SAAW1gC,EAAQg+E,iBAC/B,IAAM,MAAMl3D,KAAc9mB,EAAQ0gC,QAAU,CAC3C,IAAIA,EAAU1gC,EAAQ0gC,QAAS5Z,GAER,iBAAX4Z,IACXA,EAAU,CAAEA,IAGb,IAAM,MAAMhO,KAAagO,EACxB1gC,EAAQg+E,iBAAiBz2E,IAAKmrB,EAAW,CAAEj1B,EAAMu2C,KAChDl2C,KAAMgpB,KACNktB,OAcL,YACC,OAAOl2C,KAAKmgF,WAAW/pE,KAAMgqE,KAAiB,KAU/C,WACC,OAAOpgF,KAAKmgF,WAAWn8E,OAAQo8E,IAAc34E,OAAQ,GAAK,IAAO,KAUlE,WACC,OAAOzH,KAAKqgF,kBAAmB,GAUhC,eACC,OAAOrgF,KAAKqgF,mBAAoB,GAUjC,cACC,IAAI39E,EAAQ,KAGZ,OAA0C,OAArC1C,KAAKk2E,aAAaF,eACf,MAGRh2E,KAAKmgF,WAAW/pE,KAAM,CAAEsf,EAAM4qD,KAC7B,MAAMC,EAAU7qD,EAAK9W,UAAY5e,KAAKk2E,aAAaF,eAMnD,OAJKuK,IACJ79E,EAAQ49E,GAGFC,IAGD79E,GAMR,aACC1C,KAAK81E,OAAQ91E,KAAKovB,OAMnB,YACCpvB,KAAK81E,OAAQ91E,KAAKqvB,MAMnB,YACCrvB,KAAK81E,OAAQ91E,KAAKurB,MAMnB,gBACCvrB,KAAK81E,OAAQ91E,KAAKwgF,UASnB,OAAQ9qD,GACFA,GACJA,EAAK7F,QAaP,kBAAmBmoC,GAElB,MAAM99B,EAAUl6B,KAAKk6B,QACfumD,EAAmBzgF,KAAKmgF,WAAWp+E,OAEzC,IAAM0+E,EACL,OAAO,KAKR,GAAiB,OAAZvmD,EACJ,OAAOl6B,KAAe,IAATg4D,EAAa,QAAU,QAIrC,IAAIt1D,GAAUw3B,EAAUumD,EAAmBzoB,GAASyoB,EAEpD,EAAG,CACF,MAAM/qD,EAAO11B,KAAKmgF,WAAW/hF,IAAKsE,GAGlC,GAAK09E,GAAa1qD,GACjB,OAAOA,EAIRhzB,GAAUA,EAAQ+9E,EAAmBzoB,GAASyoB,QACrC/9E,IAAUw3B,GAEpB,OAAO,MAST,SAASkmD,GAAa1qD,GACrB,SAAWA,EAAK7F,OAAmE,QAA1D9oB,GAAO5J,OAAOq6C,iBAAkB9hB,EAAK9W,SAAUy4D,SClR1D,MAAM,WAA6B,GAIjD,YAAap7D,GACZrc,MAAOqc,GAEPjc,KAAKs+E,YAAa,CACjBl2E,IAAK,OACL9E,WAAY,CACXy6E,MAAO,CACN,KACA,6BCZU,MAAM,WAA6B,GAIjD,YAAa9hE,GACZrc,MAAOqc,GAEPjc,KAAKs+E,YAAa,CACjBl2E,IAAK,OACL9E,WAAY,CACXy6E,MAAO,CACN,KACA,8BCKU,MAAM,GAUpB,YAAan/D,EAAS1N,GAGf,GAAewvE,mBACpB,GAAeC,kBAUhB3gF,KAAK4gF,SAAWhiE,EAShB5e,KAAK6gF,UAAY3vE,EAEjB,GAAe4vE,oBAAqBliE,EAAS1N,GAC7C,GAAewvE,kBAAkB3uC,QAASnzB,GAM3C,UACC,GAAemiE,uBAAwB/gF,KAAK4gF,SAAU5gF,KAAK6gF,WAW5D,2BAA4BjiE,EAAS1N,GAC9B,GAAe8vE,oBACpB,GAAeA,kBAAoB,IAAIltE,KAGxC,IAAIhC,EAAY,GAAekvE,kBAAkB5iF,IAAKwgB,GAEhD9M,IACLA,EAAY,IAAIuG,IAChB,GAAe2oE,kBAAkBv3E,IAAKmV,EAAS9M,IAGhDA,EAAUlD,IAAKsC,GAYhB,8BAA+B0N,EAAS1N,GACvC,MAAMY,EAAY,GAAemvE,qBAAsBriE,GAIlD9M,IACJA,EAAUiC,OAAQ7C,GAGZY,EAAU9I,OACf,GAAeg4E,kBAAkBjtE,OAAQ6K,GACzC,GAAe8hE,kBAAkBQ,UAAWtiE,KAIzC,GAAeoiE,oBAAsB,GAAeA,kBAAkBh4E,OAC1E,GAAe03E,kBAAoB,KACnC,GAAeM,kBAAoB,MAYrC,4BAA6BpiE,GAC5B,OAAM,GAAeoiE,kBAId,GAAeA,kBAAkB5iF,IAAKwgB,GAHrC,KAaT,yBACC,IAAIuiE,EAOHA,EAD4C,mBAAjCp6E,GAAO5J,OAAOikF,eACHr6E,GAAO5J,OAAOikF,eAEd,GAGvB,GAAeV,kBAAoB,IAAIS,EAAqB73E,IAC3D,IAAM,MAAME,KAASF,EAAU,CAC9B,MAAMwI,EAAY,GAAemvE,qBAAsBz3E,EAAMpI,QAE7D,GAAK0Q,EACJ,IAAM,MAAMZ,KAAYY,EACvBZ,EAAU1H,OAiBhB,GAAek3E,kBAAoB,KAWnC,GAAeM,kBAAoB,KAQnC,MAAM,GAaL,YAAa9vE,GAQZlR,KAAK6gF,UAAY3vE,EASjBlR,KAAK41E,UAAY,IAAIv9D,IASrBrY,KAAKqhF,eAAiB,IAAIvtE,IAU1B9T,KAAKshF,sBAAwB,KAW9B,QAAS1iE,GACR5e,KAAK41E,UAAUhnE,IAAKgQ,GAEpB5e,KAAKuhF,uCAEwB,IAAxBvhF,KAAK41E,UAAU5sE,MACnBhJ,KAAKwhF,sBAYP,UAAW5iE,GACV5e,KAAK41E,UAAU7hE,OAAQ6K,GACvB5e,KAAKqhF,eAAettE,OAAQ6K,GAEtB5e,KAAK41E,UAAU5sE,MACpBhJ,KAAKyhF,qBAWP,sBACC,MAAMC,EAAgB,KACrB1hF,KAAKuhF,uCACLvhF,KAAKshF,sBAAwB9rC,WAAYksC,EAnSd,MAsS5B1hF,KAAKmR,SAAUpK,GAAO5J,OAAQ,SAAU,KACvC6C,KAAKuhF,yCAGNvhF,KAAKshF,sBAAwB9rC,WAAYksC,EA1Sb,KAkT7B,qBACCzrC,aAAcj2C,KAAKshF,uBACnBthF,KAAKsR,gBACLtR,KAAKqhF,eAAe93E,QASrB,uCACC,MAAMD,EAAU,GAEhB,IAAM,MAAMsV,KAAW5e,KAAK41E,UACtB51E,KAAK2hF,gBAAiB/iE,IAC1BtV,EAAQrG,KAAM,CACb7B,OAAQwd,EACRgjE,YAAa5hF,KAAKqhF,eAAejjF,IAAKwgB,KAKpCtV,EAAQvH,QACZ/B,KAAK6gF,UAAWv3E,GAYlB,gBAAiBsV,GAChB,IAAMA,EAAQkX,cAAcukB,KAAKlT,SAAUvoB,GAC1C,OAAO,EAGR,MAAMijE,EAAc,IAAI,GAAMjjE,GACxBkjE,EAAe9hF,KAAKqhF,eAAejjF,IAAKwgB,GAIxC2rD,GAAcuX,IAAiBA,EAAax1D,QAASu1D,GAI3D,OAFA7hF,KAAKqhF,eAAe53E,IAAKmV,EAASijE,GAE3BtX,GAIT/1D,GAAK,GAAwB,ICvWd,MAAM,WAA0B,GAI9C,YAAayH,GACZrc,MAAOqc,GAEP,MAAMld,EAAOiB,KAAKq+E,aAQlBr+E,KAAKyJ,IAAK,aAAa,GAYvBzJ,KAAKyJ,IAAK,WAAY,MAYtBzJ,KAAK8H,SAAW9H,KAAKw9E,mBAErBx9E,KAAKs+E,YAAa,CACjBl2E,IAAK,MAEL9E,WAAY,CACXy6E,MAAO,CACN,KACA,WACA,qBACAh/E,EAAK6U,GAAI,WAAYpV,GAAS,sBAAuBA,GACrDO,EAAKi7E,GAAI,YAAa,gCAIxBlyE,SAAU9H,KAAK8H,SAEfohB,GAAI,CAGH64D,YAAahjF,EAAK6U,GAAIkD,GAAOA,EAAI88B,qBAUpC,QACM5zC,KAAK8H,SAAS/F,QAClB/B,KAAK8H,SAASsnB,MAAMS,QAStB,YACC,GAAK7vB,KAAK8H,SAAS/F,OAAS,CAC3B,MAAMslB,EAAYrnB,KAAK8H,SAASunB,KAEI,mBAAxBhI,EAAU26D,UACrB36D,EAAU26D,YAEV36D,EAAUwI,U,MC1BP,SAASoyD,IAAoB,QAAErjE,EAAO,OAAExd,EAAM,UAAE8gF,EAAS,QAAEC,EAAO,cAAEC,IAGrE,EAAYhhF,KAChBA,EAASA,KAKL,EAAY+gF,KAChBA,EAAUA,KAGX,MAAME,EC3EQ,SAAgCzjE,GAC9C,OAAMA,GAAYA,EAAQvZ,WAIrBuZ,EAAQ0jE,eAAiBv7E,GAAO/F,SAASq5C,KACtC,KAGDz7B,EAAQ0jE,aAPP,KDyE0BC,CAAuB3jE,GACnD4jE,EAAc,IAAI,GAAM5jE,GACxBo8B,EAAa,IAAI,GAAM55C,GAE7B,IAAIqhF,EACAC,EAGJ,GAAMP,GAAYC,EAEX,CACN,MAEMO,EAsDR,SAAqCT,EAAWhgF,GAC/C,MAAM,YAAEsgF,EAAW,aAAElnC,GAAiBp5C,EAGhC0gF,EAAkBJ,EAAY1pC,UAG9B+pC,EAwCP,SAAkCX,GAAW,WAAElnC,EAAU,YAAEwnC,EAAW,YAAE3C,EAAW,aAAEvkC,IACpF,MAAMunC,EAAqB,GAGrBD,EAAkBJ,EAAY1pC,UAEpC,IAAM,MAAMjuB,KAAYq3D,EAAY,CACnC,MAAMY,EAAeC,GAAwBl4D,EAAUmwB,EAAYwnC,GAEnE,IAAMM,EACL,SAGD,MAAQE,EAAcC,GAAiBH,EACvC,IAAII,EAAuB,EACvBC,EAAwB,EAE5B,GAAKtD,EACJ,GAAKvkC,EAAe,CAEnB,MAAM8nC,EAA+BvD,EAAYhnC,gBAAiByC,GAE7D8nC,IAGJF,EAAuBE,EAA6BC,oBAAqBJ,SAG1EC,EAAuBrD,EAAYwD,oBAAqBJ,GAIrD3nC,IACJ6nC,EAAwB7nC,EAAa+nC,oBAAqBJ,IAG3D,MAAMK,EAAoB,CACzBN,eACAC,eACAC,uBACAC,yBAKD,GAAKD,IAAyBN,EAC7B,MAAO,CAAEU,GAGVT,EAAmB5/E,KAAMqgF,GAG1B,OAAOT,EA5FoBU,CAAyBrB,EAAWhgF,GAG/D,GAAKo5C,EAAe,CACnB,MAKMkoC,EAAmBC,GALYZ,EAAmB7+E,OAAQ,EAAIm/E,2BAC5DA,IAA0BP,GAIkDA,GAEpF,GAAKY,EACJ,OAAOA,EAKT,OAAOC,GAA6BZ,EAAoBD,GA9ElCc,CAA4BxB,EAAW,CAAElnC,aAAYwnC,cAAa3C,YAFnEsC,GAAW,IAAI,GAAMA,GAAUwB,aAEiDroC,aAD/E8mC,GAAiB,IAAI,GAAMr7E,GAAO5J,WAKrDulF,EAAkBD,GAAqBE,GAAgBI,GAAwBb,EAAW,GAAKlnC,EAAYwnC,QAR3GE,EAAkBD,GAAqBM,GAAwBb,EAAW,GAAKlnC,EAAYwnC,GAW9F,IAAIoB,EAA0BC,GAA4BpB,GAM1D,OAJKJ,IACJuB,EA4MF,UAAsD,KAAE79C,EAAI,IAAED,GAAOu8C,GACpE,MAAMyB,EAAmBD,GAA4B,IAAI,GAAMxB,IACzD0B,EAAuBxsC,GAAiB8qC,GAyB9C,OAnBAt8C,GAAQ+9C,EAAiB/9C,KACzBD,GAAOg+C,EAAiBh+C,IAOxBC,GAAQs8C,EAA0B32C,WAClC5F,GAAOu8C,EAA0B12C,UAOjC5F,GAAQg+C,EAAqBh+C,KAC7BD,GAAOi+C,EAAqBj+C,IAErB,CAAEC,OAAMD,OAvOYk+C,CAA6CJ,EAAyBvB,IAG1F,CACNt8C,KAAM69C,EAAwB79C,KAC9BD,IAAK89C,EAAwB99C,IAC7BhoC,KAAM4kF,GAWR,SAASK,GAAwBl4D,EAAUmwB,EAAYwnC,GACtD,MAAMM,EAAej4D,EAAUmwB,EAAYwnC,GAE3C,IAAMM,EACL,OAAO,KAGR,MAAM,KAAE/8C,EAAI,IAAED,EAAG,KAAEhoC,GAASglF,EAE5B,MAAO,CAAEhlF,EAAM0kF,EAAY92D,QAAQu4D,OAAQl+C,EAAMD,IAwIlD,SAAS29C,GAA6BZ,EAAoBD,GACzD,IACIH,EACAC,EAFAwB,EAAe,EAInB,IAAM,MAAM,aAAElB,EAAY,aAAEC,EAAY,qBAAEC,EAAoB,sBAAEC,KAA2BN,EAAqB,CAG/G,GAAKK,IAAyBN,EAC7B,MAAO,CAAEI,EAAcC,GAKxB,MAAMkB,EAAYhB,GAAyB,EAAID,GAAwB,EAElEiB,EAAYD,IAChBA,EAAeC,EACf1B,EAAmBQ,EACnBP,EAAmBM,GAIrB,OAAOP,EAAmB,CAAEC,EAAkBD,GAAqB,KAuDpE,SAASoB,IAA4B,KAAE99C,EAAI,IAAED,IAC5C,MAAM,QAAEwF,EAAO,QAAEC,GAAYxkC,GAAO5J,OAEpC,MAAO,CACN4oC,KAAMA,EAAOuF,EACbxF,IAAKA,EAAMyF,GEtSE,MAAM,WAAqB,GAUzC,YAAatvB,EAAQmoE,EAAYC,GAChCzkF,MAAOqc,GAEP,MAAMld,EAAOiB,KAAKq+E,aAQlBr+E,KAAKokF,WAAaA,EAgBlBpkF,KAAKqkF,UAAYA,EAQjBrkF,KAAKyJ,IAAK,UAAU,GAUpBzJ,KAAKyJ,IAAK,aAAa,GAQvBzJ,KAAKyJ,IAAK,SAQVzJ,KAAKyJ,IAAK,MAiBVzJ,KAAKyJ,IAAK,gBAAiB,QAY3BzJ,KAAKw0E,WAAa,IAAI,GAEtBx0E,KAAKs+E,YAAa,CACjBl2E,IAAK,MAEL9E,WAAY,CACXy6E,MAAO,CACN,KACA,cACAh/E,EAAK6U,GAAI,SACT7U,EAAKi7E,GAAI,YAAa,cAAex7E,IAAUA,IAEhD8D,GAAIvD,EAAK6U,GAAI,MACb,mBAAoB7U,EAAK6U,GAAI,sBAG9B9L,SAAU,CACTs8E,EACAC,KAIFD,EAAWhK,eAAgB,CAC1B92E,WAAY,CACXy6E,MAAO,CACN,0BA4CJ,SACCn+E,MAAM43B,SAGNx3B,KAAKmR,SAAUnR,KAAKokF,WAAY,OAAQ,KACvCpkF,KAAKskF,QAAUtkF,KAAKskF,SAIrBtkF,KAAKqkF,UAAUtlF,KAAM,aAAc6U,GAAI5T,KAAM,UAI7CA,KAAKkpB,GAAI,gBAAiB,KACnBlpB,KAAKskF,SAMiB,SAAvBtkF,KAAKukF,cACTvkF,KAAKqkF,UAAUx5D,SAAW,GAAa25D,oBAAqB,CAC3D5lE,QAAS5e,KAAKqkF,UAAUzlE,QACxBxd,OAAQpB,KAAKokF,WAAWxlE,QACxBwjE,eAAe,EACfF,UAAWliF,KAAKykF,kBACb3mF,KAEJkC,KAAKqkF,UAAUx5D,SAAW7qB,KAAKukF,iBAKjCvkF,KAAKw0E,WAAWrjE,SAAUnR,KAAK4e,SAE/B,MAAM8lE,EAAgB,CAAE/kF,EAAMu2C,KACxBl2C,KAAKskF,SACTtkF,KAAKokF,WAAWv0D,QAChB7vB,KAAKskF,QAAS,EACdpuC,MAKFl2C,KAAKw0E,WAAW/qE,IAAK,YAAa,CAAE9J,EAAMu2C,KAEpCl2C,KAAKokF,WAAW90C,YAActvC,KAAKskF,SACvCtkF,KAAKskF,QAAS,EACdpuC,OAKFl2C,KAAKw0E,WAAW/qE,IAAK,aAAc,CAAE9J,EAAMu2C,KACrCl2C,KAAKskF,QACTpuC,MAKFl2C,KAAKw0E,WAAW/qE,IAAK,YAAai7E,GAClC1kF,KAAKw0E,WAAW/qE,IAAK,MAAOi7E,GAM7B,QACC1kF,KAAKokF,WAAWv0D,QAWjB,sBACC,MAAM,UAAE80D,EAAS,UAAEC,EAAS,UAAEC,EAAS,UAAEC,GAAc,GAAaC,sBAEpE,MAAyC,QAApC/kF,KAAKic,OAAOX,oBACT,CAAEqpE,EAAWC,EAAWC,EAAWC,GAEnC,CAAEF,EAAWD,EAAWG,EAAWD,IAqD7C,GAAaE,sBAAwB,CACpCJ,UAAWK,IACH,CACNl/C,IAAKk/C,EAAWptC,OAChB7R,KAAMi/C,EAAWj/C,KACjBjoC,KAAM,OAGR8mF,UAAW,CAAEI,EAAYpF,KACjB,CACN95C,IAAKk/C,EAAWptC,OAChB7R,KAAMi/C,EAAWj/C,KAAO65C,EAAU55C,MAAQg/C,EAAWh/C,MACrDloC,KAAM,OAGR+mF,UAAW,CAAEG,EAAYpF,KACjB,CACN95C,IAAKk/C,EAAWl/C,IAAM85C,EAAUlnC,OAChC3S,KAAMi/C,EAAWj/C,KACjBjoC,KAAM,OAGRgnF,UAAW,CAAEE,EAAYpF,KACjB,CACN95C,IAAKk/C,EAAWptC,OAASgoC,EAAUlnC,OACnC3S,KAAMi/C,EAAWj/C,KAAO65C,EAAU55C,MAAQg/C,EAAWh/C,MACrDloC,KAAM,QAWT,GAAa0mF,oBAAsBvC,G,MCtYpB,MAAM,WAAiB,GAIrC,cACCriF,QAEA,MAAMb,EAAOiB,KAAKq+E,aAQlBr+E,KAAKyJ,IAAK,UAAW,IAUrBzJ,KAAKyJ,IAAK,UAAW,aASrBzJ,KAAKyJ,IAAK,YAAa,IAEvBzJ,KAAKs+E,YAAa,CACjBl2E,IAAK,MACLxJ,GAAI,6BACJ0E,WAAY,CACXy6E,MAAO,CACN,KACA,WAEDkH,QAASlmF,EAAK6U,GAAI,cAQrB,SACChU,MAAM43B,SAENx3B,KAAKklF,oBACLllF,KAAKmlF,kBAILnlF,KAAKkpB,GAAI,iBAAkB,KAC1BlpB,KAAKklF,oBACLllF,KAAKmlF,oBAGNnlF,KAAKkpB,GAAI,mBAAoB,KAC5BlpB,KAAKmlF,oBASP,oBACC,GAAKnlF,KAAKkH,QAAU,CACnB,MACMk+E,GADS,IAAIjQ,WAAYM,gBAAiBz1E,KAAKkH,QAAQoc,OAAQ,iBAClDhiB,cAAe,OAC5B2jF,EAAUG,EAAIhmE,aAAc,WAQlC,IANK6lE,IACJjlF,KAAKilF,QAAUA,GAGhBjlF,KAAK4e,QAAQ0rB,UAAY,GAEjB86C,EAAI5gF,WAAWzC,OAAS,GAC/B/B,KAAK4e,QAAQhb,YAAawhF,EAAI5gF,WAAY,KAU7C,kBACMxE,KAAKqlF,WACTrlF,KAAK4e,QAAQ0mE,iBAAkB,kBAAmB7hF,QAASoM,IAC1DA,EAAKzM,MAAM6M,KAAOjQ,KAAKqlF,a,MCvGZ,MAAM,WAAoB,GAIxC,YAAappE,GACZrc,MAAOqc,GAQPjc,KAAKyJ,IAAK,OAAQ,IAyClBzJ,KAAKyJ,IAAK,WAAY,KAEtB,MAAM1K,EAAOiB,KAAKq+E,aAElBr+E,KAAKs+E,YAAa,CACjBl2E,IAAK,OACL9E,WAAY,CACXy6E,MAAO,CACN,KACA,aACAh/E,EAAK6U,GAAI,WAAYiX,GAAY,cAAgBA,GACjD9rB,EAAKi7E,GAAI,OAAQ,YAAax7E,IAAUA,EAAM8kB,UAGhDxb,SAAU,CACT,CACCM,IAAK,OAEL9E,WAAY,CACXy6E,MAAO,CACN,KACA,qBAIFj2E,SAAU,CACT,CACCyqC,KAAMxzC,EAAK6U,GAAI,e,MC9DP,MAAM,WAAmB,GAIvC,YAAaqI,GACZrc,MAAOqc,GAEP,MAAMld,EAAOiB,KAAKq+E,aACZkH,EAAe,KAGrBvlF,KAAKyJ,IAAK,SACVzJ,KAAKyJ,IAAK,cACVzJ,KAAKyJ,IAAK,QACVzJ,KAAKyJ,IAAK,aAAa,GACvBzJ,KAAKyJ,IAAK,QAAQ,GAClBzJ,KAAKyJ,IAAK,aAAa,GACvBzJ,KAAKyJ,IAAK,gBAAgB,GAC1BzJ,KAAKyJ,IAAK,aACVzJ,KAAKyJ,IAAK,SACVzJ,KAAKyJ,IAAK,YAAa,GACvBzJ,KAAKyJ,IAAK,WACVzJ,KAAKyJ,IAAK,kBAAmB,KAC7BzJ,KAAKyJ,IAAK,OAAQ,UAClBzJ,KAAKyJ,IAAK,YAAY,GACtBzJ,KAAKyJ,IAAK,iBAAiB,GAQ3BzJ,KAAK8H,SAAW9H,KAAKw9E,mBAQrBx9E,KAAKwlF,YAAcxlF,KAAKylF,qBAQxBzlF,KAAK0lF,UAAY1lF,KAAK2lF,iBAAkBJ,GASxCvlF,KAAK4lF,SAAW,IAAI,GAEpB5lF,KAAK4lF,SAASxL,eAAgB,CAC7B92E,WAAY,CACXy6E,MAAO,qBAYT/9E,KAAK6lF,cAAgB7lF,KAAK8lF,uBAW1B9lF,KAAKjB,KAAM,kBAAmB6U,GAC7B5T,KAAM,UACNA,KAAM,QACNA,KAAM,YACNA,KAAK+lF,kBAAkBhnF,KAAMiB,OAG9BA,KAAKs+E,YAAa,CACjBl2E,IAAK,SAEL9E,WAAY,CACXy6E,MAAO,CACN,KACA,YACAh/E,EAAK6U,GAAI,SACT7U,EAAKi7E,GAAI,YAAa,cAAex7E,IAAUA,GAC/CO,EAAKi7E,GAAI,YAAa,YAAax7E,IAAUA,GAC7CO,EAAK6U,GAAI,OAAQpV,GAASA,EAAQ,QAAU,UAC5CO,EAAKi7E,GAAI,WAAY,uBACrBj7E,EAAKi7E,GAAI,gBAAiB,6BAE3B/5E,KAAMlB,EAAK6U,GAAI,OAAQpV,GAASA,GAAgB,UAChDwnF,SAAUjnF,EAAK6U,GAAI,YACnB,kBAAmB,yBAA0B2xE,EAC7C,gBAAiBxmF,EAAKi7E,GAAI,aAAa,EAAMx7E,IAAUA,GACvD,eAAgBO,EAAK6U,GAAI,OAAQpV,KAASwB,KAAKimF,cAAen6E,OAAQtN,KAGvEsJ,SAAU9H,KAAK8H,SAEfohB,GAAI,CACHg9D,UAAWnnF,EAAK6U,GAAIkD,IACnBA,EAAI88B,mBAGLuyC,MAAOpnF,EAAK6U,GAAIkD,IAGV9W,KAAKsvC,UACTtvC,KAAKqU,KAAM,WAIXyC,EAAI88B,sBAUT,SACCh0C,MAAM43B,SAEDx3B,KAAKomF,OACTpmF,KAAK4lF,SAAS7mF,KAAM,WAAY6U,GAAI5T,KAAM,QAC1CA,KAAK8H,SAAS8G,IAAK5O,KAAK4lF,WAGzB5lF,KAAK8H,SAAS8G,IAAK5O,KAAKwlF,aACxBxlF,KAAK8H,SAAS8G,IAAK5O,KAAK0lF,WAEnB1lF,KAAKqmF,eACTrmF,KAAK8H,SAAS8G,IAAK5O,KAAK6lF,eAO1B,QACC7lF,KAAK4e,QAAQiR,QAUd,qBACC,MAAM21D,EAAc,IAAI,GAKxB,OAHAA,EAAYzmF,KAAM,QAAS6U,GAAI5T,KAAM,kBACrCwlF,EAAYzmF,KAAM,YAAa6U,GAAI5T,KAAM,mBAElCwlF,EAUR,iBAAkBD,GACjB,MAAMG,EAAY,IAAI,GAChB3mF,EAAOiB,KAAKq+E,aAqBlB,OAnBAqH,EAAUpH,YAAa,CACtBl2E,IAAK,OAEL9E,WAAY,CACXy6E,MAAO,CACN,KACA,oBAED36E,MAAOrE,EAAK6U,GAAI,cAChBtR,GAAI,yBAA0BijF,GAG/Bz9E,SAAU,CACT,CACCyqC,KAAMvyC,KAAKq+E,aAAazqE,GAAI,aAKxB8xE,EAUR,uBACC,MAAMG,EAAgB,IAAI,GAmB1B,OAjBAA,EAAcvH,YAAa,CAC1Bl2E,IAAK,OAEL9E,WAAY,CACXy6E,MAAO,CACN,KACA,yBAIFj2E,SAAU,CACT,CACCyqC,KAAMvyC,KAAKq+E,aAAazqE,GAAI,YAAa2+B,GAAQxd,GAAqBwd,QAKlEszC,EAeR,kBAAmBS,EAAS51D,EAAOkE,GAClC,OAAK0xD,EACmB,iBAAXA,EACJA,GAEF1xD,IACJA,EAAYG,GAAqBH,IAG7B0xD,aAAmBrgF,SAChBqgF,EAAS51D,EAAOkE,GAEhB,GAAIlE,IAAUkE,EAAY,KAAMA,KAAgB,MAKnD,IClTM,yNCkCA,MAAM,WAA2B,GAI/C,YAAa3Y,GACZrc,MAAOqc,GAQPjc,KAAKumF,UAAYvmF,KAAKwmF,mBAEtBxmF,KAAKo6E,eAAgB,CACpB92E,WAAY,CACX,iBAAiB,KAKnBtD,KAAKuxB,SAAU,WAAY3d,GAAI5T,KAAM,QAMtC,SACCJ,MAAM43B,SAENx3B,KAAK8H,SAAS8G,IAAK5O,KAAKumF,WASzB,mBACC,MAAMA,EAAY,IAAI,GAUtB,OARAA,EAAUr/E,QAAU,GAEpBq/E,EAAUnM,eAAgB,CACzB92E,WAAY,CACXy6E,MAAO,wBAIFwI,G,MC/DM,MAAM,WAAiB,GAIrC,cACC3mF,QAQAI,KAAK2V,MAAQ3V,KAAKw9E,mBAQlBx9E,KAAKk2E,aAAe,IAAI,GAQxBl2E,KAAKw0E,WAAa,IAAI,GAStBx0E,KAAKymF,aAAe,IAAIxG,GAAa,CACpCE,WAAYngF,KAAK2V,MACjBugE,aAAcl2E,KAAKk2E,aACnBgK,iBAAkBlgF,KAAKw0E,WACvB5xC,QAAS,CAER8jD,cAAe,UAGfC,UAAW,eAIb3mF,KAAKs+E,YAAa,CACjBl2E,IAAK,KAEL9E,WAAY,CACXy6E,MAAO,CACN,KACA,WACA,YAIFj2E,SAAU9H,KAAK2V,QAOjB,SACC/V,MAAM43B,SAGN,IAAM,MAAMn1B,KAAQrC,KAAK2V,MACxB3V,KAAKk2E,aAAatnE,IAAKvM,EAAKuc,SAG7B5e,KAAK2V,MAAMuT,GAAI,MAAO,CAAEpS,EAAKzU,KAC5BrC,KAAKk2E,aAAatnE,IAAKvM,EAAKuc,WAG7B5e,KAAK2V,MAAMuT,GAAI,SAAU,CAAEpS,EAAKzU,KAC/BrC,KAAKk2E,aAAa/xE,OAAQ9B,EAAKuc,WAIhC5e,KAAKw0E,WAAWrjE,SAAUnR,KAAK4e,SAMhC,QACC5e,KAAKymF,aAAaG,aAMnB,YACC5mF,KAAKymF,aAAazE,aC1GL,MAAM,WAAqB,GAIzC,YAAa/lE,GACZrc,MAAOqc,GAQPjc,KAAK8H,SAAW9H,KAAKw9E,mBAErBx9E,KAAKs+E,YAAa,CACjBl2E,IAAK,KAEL9E,WAAY,CACXy6E,MAAO,CACN,KACA,kBAIFj2E,SAAU9H,KAAK8H,WAOjB,QACC9H,KAAK8H,SAASsnB,MAAMS,SCjCP,MAAM,WAA0B,GAI9C,YAAa5T,GACZrc,MAAOqc,GAEPjc,KAAKs+E,YAAa,CACjBl2E,IAAK,KACL9E,WAAY,CACXy6E,MAAO,CACN,KACA,0B,MCEU,MAAM,WAAyB,GAI7C,YAAa9hE,GACZrc,MAAOqc,GAEPjc,KAAKimF,cAAe,EAQpBjmF,KAAK6mF,iBAAmB7mF,KAAK8mF,oBAE7B9mF,KAAKo6E,eAAgB,CACpB92E,WAAY,CACXy6E,MAAO,qBAQV,SACCn+E,MAAM43B,SAENx3B,KAAK8H,SAAS8G,IAAK5O,KAAK6mF,kBASzB,oBACC,MAAMA,EAAmB,IAAI,GA0B7B,OAxBAA,EAAiBvI,YAAa,CAC7Bl2E,IAAK,OAEL9E,WAAY,CACXy6E,MAAO,CACN,KACA,sBAIFj2E,SAAU,CACT,CACCM,IAAK,OAEL9E,WAAY,CACXy6E,MAAO,CACN,KACA,iCAOE8I,GCtEM,SAASE,IAAqB,QAAEx1E,EAAO,UAAEy1E,EAAS,SAAE91E,EAAQ,gBAAE+1E,IAC5E11E,EAAQJ,SAAUnQ,SAAU,YAAa,CAAE8V,EAAKq4B,KAC/C,IAAM63C,IACL,OAKD,MAAMn3E,EAAqC,mBAAvBs/B,EAAO+3C,aAA6B/3C,EAAO+3C,eAAiB,GAEhF,IAAM,MAAMC,KAAkBF,EAC7B,GAAKE,EAAehgD,SAAUgI,EAAO/tC,SAAYyO,EAAKuJ,SAAU+tE,GAC/D,OAIFj2E,M,YC4CK,SAASk2E,GAAgBnrE,EAAQorE,EAAc,IACrD,MAAMjD,EAAa,IAAIiD,EAAaprE,GAE9BooE,EAAY,IAAI,GAAmBpoE,GACnCqrE,EAAe,IAAI,GAAcrrE,EAAQmoE,EAAYC,GAY3D,OAVAD,EAAWrlF,KAAM,aAAc6U,GAAI0zE,GAE9BlD,aAAsB,GAC1BA,EAAWrlF,KAAM,QAAS6U,GAAI0zE,EAAc,UAE5ClD,EAAWmC,UAAUxnF,KAAM,QAAS6U,GAAI0zE,EAAc,UAiIxD,SAA6BA,IAS7B,SAA8BA,GAC7BA,EAAap+D,GAAI,SAAU,KAC1B69D,GAAqB,CACpBx1E,QAAS+1E,EACTN,UAAW,IAAMM,EAAahD,OAC9BpzE,SAAU,KACTo2E,EAAahD,QAAS,GAEvB2C,gBAAiB,CAAEK,EAAa1oE,cAhBlC2oE,CAAqBD,GAwBtB,SAAiCA,GAEhCA,EAAap+D,GAAI,UAAWpS,IAEtBA,EAAIlM,kBAAkB,KAI3B08E,EAAahD,QAAS,KA/BvBkD,CAAwBF,GAsCzB,SAAwCA,GAEvCA,EAAa9S,WAAW/qE,IAAK,YAAa,CAAE9J,EAAMu2C,KAC5CoxC,EAAahD,SACjBgD,EAAajD,UAAUx0D,QACvBqmB,OAKFoxC,EAAa9S,WAAW/qE,IAAK,UAAW,CAAE9J,EAAMu2C,KAC1CoxC,EAAahD,SACjBgD,EAAajD,UAAUrC,YACvB9rC,OAlDFuxC,CAA+BH,GAjI/BI,CAAoBJ,GAEbA,EAyFD,SAASK,GAAmBL,EAAc3xE,GAChD,MAAMsG,EAASqrE,EAAarrE,OACtB2rE,EAAWN,EAAaM,SAAW,IAAI,GAAU3rE,GAEvD2rE,EAASjyE,MAAMuS,OAAQvS,GAAQgB,MAAO,EAAI1W,OAAM+oD,YAC/C,GAAc,cAAT/oD,EACJ,OAAO,IAAI,GAAmBgc,GACxB,GAAc,WAAThc,GAA8B,iBAATA,EAA0B,CAC1D,MAAM4nF,EAAe,IAAI,GAAc5rE,GACvC,IAAImoE,EAcJ,OAXCA,EADa,WAATnkF,EACS,IAAI,GAAYgc,GAEhB,IAAI,GAAkBA,GAIpCmoE,EAAWrlF,QAASd,OAAOuF,KAAMwlD,IAAUp1C,GAAIo1C,GAC/Co7B,EAAW7yD,SAAU,WAAY3d,GAAIi0E,GAErCA,EAAa//E,SAAS8G,IAAKw1E,GAEpByD,KAITP,EAAajD,UAAUv8E,SAAS8G,IAAKg5E,GAErCA,EAASjyE,MAAM4b,SAAU,WAAY3d,GAAI0zE,G,MC7L3B,MAAM,WAAoB,GASxC,YAAarrE,EAAQ/Z,GACpBtC,MAAOqc,GAEP,MAAMld,EAAOiB,KAAKq+E,aACZ5/E,EAAIuB,KAAKvB,EAQfuB,KAAKkC,QAAUA,GAAW,GAQ1BlC,KAAKyJ,IAAK,YAAahL,EAAG,mBAa1BuB,KAAKyJ,IAAK,WAAY,QAQtBzJ,KAAK2V,MAAQ3V,KAAKw9E,mBAQlBx9E,KAAKk2E,aAAe,IAAI,GASxBl2E,KAAKw0E,WAAa,IAAI,GAQtBx0E,KAAKyJ,IAAK,SASVzJ,KAAKyJ,IAAK,aAAa,GAQvBzJ,KAAK8nF,UAAY,IAAI,GAAW7rE,GAmBhCjc,KAAK8H,SAAW9H,KAAKw9E,mBACrBx9E,KAAK8H,SAAS8G,IAAK5O,KAAK8nF,WAWxB9nF,KAAKmgF,WAAangF,KAAKw9E,mBAkBvBx9E,KAAKymF,aAAe,IAAIxG,GAAa,CACpCE,WAAYngF,KAAKmgF,WACjBjK,aAAcl2E,KAAKk2E,aACnBgK,iBAAkBlgF,KAAKw0E,WACvB5xC,QAAS,CAER8jD,cAAe,CAAE,YAAa,WAG9BC,UAAW,CAAE,aAAc,gBAI7B,MAAMhoE,EAAU,CACf,KACA,aACA5f,EAAK6U,GAAI,SACT7U,EAAKi7E,GAAI,YAAa,uBC9JV,IAAyBtkD,EDiKjC11B,KAAKkC,QAAQ6lF,qBAAuB/nF,KAAKkC,QAAQ8lF,YACrDrpE,EAAQ1b,KAAM,uBAGfjD,KAAKs+E,YAAa,CACjBl2E,IAAK,MACL9E,WAAY,CACXy6E,MAAOp/D,EACP8/D,KAAM,UACN,aAAc1/E,EAAK6U,GAAI,aACvBxQ,MAAO,CACN6kF,SAAUlpF,EAAK6U,GAAI,cAIrB9L,SAAU9H,KAAK8H,SAEfohB,GAAI,CAEHg9D,WCpLoCxwD,EDoLT11B,KCnLvB01B,EAAK2oD,aAAazqE,GAAIkD,IACvBA,EAAI1V,SAAWs0B,EAAK9W,SACxB9H,EAAI88B,uBD8LL5zC,KAAKkoF,UAAYloF,KAAKkC,QAAQ6lF,oBAAsB,IAAI,GAAiB/nF,MAAS,IAAImoF,GAAcnoF,MAMrG,SACCJ,MAAM43B,SAGN,IAAM,MAAMn1B,KAAQrC,KAAK2V,MACxB3V,KAAKk2E,aAAatnE,IAAKvM,EAAKuc,SAG7B5e,KAAK2V,MAAMuT,GAAI,MAAO,CAAEpS,EAAKzU,KAC5BrC,KAAKk2E,aAAatnE,IAAKvM,EAAKuc,WAG7B5e,KAAK2V,MAAMuT,GAAI,SAAU,CAAEpS,EAAKzU,KAC/BrC,KAAKk2E,aAAa/xE,OAAQ9B,EAAKuc,WAIhC5e,KAAKw0E,WAAWrjE,SAAUnR,KAAK4e,SAE/B5e,KAAKkoF,UAAU1wD,OAAQx3B,MAMxB,UAGC,OAFAA,KAAKkoF,UAAUhuE,UAERta,MAAMsa,UAMd,QACCla,KAAKymF,aAAaG,aAMnB,YACC5mF,KAAKymF,aAAazE,YAUnB,eAAgBnmE,EAAQ/e,GACvBkD,KAAK2V,MAAMD,QAASmG,EAAOxR,IAAKvM,GAClB,KAARA,EACG,IAAI,GACQ,KAARA,GACNkC,KAAKkC,QAAQ6lF,qBAejB,aAAY,qDAAsDlsE,GAG5D,IAAI,IACA/e,EAAQ4M,IAAK5L,GACjBhB,EAAQ+B,OAAQf,QAmBvB,aAAY,+BAAgC,CAAEA,UAE5CkG,OAAQ3B,QAAiBiE,IAATjE,KAwBtB,MAAM,WAAkB,GAIvB,YAAa4Z,GACZrc,MAAOqc,GAQPjc,KAAK8H,SAAW9H,KAAKw9E,mBAErBx9E,KAAKs+E,YAAa,CACjBl2E,IAAK,MACL9E,WAAY,CACXy6E,MAAO,CACN,KACA,sBAGFj2E,SAAU9H,KAAK8H,YAalB,MAAMqgF,GAQL,YAAazyD,GACZ,MAAM32B,EAAO22B,EAAK2oD,aAGlB3oD,EAAKjsB,IAAK,cAAc,GAGxBisB,EAAKoyD,UAAUhgF,SAASogB,OAAQwN,EAAK/f,OAAQgB,MAAOtU,GAAQA,GAG5DqzB,EAAKyqD,WAAWj4D,OAAQwN,EAAK/f,OAAQgB,MAAOtU,GAAQA,GAEpDqzB,EAAK0kD,eAAgB,CACpB92E,WAAY,CACXy6E,MAAO,CAENh/E,EAAKi7E,GAAI,aAAc,2BAS3B,UAKA,YAsBD,MAAM,GAQL,YAAatkD,GAOZ11B,KAAK01B,KAAOA,EAQZ11B,KAAK6yC,aAAend,EAAK5tB,SAQzB9H,KAAKooF,eAAiB1yD,EAAKyqD,WAQ3BngF,KAAKqoF,cAAgB3yD,EAAKoyD,UAQ1B9nF,KAAKsoF,iBAAmB5yD,EAAKwgD,aAQ7Bl2E,KAAKuoF,WAAa7yD,EAAKzZ,OAqBvBjc,KAAKwoF,eAAiB9yD,EAAK8nD,mBAa3Bx9E,KAAKyoF,aAAe/yD,EAAK8nD,mBAWzBx9E,KAAK0oF,qBAAuB1oF,KAAK2oF,8BAWjC3oF,KAAK4oF,eAAiB,KAWtB5oF,KAAK6oF,cAAgB,KASrB7oF,KAAK8oF,kCAAmC,EAGxCpzD,EAAKoyD,UAAUhgF,SAASogB,OAAQloB,KAAKwoF,gBAAiB7xE,MAAOtU,GAAQA,GAGrErC,KAAKwoF,eAAet/D,GAAI,MAAOlpB,KAAK+oF,2BAA2BhqF,KAAMiB,OACrEA,KAAKwoF,eAAet/D,GAAI,SAAUlpB,KAAK+oF,2BAA2BhqF,KAAMiB,OAGxE01B,EAAK5tB,SAASohB,GAAI,MAAOlpB,KAAK+oF,2BAA2BhqF,KAAMiB,OAC/D01B,EAAK5tB,SAASohB,GAAI,SAAUlpB,KAAK+oF,2BAA2BhqF,KAAMiB,OAMlE01B,EAAK/f,MAAMuT,GAAI,SAAU,CAAEpS,EAAKkyE,KAC/B,MAAMtmF,EAAQsmF,EAAWtmF,MAGzB,IAAM,MAAMumF,KAAeD,EAAWlzE,QAChCpT,GAAS1C,KAAKwoF,eAAezmF,OACjC/B,KAAKyoF,aAAatkF,OAAQ8kF,GAE1BjpF,KAAKwoF,eAAerkF,OAAQ8kF,GAK9B,IAAM,IAAIC,EAAexmF,EAAOwmF,EAAexmF,EAAQsmF,EAAWp2E,MAAM7Q,OAAQmnF,IAAiB,CAChG,MAAMC,EAAYH,EAAWp2E,MAAOs2E,EAAexmF,GAE9CwmF,EAAelpF,KAAKwoF,eAAezmF,OACvC/B,KAAKyoF,aAAa75E,IAAKu6E,EAAWD,EAAelpF,KAAKwoF,eAAezmF,QAErE/B,KAAKwoF,eAAe55E,IAAKu6E,EAAWD,GAQtClpF,KAAKopF,oBAGN1zD,EAAK0kD,eAAgB,CACpB92E,WAAY,CACXy6E,MAAO,CAEN,0BAYJ,OAAQroD,GACP11B,KAAK86B,YAAcpF,EAAK9W,QAExB5e,KAAKqpF,0BACLrpF,KAAKspF,gCAAiC5zD,GAMvC,UAGC11B,KAAK0oF,qBAAqBxuE,UAE1Bla,KAAK4oF,eAAe1uE,UAarB,kBAMC,IAAMla,KAAK86B,YAAYhF,cAAcukB,KAAKlT,SAAUnnC,KAAK86B,aACxD,OAQD,IAAM96B,KAAK86B,YAAYwnD,aAGtB,YAFAtiF,KAAK8oF,kCAAmC,GAOzC,MAAMS,EAA2BvpF,KAAKyoF,aAAa1mF,OACnD,IAAIynF,EAKJ,KAAQxpF,KAAKypF,sBACZzpF,KAAK0pF,iBAELF,GAAmB,EAMpB,IAAMA,GAAoBxpF,KAAKyoF,aAAa1mF,OAAS,CAEpD,KAAQ/B,KAAKyoF,aAAa1mF,SAAW/B,KAAKypF,sBACzCzpF,KAAK2pF,oBAOD3pF,KAAKypF,sBACTzpF,KAAK0pF,iBAIF1pF,KAAKyoF,aAAa1mF,SAAWwnF,GACjCvpF,KAAK01B,KAAKrhB,KAAM,sBAWlB,2BAEC,IAAMrU,KAAKwoF,eAAezmF,OACzB,OAAO,EAGR,MAAM6c,EAAU5e,KAAK86B,YACfxf,EAAsBtb,KAAKuoF,WAAWjtE,oBACtCsuE,EAAgB,IAAI,GAAMhrE,EAAQyI,WAClCwiE,EAAc,IAAI,GAAMjrE,GAE9B,IAAM5e,KAAK6oF,cAAgB,CAC1B,MAAMiB,EAAgB/iF,GAAO5J,OAAOq6C,iBAAkB54B,GAChDmrE,EAA0C,QAAxBzuE,EAAgC,eAAiB,cAKzEtb,KAAK6oF,cAAgB3tE,OAAOs5B,SAAUs1C,EAAeC,IAGtD,MAA6B,QAAxBzuE,EACGsuE,EAAclyC,MAAQmyC,EAAYnyC,MAAQ13C,KAAK6oF,cAE/Ce,EAAc7jD,KAAO8jD,EAAY9jD,KAAO/lC,KAAK6oF,cAgBtD,0BACC,IAAImB,EAGJhqF,KAAK4oF,eAAiB,IAAI,GAAgB5oF,KAAK86B,YAAatxB,IACrDwgF,GAAiBA,IAAkBxgF,EAAMo4E,YAAY57C,QAAShmC,KAAK8oF,mCACxE9oF,KAAK8oF,kCAAmC,EAExC9oF,KAAKopF,kBAELY,EAAgBxgF,EAAMo4E,YAAY57C,SAIpChmC,KAAKopF,kBASN,gCAAiC1zD,GAChCA,EAAKxM,GAAI,kBAAmB,KAC3BlpB,KAAKopF,oBAYP,iBACOppF,KAAKyoF,aAAa1mF,SACvB/B,KAAK6yC,aAAajkC,IAAK,IAAI,IAC3B5O,KAAK6yC,aAAajkC,IAAK5O,KAAK0oF,sBAC5B1oF,KAAKsoF,iBAAiB15E,IAAK5O,KAAK0oF,qBAAqB9pE,UAGtD5e,KAAKyoF,aAAa75E,IAAK5O,KAAKwoF,eAAerkF,OAAQnE,KAAKwoF,eAAen5D,MAAQ,GAWhF,oBACCrvB,KAAKwoF,eAAe55E,IAAK5O,KAAKyoF,aAAatkF,OAAQnE,KAAKyoF,aAAar5D,QAE/DpvB,KAAKyoF,aAAa1mF,SACvB/B,KAAK6yC,aAAa1uC,OAAQnE,KAAK0oF,sBAC/B1oF,KAAK6yC,aAAa1uC,OAAQnE,KAAK6yC,aAAaxjB,MAC5CrvB,KAAKsoF,iBAAiBnkF,OAAQnE,KAAK0oF,qBAAqB9pE,UAW1D,8BACC,MAAM3C,EAASjc,KAAKuoF,WACd9pF,EAAIwd,EAAOxd,EACXwrF,EAAW7C,GAAgBnrE,GAmBjC,OAjBAguE,EAASlM,MAAQ,+BAIjBkM,EAAS1F,cAA+C,QAA/BtoE,EAAOX,oBAAgC,KAAO,KDttBlE,SAA+BgsE,EAAc4C,GACnD,MAAMjuE,EAASqrE,EAAarrE,OACtBxd,EAAIwd,EAAOxd,EACX0rF,EAAc7C,EAAa6C,YAAc,IAAI,GAAaluE,GAEhEkuE,EAAY1gF,IAAK,YAAahL,EAAG,qBAEjC6oF,EAAalN,eAAgB,CAC5B92E,WAAY,CACXy6E,MAAO,CAAE,0BAIXmM,EAAQ7/E,IAAKqrB,GAAQy0D,EAAYx0E,MAAM/G,IAAK8mB,IAE5C4xD,EAAajD,UAAUv8E,SAAS8G,IAAKu7E,GACrCA,EAAYx0E,MAAM4b,SAAU,WAAY3d,GAAI0zE,GCwsB3C8C,CAAsBH,EAAU,IAEhCA,EAAS7F,WAAW36E,IAAK,CACxBinB,MAAOjyB,EAAG,mBACV6nF,SAAS,EACTF,KE/1BY,kLFm2Bb6D,EAASE,YAAYx0E,MAAMuS,OAAQloB,KAAKyoF,cAAe9xE,MAAOtU,GAAQA,GAE/D4nF,EAeR,6BACCjqF,KAAKooF,eAAe7+E,QAEpBvJ,KAAKwoF,eAAen+E,IAAKhI,IACxBrC,KAAKooF,eAAex5E,IAAKvM,KAGrBrC,KAAKyoF,aAAa1mF,QACtB/B,KAAKooF,eAAex5E,IAAK5O,KAAK0oF,uB,MGt2BlB,MAAM,WAA4B,GAWhD,YAAazsE,EAAQw7D,EAAav1E,EAAU,IAC3CtC,MAAOqc,GASPjc,KAAKi4E,YAAc,IAAI,GAAiBh8D,GAQxCjc,KAAKo4E,QAAU,IAAI,GAAan8D,EAAQ,CACvC8rE,oBAAqB7lF,EAAQmoF,6BAS9BrqF,KAAKwsB,SAAW,IAAI,GAAsBvQ,EAAQw7D,GAMnD,SACC73E,MAAM43B,SAGNx3B,KAAKi4E,YAAY/wE,QAAQ0H,IAAK5O,KAAKo4E,SAEnCp4E,KAAK8lC,IAAIl3B,IAAK5O,KAAKi4E,aACnBj4E,KAAKq+D,KAAKzvD,IAAK5O,KAAKwsB,WC1BP,MAAM,WAAsB,GAa1C,YAAa89D,EAAqBzuE,GACjCjc,MAAOic,GAEF,GAAWyuE,KACftqF,KAAKihE,cAAgBqpB,GAGtBtqF,KAAKL,KAAK09D,UAAY,IAAI,GAAmBr9D,KAAKL,KAAK49D,cAEvDv9D,KAAKgpD,MAAMhoD,SAAS4oE,aAEpB,MAAMygB,GAA8BrqF,KAAK6b,OAAOzd,IAAK,kCAC/Cs3B,EAAO,IAAI,GAAqB11B,KAAKic,OAAQjc,KAAKq0E,QAAQ3+C,KAAM,CACrE20D,+BAGDrqF,KAAKkc,GAAK,IAAI,GAAiBlc,KAAM01B,GCzDxB,SAAuBnZ,GACrC,IAAM,EAAYA,EAAOguE,qBAOxB,MAAM,IAAI,KACT,4CACAhuE,GAIF,MAAM0kD,EAAgB1kD,EAAO0kD,cAG7B,GAAKA,GAAyD,aAAxCA,EAAcp6B,QAAQpU,eAAgCwuC,EAAcupB,KAAO,CAChG,IAAIC,EACJ,MAAMD,EAAOvpB,EAAcupB,KACrBE,EAAW,IAAMnuE,EAAOguE,sBAIzB,EAAYC,EAAKG,UACrBF,EAAiBD,EAAKG,OAEtBH,EAAKG,OAAS,KACbD,IACAD,EAAep3E,MAAOm3E,KAKxBA,EAAKv7C,iBAAkB,SAAUy7C,GAIjCnuE,EAAO2M,GAAI,UAAW,KACrBshE,EAAKp7C,oBAAqB,SAAUs7C,GAE/BD,IACJD,EAAKG,OAASF,MDiBhBG,CAAc5qF,MAUf,UAOC,OANKA,KAAKihE,eACTjhE,KAAKuqF,sBAGNvqF,KAAKkc,GAAGhC,UAEDta,MAAMsa,UAgGd,cAAeowE,EAAqBzuE,EAAS,IAC5C,OAAO,IAAI9C,QAAS/L,IACnB,MAAMuP,EAAS,IAAIvc,KAAMsqF,EAAqBzuE,GAE9C7O,EACCuP,EAAOpD,cACLD,KAAM,IAAMqD,EAAOL,GAAGI,KAAM,GAAWguE,GAAwBA,EAAsB,OACrFpxE,KAAM,KACN,IAAM,GAAWoxE,IAAyBzuE,EAAOuiD,YAGhD,MAAM,IAAI,KAAe,6BAA8B,MAGxD,MAAMA,EAAcviD,EAAOuiD,aAcjC,SAAyBksB,GACxB,OAAO,GAAWA,IE5MyB1V,EF4MmB0V,EE3MzD1V,aAAcC,oBACXD,EAAGp2E,MAGJo2E,EAAGtqC,WFuM4EggD,EE5MxE,IAA6B1V,EF6LIiW,CAAgBP,GAE1D,OAAO/tE,EAAO5c,KAAK2c,KAAM8hD,KAEzBllD,KAAM,IAAMqD,EAAOlI,KAAM,UACzB6E,KAAM,IAAMqD,OAMlB/H,GAAK,GAAe,IACpBA,GAAK,GAAe,IGxML,MAAM,GAIpB,YAAa+H,GAiBZvc,KAAKuc,OAASA,EAiBdvc,KAAKyJ,IAAK,aAAa,GAQvBzJ,KAAK8qF,cAAgB,IAAIzyE,IAuC1B,cAAe/V,GACdtC,KAAK8qF,cAAcl8E,IAAKtM,GAEQ,GAA3BtC,KAAK8qF,cAAc9hF,OACvBhJ,KAAKkpB,GAAI,gBAAiB6hE,GAAc,CAAEt6E,SAAU,YACpDzQ,KAAKsvC,WAAY,GASnB,mBAAoBhtC,GACnBtC,KAAK8qF,cAAc/2E,OAAQzR,GAEK,GAA3BtC,KAAK8qF,cAAc9hF,OACvBhJ,KAAK+P,IAAK,gBAAiBg7E,IAC3B/qF,KAAKsvC,WAAY,GAOnB,UACCtvC,KAAKsR,gBAMN,6BACC,OAAO,GAuJT,SAASy5E,GAAcj0E,GACtBA,EAAIpD,QAAS,EACboD,EAAIhH,OArJL0E,GAAK,GAAQ,ICjIE,MAAMw2E,GACpB,YAAaC,GAOZjrF,KAAKkrF,MA2CP,SAAmBD,GAElB,MAAMC,EAAQD,EAAmBC,MAAQ/hF,MAAMiK,KAAM63E,EAAmBC,OAAU,GAC5Ev1E,EAAQs1E,EAAmBt1E,MAAQxM,MAAMiK,KAAM63E,EAAmBt1E,OAAU,GAElF,GAAKu1E,EAAMnpF,OACV,OAAOmpF,EAGR,OAAOv1E,EACL3R,OAAQ3B,GAAsB,SAAdA,EAAK8oF,MACrB9gF,IAAKhI,GAAQA,EAAK+oF,aAtDNC,CAAUJ,GAQvBjrF,KAAKsrF,QAAUL,EAQhB,YACC,OAAOjrF,KAAKsrF,QAAQ3kF,MAWrB,QAAS1G,GACR,OAAOD,KAAKsrF,QAAQC,QAAStrF,GAS9B,QAASA,EAAMN,GACdK,KAAKsrF,QAAQE,QAASvrF,EAAMN,IC3Bf,MAAM,WAA0B,GAC9C,YAAa+1B,GACZ91B,MAAO81B,GAEP,MAAM6nC,EAAev9D,KAAKgB,SAO1B,SAASyqF,EAAa30E,EAAKnX,GAC1BA,EAAKi0C,iBAEL,MAAM83C,EAAe/rF,EAAKgsF,UAAY,CAAEhsF,EAAKgsF,WAAcxiF,MAAMiK,KAAMmqD,EAAanzC,UAAU8F,aAExFld,EAAY,IAAI,GAAWuqD,EAAc,kBAE/CA,EAAalpD,KAAMrB,EAAW,CAC7B44E,aAAcjsF,EAAKisF,aACnBF,iBAMI14E,EAAUlD,KAAKF,QACnBjQ,EAAKk0C,kBArBP7zC,KAAK8zC,aAAe,CAAE,QAAS,OAAQ,MAAO,OAAQ,YAEtD9zC,KAAKmR,SAAUosD,EAAc,QAASkuB,EAAa,CAAEh7E,SAAU,QAC/DzQ,KAAKmR,SAAUosD,EAAc,OAAQkuB,EAAa,CAAEh7E,SAAU,QAuB/D,WAAYijC,GACX,MAAMsgC,EAAU,CACf4X,aAAc,IAAIZ,GAAct3C,EAASm4C,cAAgBn4C,EAASm4C,cAAgBn4C,EAASk4C,eAGtE,QAAjBl4C,EAASzzC,OACb+zE,EAAQ2X,UAOX,SAA2Bj2D,EAAMge,GAChC,MAAMo4C,EAASp4C,EAAStyC,OAAO00B,cACzB+K,EAAI6S,EAASq4C,QACbnrD,EAAI8S,EAASs4C,QACnB,IAAI3lD,EAGCylD,EAAOG,qBAAuBH,EAAOG,oBAAqBprD,EAAGD,GACjEyF,EAAWylD,EAAOG,oBAAqBprD,EAAGD,GAGjC8S,EAASw4C,cAClB7lD,EAAWylD,EAAOxlD,cAClBD,EAASqD,SAAUgK,EAASw4C,YAAax4C,EAASy4C,aAClD9lD,EAASvP,UAAU,IAGpB,OAAKuP,EACG3Q,EAAKC,aAAaiV,eAAgBvE,GAElC3Q,EAAK10B,SAASopB,UAAUmF,gBA3BV68D,CAAkBpsF,KAAK01B,KAAMge,IAGlD1zC,KAAKqU,KAAMq/B,EAASzzC,KAAMyzC,EAAUsgC,ICrDvB,MAAM,WAAuB,GAI3C,wBACC,MAAO,iBAMR,OACC,MAAMt+C,EAAO11B,KAAKuc,OAAO83D,QAAQ3+C,KAC3B6nC,EAAe7nC,EAAK10B,SAC1B,IAAIqrF,GAAe,EAEnB32D,EAAKknB,YAAa,IAElB58C,KAAKmR,SAAUosD,EAAc,UAAW,CAAEzmD,EAAKnX,KAC9C0sF,EAAe1sF,EAAK+0B,WAGrB10B,KAAKmR,SAAUosD,EAAc,iBAAkB,CAAEzmD,EAAKnX,KAChD0sF,IACJ1sF,EAAK2sF,aAAc,IAElB,CAAE77E,SAAU,UClCjB,MAAM87E,GAAuB,CAAE,aAAc,MCkB9B,MAAM,WAAkB,GAItC,wBACC,MAAO,YAMR,sBACC,MAAO,CAAE,IAMV,OACC,MAAMhwE,EAASvc,KAAKuc,OACdiwE,EAAgBjwE,EAAOysC,MAAMhoD,SAC7B00B,EAAOnZ,EAAO83D,QAAQ3+C,KACtB6nC,EAAe7nC,EAAK10B,SAsG1B,SAASyrF,EAAW31E,EAAKnX,GACxB,MAAMisF,EAAejsF,EAAKisF,aAE1BjsF,EAAKi0C,iBAEL,MAAM1sC,EAAUqV,EAAO5c,KAAKm+D,OAAQvhD,EAAOysC,MAAMuqB,mBAAoBiZ,EAAcpiE,YAEnFmzC,EAAalpD,KAAM,kBAAmB,CAAEu3E,eAAc1kF,UAAS4S,OAAQhD,EAAIhZ,OArG5EkC,KAAK0sF,mBAAqB,IAAI,GAAmBnvB,GAEjD7nC,EAAKknB,YAAa,IAMlB58C,KAAKmR,SAAUosD,EAAc,iBAAkBzmD,IACzCyF,EAAO4gC,YACXrmC,EAAIhH,QAEH,CAAEW,SAAU,YAEfzQ,KAAKmR,SAAUosD,EAAc,iBAAkB,CAAEzmD,EAAKnX,KACrD,MAAMisF,EAAejsF,EAAKisF,aAC1B,IAAI1kF,EAAU,GC7DF,IAA0BqrC,ED+DjCq5C,EAAaL,QAAS,aAC1BrkF,EEhEW,SAAiCvH,GAC/C,OAAOA,EACLuK,QAAS,0DAA2D,CAAEyiF,EAAWC,IAG3D,GAAjBA,EAAO7qF,OACJ,IAGD6qF,GFuDI,CAAwBhB,EAAaL,QAAS,cAC7CK,EAAaL,QAAS,kBChEpCh5C,GADwCA,EDkEVq5C,EAAaL,QAAS,eC/DlDrhF,QAAS,KAAM,QACfA,QAAS,KAAM,QAEfA,QAAS,cAAe,WAExBA,QAAS,SAAU,QAEnBA,QAAS,MAAO,UAChBA,QAAS,MAAO,UAEhBA,QAAS,QAAS,YAEVkP,SAAU,YAAem5B,EAAKn5B,SAAU,WAEjDm5B,EAAO,MAAOA,SDiDZrrC,EC3CIqrC,GD8CLrrC,EAAUlH,KAAK0sF,mBAAmB5uB,OAAQ52D,GAE1C,MAAM8L,EAAY,IAAI,GAAWhT,KAAM,uBACvCA,KAAKqU,KAAMrB,EAAW,CACrB9L,UACA0kF,eACAU,YAAa3sF,EAAK2sF,cAMdt5E,EAAUlD,KAAKF,QACnBkH,EAAIhH,OAGL4lB,EAAKm3D,wBACH,CAAEp8E,SAAU,QAEfzQ,KAAKmR,SAAUnR,KAAM,sBAAuB,CAAE8W,EAAKnX,KAClD,IAAMA,EAAKuH,QAAQub,QAAU,CAC5B,MAAMqqE,EAAiB9sF,KAAKuc,OAAO5c,KAC7BqpD,EAAQhpD,KAAKuc,OAAOysC,MAKpB+jC,EAAgBD,EAAepuB,QAAS/+D,EAAKuH,QAAS,oBAE5D,GAAiC,GAA5B6lF,EAAcjmE,WAClB,OAGDkiC,EAAM5L,OAAQprB,IACb,MAAM5H,EAAY4+B,EAAMhoD,SAASopB,UAIjC,GAAKzqB,EAAK2sF,aA+Hf,SAA8BtwB,EAAkB/S,GAC/C,GAAK+S,EAAiBl1C,WAAa,EAClC,OAAO,EAGR,MAAML,EAAQu1C,EAAiB9+C,SAAU,GAEzC,GAAK+rC,EAAO6D,SAAUrmC,GACrB,OAAO,EAGR,OAAiD,GAA1C,IAAKA,EAAM+O,oBAAqBzzB,OA1IVirF,CAAqBD,EAAe/jC,EAAMC,QAAW,CAE7E,MAAMgkC,EAAiB9jF,MAAMiK,KAAMgX,EAAU2Q,iBAC3C/2B,OAAQ,EAAIlF,KAAWkqD,EAAMC,OAAOqO,uBAAwBx4D,GAAMouF,cAE9D9iE,EAAUqD,aACfu7B,EAAM8jB,cAAe1iD,EAAW,CAAEqkD,oBAAoB,IAMvDwe,EAAehqF,QAASmnB,EAAU2Q,iBAElC,MAAM9L,EAAQ+C,EAAO0iC,cAAeq4B,GAEpC,IAAM,MAAM1qF,KAAQ4sB,EAAMq4B,YACpBjlD,EAAKlC,GAAI,UAAakC,EAAKlC,GAAI,gBACnC6xB,EAAOo8C,cAAe6e,EAAgB5qF,GAKzC2mD,EAAM6pB,cAAeka,KAGtBj2E,EAAIhH,SAEH,CAAEW,SAAU,QAcfzQ,KAAKmR,SAAUosD,EAAc,OAAQkvB,EAAW,CAAEh8E,SAAU,QAC5DzQ,KAAKmR,SAAUosD,EAAc,MAAO,CAAEzmD,EAAKnX,KAGrC4c,EAAO4gC,WACXx9C,EAAKi0C,iBAEL64C,EAAW31E,EAAKnX,IAEf,CAAE8Q,SAAU,QAEfzQ,KAAKmR,SAAUosD,EAAc,kBAAmB,CAAEzmD,EAAKnX,KAChDA,EAAKuH,QAAQub,UAClB9iB,EAAKisF,aAAaJ,QAAS,YAAaxrF,KAAK0sF,mBAAmB3uB,OAAQp+D,EAAKuH,UAC7EvH,EAAKisF,aAAaJ,QAAS,aD9JhB,SAAS2B,EAAiBp6B,GACxC,IAAIxgB,EAAO,GAEX,GAAKwgB,EAAS5yD,GAAI,UAAa4yD,EAAS5yD,GAAI,cAE3CoyC,EAAOwgB,EAASpzD,UACV,GAAKozD,EAAS5yD,GAAI,UAAW,QAAW4yD,EAAS7zC,aAAc,OAErEqzB,EAAOwgB,EAAS3zC,aAAc,YACxB,GAAK2zC,EAAS5yD,GAAI,UAAW,MAEnCoyC,EAAO,SACD,CAGN,IAAIzZ,EAAO,KAEX,IAAM,MAAMrS,KAASssC,EAASrsC,cAAgB,CAC7C,MAAM0mE,EAAYD,EAAiB1mE,GAG9BqS,IAAUA,EAAK34B,GAAI,qBAAwBsmB,EAAMtmB,GAAI,uBACpDosF,GAAqBnzE,SAAU0f,EAAKh7B,OAAUyuF,GAAqBnzE,SAAUqN,EAAM3oB,MACvFy0C,GAAQ,KAERA,GAAQ,QAIVA,GAAQ66C,EACRt0D,EAAOrS,GAIT,OAAO8rB,EC4HqC46C,CAAiBxtF,EAAKuH,WAG5C,OAAfvH,EAAKma,QACTyC,EAAOysC,MAAM8jB,cAAe0f,EAAcpiE,YAEzC,CAAE3Z,SAAU,SG9JF,MAAM48E,GAMpB,YAAa9wE,GAOZvc,KAAKuc,OAASA,EAgBdvc,KAAKyJ,IAAK,aAASnD,GAyCnBtG,KAAKyJ,IAAK,aAAa,GAQvBzJ,KAAK8qF,cAAgB,IAAIzyE,IAEzBrY,KAAKm2D,SAAU,WAGfn2D,KAAKmR,SAAUnR,KAAKuc,OAAOysC,MAAMhoD,SAAU,SAAU,KACpDhB,KAAK+pE,YAGN/pE,KAAKkpB,GAAI,UAAWpS,IACb9W,KAAKsvC,WACVx4B,EAAIhH,QAEH,CAAEW,SAAU,SAGfzQ,KAAKmR,SAAUoL,EAAQ,oBAAqB,CAAEzF,EAAKhZ,EAAMU,KACnDA,EACJwB,KAAKstF,cAAe,gBAEpBttF,KAAKutF,mBAAoB,kBAY5B,UACCvtF,KAAKsvC,WAAY,EAuClB,cAAehtC,GACdtC,KAAK8qF,cAAcl8E,IAAKtM,GAEQ,GAA3BtC,KAAK8qF,cAAc9hF,OACvBhJ,KAAKkpB,GAAI,gBAAiB,GAAc,CAAEzY,SAAU,YACpDzQ,KAAKsvC,WAAY,GASnB,mBAAoBhtC,GACnBtC,KAAK8qF,cAAc/2E,OAAQzR,GAEK,GAA3BtC,KAAK8qF,cAAc9hF,OACvBhJ,KAAK+P,IAAK,gBAAiB,IAC3B/P,KAAK+pE,WAoBP,WAKA,UACC/pE,KAAKsR,iBAmBP,SAAS,GAAcwF,GACtBA,EAAIpD,QAAS,EACboD,EAAIhH,OC/NE,SAAU09E,GAA0BvkC,EAAQwkC,GAClD,IAAM,MAAMtuE,KAAasuE,EACnBtuE,GAAa8pC,EAAOqO,uBAAwBn4C,EAAW,IAAMuuE,oBAC3DvuE,GDuNT3K,GAAK64E,GAAS,IE5NC,MAAM,WAAqBA,GAIzC,UACC,MAAMrkC,EAAQhpD,KAAKuc,OAAOysC,MACpB5hB,EAAM4hB,EAAMhoD,SAElBgoD,EAAM5L,OAAQprB,KAchB,SAAqBg3B,EAAOh3B,EAAQ5H,EAAW6+B,GAC9C,MAAM0kC,EAAmBvjE,EAAUqD,YAC7BwB,EAAQ7E,EAAUmF,gBAClBnB,EAAea,EAAMpO,MAAM9D,OAC3BsR,EAAaY,EAAMnO,IAAI/D,OAG7B,GAAKksC,EAAOG,QAASh7B,IAAkB66B,EAAOG,QAAS/6B,GAStD,YAJMs/D,GAAoBv/D,GAAgBC,GACzC26B,EAAM8jB,cAAe1iD,IAMvB,GAAKujE,EAAmB,CACvB,MAAMC,EAAmBJ,GAA0Bx7D,EAAOg3B,MAAMC,OAAQ7+B,EAAU2Q,iBAClF8yD,GAAY77D,EAAQ/C,EAAMpO,OAC1BmR,EAAO87D,sBAAuBF,OACxB,CACN,MAAMpgB,IAAmBv+C,EAAMpO,MAAMqL,WAAa+C,EAAMnO,IAAI8K,SACtDmiE,EAAgC3/D,GAAgBC,EAEtD26B,EAAM8jB,cAAe1iD,EAAW,CAAEojD,kBAE7BA,IAICugB,EACJF,GAAY77D,EAAQ5H,EAAUyF,OAM9BmC,EAAOyI,aAAcpM,EAAY,KArDlC2/D,CAAYhuF,KAAKuc,OAAOysC,MAAOh3B,EAAQoV,EAAIhd,UAAW4+B,EAAMC,QAC5DjpD,KAAKqU,KAAM,eAAgB,CAAE2d,cA0DhC,SAAS67D,GAAY77D,EAAQi8D,GAC5Bj8D,EAAOziB,MAAO0+E,GACdj8D,EAAOyI,aAAcwzD,EAASlxE,OAAOmR,YAAa,GCrEpC,MAAM,WAAsBmhB,GAC1C,YAAa3Z,GACZ91B,MAAO81B,GAEP,MAAM0R,EAAMpnC,KAAKgB,SAEjBomC,EAAIle,GAAI,UAAW,CAAEpS,EAAKnX,KACzB,GAAKK,KAAKsvC,WAAa3vC,EAAK40B,SAAWlB,GAASM,MAAQ,CAEvD,IAAI1iB,EACJm2B,EAAI+sC,KAAM,QAASr9D,GAAS7F,EAAQ6F,EAAO,CAAErG,SAAU,YAEvD22B,EAAI/yB,KAAM,QAAS,IAAI,GAAc+yB,EAAKznC,EAAK+zC,SAAU,CACxDw6C,OAAQvuF,EAAK+0B,YAKTzjB,GAASA,EAAMnB,KAAKF,QACxBkH,EAAIhH,UASR,YCxBc,MAAM,WAAc,GAIlC,wBACC,MAAO,QAGR,OACC,MAAMyM,EAASvc,KAAKuc,OACdmZ,EAAOnZ,EAAO83D,QAAQ3+C,KACtB6nC,EAAe7nC,EAAK10B,SAE1B00B,EAAKknB,YAAa,IAElBrgC,EAAO24C,SAAStmD,IAAK,QAAS,IAAI,GAAc2N,IAEhDvc,KAAKmR,SAAUosD,EAAc,QAAS,CAAEzmD,EAAKnX,KAC5CA,EAAKi0C,iBAGAj0C,EAAKuuF,SAIV3xE,EAAO04C,QAAS,SAChBv/B,EAAKm3D,yBACH,CAAEp8E,SAAU,SC/BF,MAAM,WAA0B48E,GAI9C,UACC,MAAMrkC,EAAQhpD,KAAKuc,OAAOysC,MACpB5hB,EAAM4hB,EAAMhoD,SAElBgoD,EAAM5L,OAAQprB,KAkDhB,SAA0Bg3B,EAAOh3B,EAAQ5H,GACxC,MAAMujE,EAAmBvjE,EAAUqD,YAC7BwB,EAAQ7E,EAAUmF,gBAClBnB,EAAea,EAAMpO,MAAM9D,OAC3BsR,EAAaY,EAAMnO,IAAI/D,OACvBgxE,EAAgC3/D,GAAgBC,EAEtD,GAAKs/D,EAAmB,CACvB,MAAMC,EAAmBJ,GAA0BxkC,EAAMC,OAAQ7+B,EAAU2Q,iBAC3EozD,GAAanlC,EAAOh3B,EAAQ/C,EAAMnO,KAElCkR,EAAOysC,yBAA0Br0C,EAAUoL,oBAC3CxD,EAAO87D,sBAAuBF,OACxB,CACN,MAAMpgB,IAAmBv+C,EAAMpO,MAAMqL,WAAa+C,EAAMnO,IAAI8K,SAC5Do9B,EAAM8jB,cAAe1iD,EAAW,CAAEojD,kBAK7BugB,EACJI,GAAanlC,EAAOh3B,EAAQ5H,EAAUyF,OAcjC29C,GACJx7C,EAAOyI,aAAcpM,EAAY,IArFlC+/D,CAAiBplC,EAAOh3B,EAAQoV,EAAIhd,WACpCpqB,KAAKqU,KAAM,eAAgB,CAAE2d,aAI/B,UACC,MAAMg3B,EAAQhpD,KAAKuc,OAAOysC,MACpB5hB,EAAM4hB,EAAMhoD,SAElBhB,KAAKsvC,UAQP,SAAoB2Z,EAAQ7+B,GAG3B,GAAKA,EAAU8E,WAAa,EAC3B,OAAO,EAGR,MAAMm/D,EAAYjkE,EAAU+E,OAG5B,IAAMk/D,IAAcplC,EAAOiH,WAAYm+B,EAAW,aACjD,OAAO,EAGR,MAAMp/D,EAAQ7E,EAAUmF,gBAClBnB,EAAea,EAAMpO,MAAM9D,OAC3BsR,EAAaY,EAAMnO,IAAI/D,OAG7B,IAAOuxE,GAAsBlgE,EAAc66B,IAAYqlC,GAAsBjgE,EAAY46B,KAAc76B,IAAiBC,EACvH,OAAO,EAGR,OAAO,EA/BW,CAAW26B,EAAMC,OAAQ7hB,EAAIhd,YAkFhD,SAAS+jE,GAAanlC,EAAOh3B,EAAQnH,GACpC,MAAM0jE,EAAmBv8D,EAAO3uB,cAAe,aAE/C2lD,EAAM6pB,cAAe0b,EAAkB1jE,GACvCmH,EAAOyI,aAAc8zD,EAAkB,SAYxC,SAASD,GAAsB1vE,EAASqqC,GAEvC,OAAKrqC,EAAQze,GAAI,iBAIV8oD,EAAOG,QAASxqC,IAAa0vE,GAAsB1vE,EAAQ7B,OAAQksC,ICtH5D,MAAM,WAAmB,GAIvC,wBACC,MAAO,aAGR,OACC,MAAM1sC,EAASvc,KAAKuc,OACd0sC,EAAS1sC,EAAOysC,MAAMC,OACtBqrB,EAAa/3D,EAAO+3D,WACpB5+C,EAAOnZ,EAAO83D,QAAQ3+C,KACtB6nC,EAAe7nC,EAAK10B,SAG1BioD,EAAOipB,SAAU,YAAa,CAC7BvY,WAAY,QACZ9M,UAAU,IAIXynB,EAAWjV,IAAK,UACdC,iBAAkB,CAClBtW,MAAO,YACPtzB,KAAM,OAGR4+C,EAAWjV,IAAK,YACdC,iBAAkB,CAClBtW,MAAO,YACPtzB,KAAM,CAAEstB,GAAgBhxB,YAAcA,EAAOw8D,mBAAoB,QAGnE94D,EAAKknB,YAAa,IAElBrgC,EAAO24C,SAAStmD,IAAK,aAAc,IAAI,GAAmB2N,IAE1Dvc,KAAKmR,SAAUosD,EAAc,QAAS,CAAEzmD,EAAKnX,KAC5CA,EAAKi0C,iBAGCj0C,EAAKuuF,SAIX3xE,EAAO04C,QAAS,cAChBv/B,EAAKm3D,yBACH,CAAEp8E,SAAU,SC3CF,MAAM,WAAyB48E,GAI7C,UACC,MAAMrkC,EAAQhpD,KAAKuc,OAAOysC,MACpB5+B,EAAY4+B,EAAMhoD,SAASopB,UACjC,IAAIqkE,EAAezlC,EAAMC,OAAOgkB,gBAAiB7iD,GAIjD,GAAKA,EAAU6/B,sBAAuBwkC,KAAmBC,GAAkB1lC,EAAMC,OAAQwlC,GACxF,GAIC,GAHAA,EAAeA,EAAa1xE,QAGtB0xE,EACL,cAESC,GAAkB1lC,EAAMC,OAAQwlC,IAG5CzlC,EAAM5L,OAAQprB,IACbA,EAAOyI,aAAcg0D,EAAc,SAYtC,SAASC,GAAkBzlC,EAAQrqC,GAClC,OAAOqqC,EAAOG,QAASxqC,KAAeqqC,EAAOiH,WAAYtxC,EAAS,UAAaqqC,EAAOiH,WAAYtxC,EAAS,cClD5G,MAAM+vE,GAAuBh6D,GAAgB,UAU9B,MAAM,WAAyB,GAI7C,wBACC,MAAO,mBAMR,OACC,MAAMpY,EAASvc,KAAKuc,OAEdghD,EADOhhD,EAAO83D,QAAQ3+C,KACF10B,SAE1Bub,EAAO24C,SAAStmD,IAAK,YAAa,IAAI,GAAkB2N,IAExDvc,KAAKmR,SAAUosD,EAAc,UAAW,CAAEvqD,EAAW47E,KAC/Ct6D,GAASs6D,KAAmBD,KAChCpyE,EAAO04C,QAAS,aAChB25B,EAAah7C,qBCrBF,MAAM,WAAoB,GAIxC,wBACC,MAAO,cAMR,OACC,MAAMr3B,EAASvc,KAAKuc,OAEpBA,EAAOL,GAAG+5D,iBAAiBrnE,IAAK,YAAaqN,IAC5C,MAAM+4C,EAAUz4C,EAAO24C,SAAS92D,IAAK,aAC/Bs3B,EAAO,IAAI,GAAYzZ,GACvBxd,EAAIwd,EAAOxd,EAiBjB,OAfAi3B,EAAKjsB,IAAK,CACTinB,MAAOjyB,EAAG,cACV2nF,KC5CW,gkDD6CXxxD,UAAW,SACX0xD,SAAS,IAGV5wD,EAAK32B,KAAM,OAAQ,aAAc6U,GAAIohD,EAAS,QAAS,aAGvDh1D,KAAKmR,SAAUukB,EAAM,UAAW,KAC/BnZ,EAAO04C,QAAS,aAChB14C,EAAO83D,QAAQ3+C,KAAK7F,UAGd6F,KElCK,MAAM,WAAkB,GAItC,sBACC,MAAO,CAAE,GAAkB,IAM5B,wBACC,MAAO,aCRM,MAAMm5D,GAOpB,YAAa7lC,EAAO8lC,EAAQ,IAO3B9uF,KAAKgpD,MAAQA,EASbhpD,KAAKgJ,KAAO,EAQZhJ,KAAK8uF,MAAQA,EAQb9uF,KAAK+uF,UAAW,EAQhB/uF,KAAKgvF,gBAAkB,CAAEl4E,EAAKq0C,KACV,eAAdA,EAAMlrD,MAAyBkrD,IAAUnrD,KAAKivF,QAClDjvF,KAAKkvF,QAAQ,IAIflvF,KAAKmvF,yBAA2B,KAC/BnvF,KAAKkvF,UAGNlvF,KAAKgpD,MAAMhoD,SAASkoB,GAAI,SAAUlpB,KAAKgvF,iBAEvChvF,KAAKgpD,MAAMhoD,SAASopB,UAAUlB,GAAI,eAAgBlpB,KAAKmvF,0BACvDnvF,KAAKgpD,MAAMhoD,SAASopB,UAAUlB,GAAI,mBAAoBlpB,KAAKmvF,0BA8B5D,YAKC,OAJMnvF,KAAKivF,SACVjvF,KAAKivF,OAASjvF,KAAKgpD,MAAMomC,eAGnBpvF,KAAKivF,OASb,MAAO7nB,GACNpnE,KAAKgJ,MAAQo+D,EAERpnE,KAAKgJ,MAAQhJ,KAAK8uF,OACtB9uF,KAAKkvF,QAAQ,GAOf,OACClvF,KAAK+uF,UAAW,EAMjB,SACC/uF,KAAK+uF,UAAW,EAMjB,UACC/uF,KAAKgpD,MAAMhoD,SAAS+O,IAAK,SAAU/P,KAAKgvF,iBACxChvF,KAAKgpD,MAAMhoD,SAASopB,UAAUra,IAAK,eAAgB/P,KAAKmvF,0BACxDnvF,KAAKgpD,MAAMhoD,SAASopB,UAAUra,IAAK,mBAAoB/P,KAAKmvF,0BAS7D,OAAQE,GACDrvF,KAAK+uF,WAAYM,IACtBrvF,KAAKivF,OAAS,KACdjvF,KAAKgJ,KAAO,ICzJA,MAAM,WAAqBqkF,GAQzC,YAAa9wE,EAAQ+yE,GACpB1vF,MAAO2c,GASPvc,KAAKuvF,QAAU,IAAIV,GAActyE,EAAOysC,MAAOsmC,GAS/CtvF,KAAKwvF,SAAW,IAAI5mD,QAQrB,aACC,OAAO5oC,KAAKuvF,QAMb,UACC3vF,MAAMsa,UAENla,KAAKuvF,QAAQr1E,UAiBd,QAAShY,EAAU,IAClB,MAAM8mD,EAAQhpD,KAAKuc,OAAOysC,MACpB5hB,EAAM4hB,EAAMhoD,SACZuxC,EAAOrwC,EAAQqwC,MAAQ,GACvBk9C,EAAiBl9C,EAAKxwC,OACtBqoB,EAAYloB,EAAQ+sB,MAAQ+5B,EAAMsL,gBAAiBpyD,EAAQ+sB,OAAUmY,EAAIhd,UACzEslE,EAAcxtF,EAAQwtF,YAE5B1mC,EAAMqC,cAAerrD,KAAKuvF,QAAQpkC,MAAOn5B,IACxChyB,KAAKuvF,QAAQI,OAGb3vF,KAAKwvF,SAAS5gF,IAAK5O,KAAKuvF,QAAQpkC,OAEhCnC,EAAM8jB,cAAe1iD,GAEhBmoB,GACJyW,EAAM6pB,cAAe7gD,EAAOwiC,WAAYjiB,EAAMnL,EAAIhd,UAAU2Q,iBAAmB3Q,GAG3EslE,EACJ19D,EAAOyI,aAAci1D,GACTtlE,EAAUjqB,GAAI,sBAC1B6xB,EAAOyI,aAAcrQ,GAGtBpqB,KAAKuvF,QAAQK,SAEb5vF,KAAKuvF,QAAQriF,MAAOuiF,MCevB,MAAMI,GAAe,CACpBv7D,GAAS,WACTA,GAAS,cACTA,GAAS,aACTA,GAAS,aACT,EACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,KAID,IAAM,IAAIJ,EAAO,IAAKA,GAAQ,IAAKA,IAClC27D,GAAa5sF,KAAMixB,GAgBb,SAAS47D,GAAsBC,GAErC,QAAKA,EAAQt7D,SAINo7D,GAAaz2E,SAAU22E,EAAQx7D,SCtIhC,SAASy7D,GAAyB39C,GAExC,GAAKA,EAASY,YAAYlxC,OAASswC,EAASW,YAAYjxC,QAAU,EACjE,OAID,MACMujD,ECpBQ,SAAwB5iB,EAAMutD,GAC5C,MAAM3qC,EAAU,GAChB,IACI4qC,EADAxtF,EAAQ,EAuCZ,OApCAggC,EAAKj/B,QAAS25C,IACE,SAAVA,GACJ+yC,IAEAztF,KACqB,UAAV06C,GACNgzC,EAAkB,UACtBF,EAAc7jF,OAAOpJ,KAAMgtF,EAAQvtF,KAEnCytF,IAEAD,EAAgB,CACfjwF,KAAM,SACNyC,QACA2J,OAAQ,CAAE4jF,EAAQvtF,MAIpBA,KAEK0tF,EAAkB,UACtBF,EAAcjpE,WAEdkpE,IAEAD,EAAgB,CACfjwF,KAAM,SACNyC,QACAukB,QAAS,MAMbkpE,IAEO7qC,EAEP,SAAS6qC,IACHD,IACJ5qC,EAAQriD,KAAMitF,GACdA,EAAgB,MAIlB,SAASE,EAAkBC,GAC1B,OAAOH,GAAiBA,EAAcjwF,MAAQowF,GD/B/BC,CADG,GAAMj+C,EAASW,YAAaX,EAASY,YAAas9C,IAC1Bl+C,EAASY,aAGpD,GAAKqS,EAAQvjD,OAAS,EACrB,OAGD,MAAMq7C,EAASkI,EAAS,GAGxB,OAAUlI,EAAO/wC,OAAQ,IAAO+wC,EAAO/wC,OAAQ,GAAIlM,GAAI,SAIhDi9C,OAJP,EAgBM,SAASmzC,GAAmBC,EAAUC,GAC5C,OAAOD,GAAYA,EAASrwF,GAAI,UAAeswF,GAAYA,EAAStwF,GAAI,SAChEqwF,EAAS7wF,OAAS8wF,EAAS9wF,KAE3B6wF,IAAaC,EEpDtB,MAAM,GAML,YAAal0E,GAOZvc,KAAKuc,OAASA,EAQdvc,KAAKq0E,QAAUr0E,KAAKuc,OAAO83D,QAU5B,OAAQqc,EAAWl2D,GAClB,GF1CK,SAAmCk2D,GACzC,GAAyB,GAApBA,EAAU3uF,OACd,OAAO,EAIR,IAAM,MAAMswC,KAAYq+C,EACvB,GAAuB,aAAlBr+C,EAASpyC,OAAwB+vF,GAAyB39C,GAC9D,OAAO,EAIT,OAAO,EE8BDs+C,CAA0BD,GAC9B1wF,KAAK4wF,kCAAmCF,EAAWl2D,QAEnD,IAAM,MAAM6X,KAAYq+C,EAEvB1wF,KAAK6wF,oBAAqBx+C,EAAU7X,GACpCx6B,KAAK8wF,yBAA0Bz+C,GAuBlC,kCAAmCq+C,EAAWl2D,GAE7C,MAAMu2D,EA4KR,SAAgCL,GAC/B,MAAMhjD,EAAMgjD,EACVrmF,IAAKgoC,GAAYA,EAAS9/B,MAC1B8E,OAAQ,CAAE22D,EAAgBz7D,IACnBy7D,EAAe//C,kBAAmB1b,EAAM,CAAE6K,aAAa,KAGhE,IAAMswB,EACL,OAKD,OAAOA,EAAIlwB,aAAc,CAAEJ,aAAa,EAAMC,aAAa,IACzDjH,KAAMwI,GAAWA,EAAQze,GAAI,qBAAwBye,EAAQze,GAAI,gBA1LlC6wF,CAAuBN,GAGvD,IAAMK,EACL,OAGD,MAGME,EAHejxF,KAAKuc,OAAO83D,QAAQ3+C,KAAKC,aAGC6L,aAAcuvD,GAIvDG,EAAoB,IAAI,GAAclxF,KAAKuc,OAAO83D,QAAQ3+C,KAAK10B,UAC/DmwF,EAAsBnxF,KAAKuc,OAAO5c,KAAK++D,QAC5CwyB,EAAkBtsD,UAAWqsD,IAC5B/zE,SAAU,GAGNk0E,EAAepxF,KAAKuc,OAAO83D,QAAQ1wB,OAAOV,eAAgB8tC,GAQhE,IAAMK,EACL,OAID,MAAMC,EAAuBloF,MAAMiK,KAAM+9E,EAAoBzqE,eACvD4qE,EAAuBnoF,MAAMiK,KAAMg+E,EAAa1qE,eAIhD6qE,EAAeF,EAAsBA,EAAqBtvF,OAAS,GACnEyvF,EAAmBF,EAAsBA,EAAqBvvF,OAAS,GAEvE0vF,EAA0BF,GAAgBA,EAAapxF,GAAI,UAAW,aACtEuxF,EAA8BF,IAAqBA,EAAiBrxF,GAAI,UAAW,aAEpFsxF,GAA2BC,GAC/BL,EAAqBjoF,MAGtB,MAAM6/C,EAASjpD,KAAKuc,OAAOysC,MAAMC,OAGjC,IAAM0oC,GAAuBN,EAAsBpoC,KAAa0oC,GAAuBL,EAAsBroC,GAC5G,OAOD,MAAMxW,EAAU4+C,EAAqBhnF,IAAKhI,GAAQA,EAAKlC,GAAI,SAAYkC,EAAK1C,KAAO,KAAMsE,KAAM,IAAKiG,QAAS,UAAW,KAClHsoC,EAAU8+C,EAAqBjnF,IAAKhI,GAAQA,EAAKlC,GAAI,SAAYkC,EAAK1C,KAAO,KAAMsE,KAAM,IAAKiG,QAAS,UAAW,KAGxH,GAAKsoC,IAAYC,EAChB,OAGD,MAAMm/C,EAAa,GAAMp/C,EAASC,IAE5B,cAAEo/C,EAAa,WAAEC,EAAU,UAAEC,GAAcC,GAAkBJ,GAGnE,IAAIK,EAAsB,KAErBz3D,IACJy3D,EAAsBjyF,KAAKq0E,QAAQ1wB,OAAOyQ,aAAc55B,EAAcjL,kBAGvE,MAAM2iE,EAAaz/C,EAAQpgC,OAAQw/E,EAAeC,GAC5C9hB,EAAchwE,KAAKuc,OAAOysC,MAAM1iB,YACrCtmC,KAAKuc,OAAOysC,MAAMoI,iBAAkBggC,EAAcS,GAClD7xF,KAAKuc,OAAOysC,MAAMoI,iBAAkBggC,EAAcS,EAAgBE,IAGnE/xF,KAAKuc,OAAO04C,QAAS,QAAS,CAC7B1iB,KAAM2/C,EACNjjE,MAAO+gD,EACP0f,YAAauC,IAOf,oBAAqB5/C,EAAU7X,GAC9B,GAAsB,QAAjB6X,EAASpyC,KACb,OAYD,MAAMwyC,EAAUJ,EAASI,QAAQvoC,QAAS,UAAW,KAE/CsoC,EAAUH,EAASG,QAAQtoC,QAAS,UAAW,KAGrD,GAAKsoC,IAAYC,EAChB,OAGD,MAAMm/C,EAAa,GAAMp/C,EAASC,IAE5B,cAAEo/C,EAAa,WAAEC,EAAU,UAAEC,GAAcC,GAAkBJ,GAGnE,IAAIK,EAAsB,KAErBz3D,IACJy3D,EAAsBjyF,KAAKq0E,QAAQ1wB,OAAOyQ,aAAc55B,EAAcjL,kBAIvE,MAAM4iE,EAAUnyF,KAAKq0E,QAAQ3+C,KAAK07B,iBAAkB/e,EAAS9/B,KAAMs/E,GAC7DO,EAAWpyF,KAAKq0E,QAAQ1wB,OAAOH,gBAAiB2uC,GAChDniB,EAAchwE,KAAKuc,OAAOysC,MAAM1iB,YAAa8rD,EAAUA,EAAS9jE,aAAcyjE,IAC9EG,EAAaz/C,EAAQpgC,OAAQw/E,EAAeC,GAElD9xF,KAAKuc,OAAO04C,QAAS,QAAS,CAC7B1iB,KAAM2/C,EACNjjE,MAAO+gD,EACP0f,YAAauC,IAOf,yBAA0B5/C,GACzB,GAAsB,YAAjBA,EAASpyC,KACb,OAGD,MAAMm9C,EAAS4yC,GAAyB39C,GAClC8/C,EAAUnyF,KAAKq0E,QAAQ3+C,KAAK07B,iBAAkB/e,EAAS9/B,KAAM6qC,EAAO16C,OACpE0vF,EAAWpyF,KAAKq0E,QAAQ1wB,OAAOH,gBAAiB2uC,GAChDE,EAAej1C,EAAO/wC,OAAQ,GAAI1M,KAExCK,KAAKuc,OAAO04C,QAAS,QAAS,CAK7B1iB,KAAM8/C,EAAanoF,QAAS,UAAW,KACvC+kB,MAAOjvB,KAAKuc,OAAOysC,MAAM1iB,YAAa8rD,MAkCzC,SAAST,GAAuB7pF,EAAUmhD,GACzC,OAAOnhD,EAASoiB,MAAOzD,GAASwiC,EAAO4D,SAAUpmC,IAQlD,SAASurE,GAAkBJ,GAE1B,IAAIC,EAAgB,KAEhBS,EAAe,KAGnB,IAAM,IAAI/0F,EAAI,EAAGA,EAAIq0F,EAAW7vF,OAAQxE,IAAM,CAG9B,SAFAq0F,EAAYr0F,KAG1Bs0F,EAAkC,OAAlBA,EAAyBt0F,EAAIs0F,EAC7CS,EAAe/0F,GAKjB,IAAIw0F,EAAY,EAEZD,EAAa,EAEjB,IAAM,IAAIv0F,EAAIs0F,EAAet0F,GAAK+0F,EAAc/0F,IAEvB,UAAnBq0F,EAAYr0F,IAChBw0F,IAIuB,UAAnBH,EAAYr0F,IAChBu0F,IAIF,MAAO,CAAEA,aAAYC,YAAWF,iBCrTlB,MAAM,WAAc,GAIlC,wBACC,MAAO,QAMR,OACC,MAAMt1E,EAASvc,KAAKuc,OAGdg2E,EAAe,IAAI,GAAch2E,EAAQA,EAAOV,OAAOzd,IAAK,oBAAuB,IAEzFme,EAAO24C,SAAStmD,IAAK,QAAS2jF,GJnBjB,SAAyCh2E,GACvD,IAAIi2E,EAA6B,KAEjC,MAAMxpC,EAAQzsC,EAAOysC,MACftzB,EAAOnZ,EAAO83D,QAAQ3+C,KACtB68D,EAAeh2E,EAAO24C,SAAS92D,IAAK,SA2B1C,SAASq0F,EAAuBze,GAC/B,MAAM5sC,EAAM4hB,EAAMhoD,SACZq2C,EAAc3hB,EAAK10B,SAASq2C,YAC5Bq7C,EAAuBF,GAA8BA,EAA2BlmE,QAAS8a,EAAIhd,WAGnGooE,EAA6B,KAOvBD,EAAajjD,YAIdwgD,GAAsB9b,IAAa5sC,EAAIhd,UAAUqD,aAKjD4pB,GAAmC,MAApB28B,EAAQz/C,UAOtB8iB,GAAmC,MAApB28B,EAAQz/C,SAAmBm+D,GAIhDC,KAwBD,SAASA,IACR,MAAMprF,EAASgrF,EAAahrF,OAE5BA,EAAOooF,OAEP,MAAMxkC,EAAQ5jD,EAAO4jD,MACrBonC,EAAa/C,SAAS5gF,IAAKu8C,GAE3BnC,EAAMqC,cAAeF,EAAO,KAC3BnC,EAAM8jB,cAAe9jB,EAAMhoD,SAASopB,aAGrC7iB,EAAOqoF,SA7FH,GAAI/8D,UACR6C,EAAK10B,SAASkoB,GAAI,cAAe,CAAEpS,EAAKk9D,IAAaye,EAAuBze,GAAW,CAAEvjE,SAAU,WAEnGilB,EAAK10B,SAASkoB,GAAI,UAAW,CAAEpS,EAAKk9D,IAAaye,EAAuBze,GAAW,CAAEvjE,SAAU,WAGhGilB,EAAK10B,SAASkoB,GAAI,oBA4DlB,WACC,MAAMke,EAAM4hB,EAAMhoD,SACZ4xF,EAA+C,IAA7BxrD,EAAIhd,UAAU8E,YAAmBkY,EAAIhd,UAAUmF,gBAAgBhhB,OAMvF,GAAK64B,EAAIhd,UAAUqD,aAAemlE,EACjC,OAGDD,MAxE6D,CAAEliF,SAAU,WAE1EilB,EAAK10B,SAASkoB,GAAI,iBAAkB,KACnCspE,EAA6BxpC,EAAMsL,gBAAiBtL,EAAMhoD,SAASopB,YACjE,CAAE3Z,SAAU,WIGdoiF,CAAgCt2E,GDpBnB,SAAwCA,GACtDA,EAAO83D,QAAQ3+C,KAAK10B,SAASkoB,GAAI,YAAa,CAAEpS,EAAK45E,EAAWl2D,KAC/D,IAAI,GAAiBje,GAASu2E,OAAQpC,EAAWl2D,KCmBjDu4D,CAA+Bx2E,GAoBhC,QAAS4uC,GAGR,OAFqBnrD,KAAKuc,OAAO24C,SAAS92D,IAAK,SAE3BoxF,SAAS9lF,IAAKyhD,IC3CrB,MAAM,WAAsBkiC,GAQ1C,YAAa9wE,EAAQqO,GACpBhrB,MAAO2c,GASPvc,KAAK4qB,UAAYA,EASjB5qB,KAAKuvF,QAAU,IAAIV,GAActyE,EAAOysC,MAAOzsC,EAAOV,OAAOzd,IAAK,oBAQnE,aACC,OAAO4B,KAAKuvF,QAeb,QAASrtF,EAAU,IAClB,MAAM8mD,EAAQhpD,KAAKuc,OAAOysC,MACpB5hB,EAAM4hB,EAAMhoD,SAElBgoD,EAAMqC,cAAerrD,KAAKuvF,QAAQpkC,MAAOn5B,IACxChyB,KAAKuvF,QAAQI,OAEb,MAAMvlE,EAAY4H,EAAOsiC,gBAAiBpyD,EAAQkoB,WAAagd,EAAIhd,WAO7D4iD,EAA0B5iD,EAAUqD,YAQ1C,GALKrD,EAAUqD,aACdu7B,EAAMskB,gBAAiBljD,EAAW,CAAEQ,UAAW5qB,KAAK4qB,UAAWukD,KAAMjtE,EAAQitE,OAIzEnvE,KAAKgzF,4CAA6C9wF,EAAQ+wF,UAAY,GAG1E,YAFAjzF,KAAKkzF,mCAAoClhE,GAM1C,GAAK5H,EAAUqD,YACd,OAGD,IAAI25C,EAAc,EAElBh9C,EAAUmF,gBAAgBkoC,uBAAuBh0D,QAASwrB,IACzDm4C,GAAe,GACdn4C,EAAMgL,UAAW,CAAElP,kBAAkB,EAAME,kBAAkB,EAAMD,SAAS,OAI9Eg+B,EAAM8jB,cAAe1iD,EAAW,CAC/B4iD,0BACApiD,UAAW5qB,KAAK4qB,YAGjB5qB,KAAKuvF,QAAQriF,MAAOk6D,GAEpBp1C,EAAOyI,aAAcrQ,GAErBpqB,KAAKuvF,QAAQK,WAsBf,4CAA6CqD,GAE5C,GAAKA,EAAW,EACf,OAAO,EAGR,MAAMjqC,EAAQhpD,KAAKuc,OAAOysC,MAEpB5+B,EADM4+B,EAAMhoD,SACIopB,UAChB0tC,EAAe9O,EAAMC,OAAOgkB,gBAAiB7iD,GAMnD,KAF4BA,EAAUqD,aAAerD,EAAU6/B,sBAAuB6N,IAGrF,OAAO,EAGR,IAAM9O,EAAMC,OAAOiH,WAAY4H,EAAc,aAC5C,OAAO,EAGR,MAAMq7B,EAAyBr7B,EAAa56C,SAAU,GAKtD,OAAKi2E,GAA0D,cAAhCA,EAAuBr1F,KAYvD,mCAAoCk0B,GACnC,MAAMg3B,EAAQhpD,KAAKuc,OAAOysC,MAEpB5+B,EADM4+B,EAAMhoD,SACIopB,UAChB0tC,EAAe9O,EAAMC,OAAOgkB,gBAAiB7iD,GAC7C+mC,EAAYn/B,EAAO3uB,cAAe,aAExC2uB,EAAO7tB,OAAQ6tB,EAAO0iC,cAAeoD,IACrC9lC,EAAOruB,OAAQwtD,EAAW2G,GAE1B9lC,EAAOyI,aAAc02B,EAAW,IC9KnB,MAAM,WAAuB9hB,GAC3C,YAAa3Z,GACZ91B,MAAO81B,GAEP,MAAM10B,EAAW00B,EAAK10B,SACtB,IAAIiyF,EAAW,EAyDf,SAASG,EAAqBC,EAAe3/C,EAAUpP,GAEtD,IAAIrzB,EACJjQ,EAASmzE,KAAM,SAAUr9D,GAAS7F,EAAQ6F,EAAO,CAAErG,SAAUyK,OAAOkhB,oBAEpEp7B,EAASqT,KAAM,SAAU,IAAI,GAAcrT,EAAU0yC,EAAUpP,IAI1DrzB,GAASA,EAAMnB,KAAKF,QACxByjF,EAAcvjF,OAjEhB9O,EAASkoB,GAAI,QAAS,CAAEpS,EAAKnX,KACvBA,EAAK40B,SAAWlB,GAAStf,QAAUpU,EAAK40B,SAAWlB,GAASK,YAChEu/D,EAAW,KAIbjyF,EAASkoB,GAAI,UAAW,CAAEpS,EAAKnX,KAC9B,MAAM2kC,EAAa,GAEnB,GAAK3kC,EAAK40B,SAAWlB,GAAStf,OAC7BuwB,EAAW1Z,UAAY,UACvB0Z,EAAW6qC,KAAO,gBACZ,IAAKxvE,EAAK40B,SAAWlB,GAASK,UAIpC,OAHA4Q,EAAW1Z,UAAY,WACvB0Z,EAAW6qC,KAAO,YAKnB,MAAMmkB,EAAkB,GAAI5gE,MAAQ/yB,EAAK60B,OAAS70B,EAAK80B,QACvD6P,EAAW6qC,KAAOmkB,EAAkB,OAAShvD,EAAW6qC,KACxD7qC,EAAW2uD,WAAaA,EAExBG,EAAqBt8E,EAAKnX,EAAK+zC,SAAUpP,KAIrC,GAAIzR,WACR7xB,EAASkoB,GAAI,cAAe,CAAEpS,EAAKnX,KAElC,GAAgC,yBAA3BA,EAAK+zC,SAAS6/C,UAClB,OAGD,MAAMjvD,EAAa,CAClB6qC,KAAM,YACNvkD,UAAW,WACXqoE,SAAU,GAQLr9D,EAAej2B,EAAKk2B,UAAUC,cAAcC,YAAYC,eAEzDJ,EAAasR,YAActR,EAAaS,WAAaT,EAAaqW,aAAe,GAAKrW,EAAaW,cACvG+N,EAAWkvD,kBAAoB99D,EAAKC,aAAasR,mBAAoBrR,IAGtEw9D,EAAqBt8E,EAAKnX,EAAK+zC,SAAUpP,KAsB5C,YChFc,MAAM,WAAe,GAInC,wBACC,MAAO,SAGR,OACC,MAAM/nB,EAASvc,KAAKuc,OACdmZ,EAAOnZ,EAAO83D,QAAQ3+C,KACtB6nC,EAAe7nC,EAAK10B,SAuC1B,GArCA00B,EAAKknB,YAAa,IAElBrgC,EAAO24C,SAAStmD,IAAK,gBAAiB,IAAI,GAAe2N,EAAQ,YACjEA,EAAO24C,SAAStmD,IAAK,SAAU,IAAI,GAAe2N,EAAQ,aAE1Dvc,KAAKmR,SAAUosD,EAAc,SAAU,CAAEzmD,EAAKnX,KAC7C,MAAM8zF,EAAsB,CAAEtkB,KAAMxvE,EAAKwvE,KAAM8jB,SAAUtzF,EAAKszF,UAG9D,GAAKtzF,EAAK6zF,kBAAoB,CAC7B,MAAMn/B,EAAiB93C,EAAOysC,MAAMsL,kBAC9BzmC,EAAS,GAEf,IAAM,MAAM0b,KAAa5pC,EAAK6zF,kBAAkBtjE,YAC/CrC,EAAO5qB,KAAMsZ,EAAO83D,QAAQ1wB,OAAOyQ,aAAc7qB,IAGlD8qB,EAAepuC,MAAO4H,GAEtB4lE,EAAoBrpE,UAAYiqC,EAGjC93C,EAAO04C,QAA2B,WAAlBt1D,EAAKirB,UAAyB,gBAAkB,SAAU6oE,GAE1E9zF,EAAKi0C,iBAELle,EAAKm3D,yBAWD,GAAIh6D,UAAY,CACpB,IAAI6gE,EAA4B,KAEhC1zF,KAAKmR,SAAUosD,EAAc,SAAU,CAAEzmD,EAAKnX,KAC7C,MAAMi2B,EAAej2B,EAAKk2B,UAAUC,cAAcC,YAAYC,eAE9D09D,EAA4B,CAC3BxsD,WAAYtR,EAAasR,WACzB+E,aAAcrW,EAAaqW,aAC3B5V,UAAWT,EAAaS,UACxBE,YAAaX,EAAaW,cAEzB,CAAE9lB,SAAU,WAEfzQ,KAAKmR,SAAUosD,EAAc,QAAS,CAAEzmD,EAAKnX,KAC5C,GAAK+zF,EAA4B,CAChC,MAAM99D,EAAej2B,EAAKk2B,UAAUC,cAAcC,YAAYC,eAE9DJ,EAAakB,SAAU48D,EAA0BxsD,WAAYwsD,EAA0BznD,cACvFrW,EAAamB,OAAQ28D,EAA0Br9D,UAAWq9D,EAA0Bn9D,aAEpFm9D,EAA4B,UCrElB,MAAM,WAAe,GACnC,sBACC,MAAO,CAAE,GAAO,IAMjB,wBACC,MAAO,UCXT,MAAMC,GAAkB,IAAI7/E,IAwB5B,SAAS8/E,GAAmBC,EAAYC,EAAYC,GACnD,IAAIC,EAASL,GAAgBv1F,IAAKy1F,GAE5BG,IACLA,EAAS,IAAIlgF,IACb6/E,GAAgBlqF,IAAKoqF,EAAYG,IAGlCA,EAAOvqF,IAAKqqF,EAAYC,GAgCzB,SAASE,GAAwBt3E,GAChC,MAAO,CAAEA,GAWH,SAAS,GAAWA,EAAGC,EAAGld,EAAU,IAC1C,MAAMq0F,EA9BP,SAA4BF,EAAYC,GACvC,MAAME,EAASL,GAAgBv1F,IAAKy1F,GAEpC,OAAKG,GAAUA,EAAOtqF,IAAKoqF,GACnBE,EAAO51F,IAAK01F,GAGbG,GAuBwBC,CAAmBv3E,EAAEjV,YAAakV,EAAElV,aAGnE,IAGC,OAAOqsF,EAFPp3E,EAAIA,EAAE+O,QAE4B9O,EAAGld,GACpC,MAAQgC,GAUT,MAAMA,GA0CD,SAASyyF,GAAeC,EAAaC,EAAanyF,GAGxDkyF,EAAcA,EAAY3sF,QAC1B4sF,EAAcA,EAAY5sF,QAE1B,MAAM6sF,EAAiB,IAAI,GAAgBpyF,EAAQlB,SAAUkB,EAAQqyF,aAAcryF,EAAQsyF,iBAC3FF,EAAeG,sBAAuBL,GACtCE,EAAeG,sBAAuBJ,GAEtC,MAAMK,EAAqBJ,EAAeI,mBAG1C,GAA2B,GAAtBN,EAAYryF,QAAqC,GAAtBsyF,EAAYtyF,OAC3C,MAAO,CAAEqyF,cAAaC,cAAaK,sBAqIpC,MAAMC,EAAqB,IAAIr/E,QAG/B,IAAM,MAAM0qD,KAAMo0B,EACjBO,EAAmBlrF,IAAKu2D,EAAI,GAI7B,MAAMrgE,EAAO,CACZi1F,iBAAkBR,EAAaA,EAAYryF,OAAS,GAAIk+D,YAAc,EACtE40B,iBAAkBR,EAAaA,EAAYtyF,OAAS,GAAIk+D,YAAc,EACtE60B,yBAA0BV,EAAYryF,OACtCgzF,yBAA0BV,EAAYtyF,QAIvC,IAAIxE,EAAI,EAGR,KAAQA,EAAI62F,EAAYryF,QAAS,CAEhC,MAAMizF,EAAMZ,EAAa72F,GAGnB03F,EAASN,EAAmBv2F,IAAK42F,GAGvC,GAAKC,GAAUZ,EAAYtyF,OAAS,CACnCxE,IACA,SAGD,MAAM23F,EAAMb,EAAaY,GAGnBE,EAAU,GAAWH,EAAKE,EAAKZ,EAAec,WAAYJ,EAAKE,GAAK,IACpEG,EAAU,GAAWH,EAAKF,EAAKV,EAAec,WAAYF,EAAKF,GAAK,IAI1EV,EAAegB,eAAgBN,EAAKE,GAEpCZ,EAAeG,sBAAuBU,EAASH,GAC/CV,EAAeG,sBAAuBY,EAASH,GAM/C,IAAM,MAAMK,KAAUJ,EAMrBR,EAAmBlrF,IAAK8rF,EAAQN,EAASI,EAAQtzF,QAIlDqyF,EAAYtuF,OAAQvI,EAAG,KAAM43F,GAC7Bd,EAAYvuF,OAAQmvF,EAAQ,KAAMI,GAGnC,GAAKnzF,EAAQszF,aAAe,CAE3B,MAAMC,EAAyBrB,EAAYryF,OAASpC,EAAKm1F,yBACnDY,EAAyBrB,EAAYtyF,OAASpC,EAAKo1F,yBAMzDS,GAAcpB,EAAasB,EAAyBD,GACpDD,GAAcnB,EAAaoB,EAAyBC,GAOrD,OAHAC,GAAoBvB,EAAaz0F,EAAKk1F,kBACtCc,GAAoBtB,EAAa10F,EAAKi1F,kBAE/B,CAAER,cAAaC,cAAaK,sBAKpC,MAAM,GAQL,YAAa1zF,EAAUuzF,EAAcC,GAAkB,GAMtDx0F,KAAK00F,mBAAqB,IAAI5gF,IAG9B9T,KAAK41F,SAAW50F,EAAS0oE,QAGzB1pE,KAAK61F,cAAgBtB,EAErBv0F,KAAK81F,mBAAqBtB,EAK1Bx0F,KAAK+1F,WAAa,IAAIjiF,IAqBvB,sBAAuBotC,EAAY80C,EAAW,MAC7C,MAAMC,EAAoBD,EAAWh2F,KAAK00F,mBAAmBt2F,IAAK43F,GAAa,KAE/E,IAAM,MAAMt2C,KAAawB,EACxBlhD,KAAK00F,mBAAmBjrF,IAAKi2C,EAAWu2C,GAAqBv2C,GAU/D,eAAgBs1C,EAAKE,GAQpB,OAASF,EAAIttF,aACZ,KAAK,GACJ,OAASwtF,EAAIxtF,aACZ,KAAK,GACCstF,EAAI18D,eAAehM,QAAS4oE,EAAIj1C,iBAAoBi1C,EAAIh1C,WAAWvyB,iBAAkBqnE,EAAI18D,gBAC7Ft4B,KAAKk2F,aAAclB,EAAKE,EAAK,kBAClBF,EAAI18D,eAAehM,QAAS4oE,EAAI10C,kBAC3CxgD,KAAKk2F,aAAclB,EAAKE,EAAK,iBAClBF,EAAI18D,eAAepL,QAASgoE,EAAIj1C,iBAC3CjgD,KAAKk2F,aAAclB,EAAKE,EAAK,mBAG9B,MAGD,KAAK,GACCF,EAAI18D,eAAehM,QAAS4oE,EAAIj1C,iBAAoB+0C,EAAI18D,eAAeza,SAAUq3E,EAAIj1C,gBACzFjgD,KAAKk2F,aAAclB,EAAKE,EAAK,gBAE7Bl1F,KAAKk2F,aAAclB,EAAKE,EAAK,eAOhC,MAGD,KAAK,GACJ,OAASA,EAAIxtF,aACZ,KAAK,GACCstF,EAAI50C,cAAcviC,SAAUq3E,EAAIj1C,iBACpCjgD,KAAKk2F,aAAclB,EAAKE,EAAK,eAG9B,MAGD,KAAK,IACCF,EAAI50C,cAAc9zB,QAAS4oE,EAAIj1C,iBAAoB+0C,EAAI50C,cAAcviC,SAAUq3E,EAAIj1C,kBACvFjgD,KAAKk2F,aAAclB,EAAKE,EAAK,eAOhC,MAGD,KAAK,GACJ,OAASA,EAAIxtF,aACZ,KAAK,GACEstF,EAAI18D,eAAehM,QAAS4oE,EAAIj1C,iBACrCjgD,KAAKk2F,aAAclB,EAAKE,EAAK,uBAGzBF,EAAI/0C,eAAe3zB,QAAS4oE,EAAI58D,iBACpCt4B,KAAKk2F,aAAclB,EAAKE,EAAK,uBAGzBF,EAAI/0C,eAAe3zB,QAAS4oE,EAAIj1C,iBACpCjgD,KAAKk2F,aAAclB,EAAKE,EAAK,oBAG9B,MAGD,KAAK,GACCF,EAAI/0C,eAAe3zB,QAAS4oE,EAAI90C,gBACpCpgD,KAAKk2F,aAAclB,EAAKE,EAAK,iBAKhC,MAGD,KAAK,GAAiB,CACrB,MAAMlvC,EAAcgvC,EAAIr6D,SAExB,IAAMqrB,EACL,OAGD,OAASkvC,EAAIxtF,aACZ,KAAK,GAAe,CACnB,MAAMw4C,EAAa,GAAMzxB,4BAA6BymE,EAAIj1C,eAAgBi1C,EAAIjuE,SAExEkvE,EAAej2C,EAAWvyB,iBAAkBq4B,EAAYnlC,QAC7Dq/B,EAAWr/B,MAAMyL,QAAS05B,EAAYnlC,OAEjCu1E,EAAgBl2C,EAAWvyB,iBAAkBq4B,EAAYllC,MAC9Do/B,EAAWp/B,IAAIwL,QAAS05B,EAAYllC,MAE9Bq1E,IAAgBC,GAAoBl2C,EAAWmB,cAAe2E,IACpEhmD,KAAKk2F,aAAclB,EAAKE,EAAK,CAC5BmB,KAAMF,EAAe,OAAS,QAC9BtmF,KAAMsmF,EAAenwC,EAAYnlC,MAAMhR,KAAKpI,QAAUu+C,EAAYllC,IAAIjR,KAAKpI,UAI7E,MAGD,KAAK,GAAgB,CACpB,MAAM6uF,EAAmBtwC,EAAYnlC,MAAMyL,QAAS4oE,EAAI58D,gBAClDi+D,EAA8BvwC,EAAYnlC,MAAMyL,QAAS4oE,EAAI10C,kBAC7Dg2C,EAA4BxwC,EAAYllC,IAAIwL,QAAS4oE,EAAI10C,kBACzDi2C,EAAoBzwC,EAAYllC,IAAIwL,QAAS4oE,EAAIj1C,iBAElDq2C,GAAoBC,GAA+BC,GAA6BC,IACpFz2F,KAAKk2F,aAAclB,EAAKE,EAAK,CAC5BoB,mBACAC,8BACAC,4BACAC,sBAIF,OAIF,QAUH,WAAYzB,EAAKE,EAAKwB,GACrB,MAAO,CACNA,YACAC,WAAY32F,KAAK42F,WAAY5B,GAC7B6B,WAAY72F,KAAK42F,WAAY1B,GAC7B4B,WAAY92F,KAAK61F,cAAgB71F,KAAK+2F,aAAc/B,EAAKE,GAAQ,KACjE8B,WAAYh3F,KAAK61F,cAAgB71F,KAAK+2F,aAAc7B,EAAKF,GAAQ,KACjER,gBAAiBx0F,KAAK81F,kBAUxB,WAAY91B,GAIX,MAAMi3B,EAAaj3F,KAAK00F,mBAAmBt2F,IAAK4hE,GAGhD,OAAOi3B,EAAWC,WAAal3F,KAAK41F,SAASuB,kBAAmBF,GA2BjE,aAAcjC,EAAKE,GAElB,MAAMkC,EAAQp3F,KAAK00F,mBAAmBt2F,IAAK82F,GACrCmC,EAAUr3F,KAAK41F,SAAS0B,mBAAoBF,GAGlD,IAAMC,EACL,OAAO,KAGR,MAAME,EAAQv3F,KAAK00F,mBAAmBt2F,IAAK42F,GACrCwC,EAAax3F,KAAK+1F,WAAW33F,IAAKm5F,GAGxC,OAAKC,GACGA,EAAWp5F,IAAKi5F,IAGjB,KASR,aAAcrC,EAAKE,EAAKuC,GAEvB,MAAMF,EAAQv3F,KAAK00F,mBAAmBt2F,IAAK42F,GACrCoC,EAAQp3F,KAAK00F,mBAAmBt2F,IAAK82F,GAE3C,IAAIsC,EAAax3F,KAAK+1F,WAAW33F,IAAKm5F,GAEhCC,IACLA,EAAa,IAAI1jF,IACjB9T,KAAK+1F,WAAWtsF,IAAK8tF,EAAOC,IAG7BA,EAAW/tF,IAAK2tF,EAAOK,IA4BzB,SAAS9B,GAAoBz0C,EAAY+e,GACxC,IAAM,MAAMvgB,KAAawB,EACxBxB,EAAUugB,YAAcA,IAW1B,SAASu1B,GAAct0C,EAAYj6B,GAClC,IAAM,IAAI1pB,EAAI,EAAGA,EAAI0pB,EAAS1pB,IAC7B2jD,EAAWj+C,KAAM,IAAI,GAAa,IAmIpC,SAASy0F,GAAsCC,EAAiB74F,EAAKkM,GACpE,MAGM4sF,EAHQD,EAAgB5wE,MAGJw3B,QAAS,GAAIn/B,aAActgB,GAErD,GAAK84F,GAAe5sF,EACnB,OAAO,KAGR,MAAMikB,EAAQ,IAAI,GAAO0oE,EAAgB9sE,SAAU8sE,EAAgB9sE,SAASyD,aAAcqpE,EAAgB1wE,UAE1G,OAAO,IAAI,GAAoBgI,EAAOnwB,EAAK84F,EAAa5sF,EAAU,GAw6CnE,SAAS6sF,GAA2Bl7E,EAAGC,GACtC,OAAqF,OAA9ED,EAAE2b,eAAeioB,0BAA2B3jC,EAAEqjC,eAAgBrjC,EAAEqK,SAgBxE,SAAS6wE,GAA+BjqE,EAAQyK,GAU/C,MAAM4oB,EAAa,GAGnB,IAAM,IAAI3jD,EAAI,EAAGA,EAAIswB,EAAO9rB,OAAQxE,IAAM,CAEzC,MAAM0xB,EAAQpB,EAAQtwB,GAChByiE,EAAK,IAAI,GACd/wC,EAAMpO,MACNoO,EAAMnO,IAAIxU,OAAS2iB,EAAMpO,MAAMvU,OAC/BgsB,EACA,GAGD4oB,EAAWj+C,KAAM+8D,GAGjB,IAAM,IAAI5e,EAAI7jD,EAAI,EAAG6jD,EAAIvzB,EAAO9rB,OAAQq/C,IAOvCvzB,EAAQuzB,GAAMvzB,EAAQuzB,GAAIpB,sBAAuBggB,EAAG/f,eAAgB+f,EAAG1nC,eAAgB0nC,EAAG/4C,SAAW,GAGtGqR,EAAiBA,EAAe0nB,sBAAuBggB,EAAG/f,eAAgB+f,EAAG1nC,eAAgB0nC,EAAG/4C,SAGjG,OAAOi6B,EAzmDR0yC,GAAmB,GAAoB,GAAoB,CAAEj3E,EAAGC,EAAGld,KAQlE,GAAKid,EAAE7d,MAAQ8d,EAAE9d,KAAO6d,EAAEsS,MAAMpO,MAAMk3E,gBAAiBn7E,EAAEqS,MAAMpO,OAAU,CAExE,MAAMqgC,EAAavkC,EAAEsS,MAAMyyB,cAAe9kC,EAAEqS,OAAQ5kB,IAAK4kB,GACjD,IAAI,GAAoBA,EAAOtS,EAAE7d,IAAK6d,EAAEkL,SAAUlL,EAAE3R,SAAU,IAIhE42C,EAASjlC,EAAEsS,MAAM4pB,gBAAiBj8B,EAAEqS,OAW1C,OATK2yB,GAICliD,EAAQg3F,WACZx1C,EAAWj+C,KAAM,IAAI,GAAoB2+C,EAAQhlC,EAAE9d,IAAK8d,EAAE5R,SAAU2R,EAAE3R,SAAU,IAIxD,GAArBk2C,EAAWn/C,OACR,CAAE,IAAI,GAAa,IAGpBm/C,EAGP,MAAO,CAAEvkC,KAIXi3E,GAAmB,GAAoB,GAAiB,CAAEj3E,EAAGC,KAO5D,GAAKD,EAAEsS,MAAMpO,MAAMk3E,gBAAiBn7E,EAAEiO,WAAclO,EAAEsS,MAAMtB,iBAAkB/Q,EAAEiO,UAAa,CAG5F,MACM/oB,EADQ6a,EAAEsS,MAAM8wB,2BAA4BnjC,EAAEiO,SAAUjO,EAAEqK,SAAUrK,EAAEykD,yBACvDh3D,IAAKhM,GAClB,IAAI,GAAoBA,EAAGse,EAAE7d,IAAK6d,EAAEkL,SAAUlL,EAAE3R,SAAU2R,EAAEsjD,cAGpE,GAAKrjD,EAAEykD,wBAA0B,CA4ChC,MAAMrB,EAAK03B,GAAsC96E,EAAGD,EAAE7d,IAAK6d,EAAEkL,UAExDm4C,GACJl+D,EAAOqb,QAAS6iD,GAKlB,OAAOl+D,EAMR,OAFA6a,EAAEsS,MAAQtS,EAAEsS,MAAM8wB,2BAA4BnjC,EAAEiO,SAAUjO,EAAEqK,SAAS,GAAS,GAEvE,CAAEtK,KA8BVi3E,GAAmB,GAAoB,GAAgB,CAAEj3E,EAAGC,KAC3D,MAAMiR,EAAS,GAOVlR,EAAEsS,MAAMpO,MAAMk3E,gBAAiBn7E,EAAE4jC,oBAChC7jC,EAAEsS,MAAMtB,iBAAkB/Q,EAAE4jC,mBAAsB7jC,EAAEsS,MAAMpO,MAAMyL,QAAS1P,EAAE4jC,oBAC/E3yB,EAAO5qB,KAAM,GAAMwrB,4BAA6B7R,EAAE0jC,kBAAmB,IAIvE,MAAMrxB,EAAQtS,EAAEsS,MAAM6wB,gCAAiCljC,GAQvD,OALMqS,EAAMxB,aACXI,EAAO5qB,KAAMgsB,GAIPpB,EAAOxjB,IAAK4kB,GACX,IAAI,GAAoBA,EAAOtS,EAAE7d,IAAK6d,EAAEkL,SAAUlL,EAAE3R,SAAU2R,EAAEsjD,gBAIzE2zB,GAAmB,GAAoB,GAAe,CAAEj3E,EAAGC,IAqB3D,SAAqCqS,EAAO+oE,GAC3C,MAAMx2C,EAAY,GAAM/yB,4BAA6BupE,EAAO/3C,eAAgB+3C,EAAO/wE,SAInF,IAAI26B,EAAS,KACTD,EAAa,GAGZH,EAAUH,cAAepyB,GAAO,GAEpC2yB,EAAS3yB,EACEA,EAAMpO,MAAMk3E,gBAAiBv2C,EAAU3gC,QAGlD8gC,EAAa1yB,EAAMyyB,cAAeF,GAClCI,EAAS3yB,EAAM4pB,gBAAiB2I,IAOhCG,EAAa,CAAE1yB,GAGhB,MAAMntB,EAAS,GAIf,IAAM,IAAI4gC,KAAQif,EAAa,CAG9Bjf,EAAOA,EAAK6d,0BAA2By3C,EAAO/3C,eAAgB+3C,EAAO/wE,SAGrE,MAAMqR,EAAiB0/D,EAAOh3B,qBAGxB1f,EAAS5e,EAAK7hB,MAAMk3E,gBAAiBz/D,GAG3CoK,EAAOA,EAAKqd,2BAA4BznB,EAAgB0/D,EAAO/wE,QAASq6B,GAExEx/C,EAAOmB,QAASy/B,GAKZkf,GACJ9/C,EAAOmB,KACN2+C,EAAO5B,sBAAuBg4C,EAAO/3C,eAAgB+3C,EAAO1/D,eAAgB0/D,EAAO/wE,SAAS,GAAS,IAIvG,OAAOnlB,EA3EQm2F,CAA4Bt7E,EAAEsS,MAAOrS,GAGtCvS,IAAK4kB,GAAS,IAAI,GAAoBA,EAAOtS,EAAE7d,IAAK6d,EAAEkL,SAAUlL,EAAE3R,SAAU2R,EAAEsjD,eA2E7F2zB,GAAmB,GAAoB,GAAgB,CAAEj3E,EAAGC,KAe3D,GAAKD,EAAEsS,MAAMnO,IAAIwL,QAAS1P,EAAE2c,mBAK3B,OAJM3c,EAAE0jC,mBACP3jC,EAAEsS,MAAMnO,IAAIxU,SAGN,CAAEqQ,GAiBV,GAAKA,EAAEsS,MAAMpO,MAAMk3E,gBAAiBn7E,EAAEwjC,gBAAmBzjC,EAAEsS,MAAMtB,iBAAkB/Q,EAAEwjC,eAAkB,CACtG,MAAMwgB,EAAajkD,EAAE+O,QAUrB,OARAk1C,EAAW3xC,MAAQ,IAAI,GACtBrS,EAAEyjC,mBAAmB30B,QACrB/O,EAAEsS,MAAMnO,IAAIq/B,aAAcvjC,EAAEwjC,cAAexjC,EAAEyjC,qBAG9C1jC,EAAEsS,MAAMnO,IAAMlE,EAAEwjC,cAAc10B,QAC9B/O,EAAEsS,MAAMnO,IAAI+9B,WAAa,aAElB,CAAEliC,EAAGikD,GAOb,OAFAjkD,EAAEsS,MAAQtS,EAAEsS,MAAM4wB,gCAAiCjjC,GAE5C,CAAED,KAGVi3E,GAAmB,GAAiB,GAAoB,CAAEj3E,EAAGC,KAC5D,MAAM9a,EAAS,CAAE6a,GAYjB,GAAKA,EAAE0kD,yBAA2B1kD,EAAEkO,SAASktE,gBAAiBn7E,EAAEqS,MAAMpO,QAAWjE,EAAEqS,MAAMtB,iBAAkBhR,EAAEkO,UAAa,CACzH,MAAMm1C,EAAK03B,GAAsC/6E,EAAGC,EAAE9d,IAAK8d,EAAE5R,UAExDg1D,GACJl+D,EAAOmB,KAAM+8D,GAOf,OAAOl+D,IAGR8xF,GAAmB,GAAiB,GAAiB,CAAEj3E,EAAGC,EAAGld,KAUvDid,EAAEkO,SAASyB,QAAS1P,EAAEiO,WAAcnrB,EAAQg3F,YAMjD/5E,EAAEkO,SAAWlO,EAAEkO,SAAS80B,iCAAkC/iC,IALlD,CAAED,KAUXi3E,GAAmB,GAAiB,GAAe,CAAEj3E,EAAGC,KAGvDD,EAAEkO,SAAWlO,EAAEkO,SAAS+0B,+BAAgChjC,GAEjD,CAAED,KAGVi3E,GAAmB,GAAiB,GAAgB,CAAEj3E,EAAGC,KAGxDD,EAAEkO,SAAWlO,EAAEkO,SAASg1B,gCAAiCjjC,GAElD,CAAED,KAGVi3E,GAAmB,GAAiB,GAAgB,CAAEj3E,EAAGC,KACxDD,EAAEkO,SAAWlO,EAAEkO,SAASi1B,gCAAiCljC,GAElD,CAAED,KAKVi3E,GAAmB,GAAiB,GAAiB,CAAEj3E,EAAGC,KACpDD,EAAEqrC,WACNrrC,EAAEqrC,SAAWrrC,EAAEqrC,SAASrI,iCAAkC/iC,GAAK,IAG3DD,EAAEge,WACNhe,EAAEge,SAAWhe,EAAEge,SAASglB,iCAAkC/iC,GAAK,IAGzD,CAAED,KAGVi3E,GAAmB,GAAiB,GAAiB,CAAEj3E,EAAGC,EAAGld,KAC5D,GAAKid,EAAE7e,MAAQ8e,EAAE9e,KAAO,CACvB,IAAK4B,EAAQg3F,UAGZ,MAAO,CAAE,IAAI,GAAa,IAF1B/5E,EAAEqrC,SAAWprC,EAAE+d,SAAW/d,EAAE+d,SAASjP,QAAU,KAMjD,MAAO,CAAE/O,KAGVi3E,GAAmB,GAAiB,GAAgB,CAAEj3E,EAAGC,KACnDD,EAAEqrC,WACNrrC,EAAEqrC,SAAWrrC,EAAEqrC,SAASlI,gCAAiCljC,IAGrDD,EAAEge,WACNhe,EAAEge,SAAWhe,EAAEge,SAASmlB,gCAAiCljC,IAGnD,CAAED,KAGVi3E,GAAmB,GAAiB,GAAe,CAAEj3E,EAAGC,EAAGld,KAK1D,GAJKid,EAAEqrC,WACNrrC,EAAEqrC,SAAW,GAAMyB,kBAAmB9sC,EAAEqrC,SAASpI,+BAAgChjC,KAG7ED,EAAEge,SAAW,CACjB,GAAKj7B,EAAQo3F,WAAa,CACzB,MAAMoB,EAAY,GAAMzuC,kBAAmB9sC,EAAEge,SAASilB,+BAAgChjC,IAEtF,GAAgC,QAA3Bld,EAAQo3F,WAAWT,MAAkBz5E,EAAE0b,eAAehM,QAAS3P,EAAEge,SAAS9Z,OAI9E,OAHAlE,EAAEge,SAAS9Z,MAAMhR,KAAOnQ,EAAQo3F,WAAWjnF,KAC3C8M,EAAEge,SAAS7Z,IAAMo3E,EAAUp3E,IAEpB,CAAEnE,GACH,GAAgC,SAA3Bjd,EAAQo3F,WAAWT,MAAmBz5E,EAAE0b,eAAehM,QAAS3P,EAAEge,SAAS7Z,KAItF,OAHAnE,EAAEge,SAAS9Z,MAAQq3E,EAAUr3E,MAC7BlE,EAAEge,SAAS7Z,IAAIjR,KAAOnQ,EAAQo3F,WAAWjnF,KAElC,CAAE8M,GAIXA,EAAEge,SAAW,GAAM8uB,kBAAmB9sC,EAAEge,SAASilB,+BAAgChjC,IAGlF,MAAO,CAAED,KAGVi3E,GAAmB,GAAiB,GAAgB,CAAEj3E,EAAGC,EAAGld,KAK3D,GAJKid,EAAEqrC,WACNrrC,EAAEqrC,SAAWrrC,EAAEqrC,SAASnI,gCAAiCjjC,IAGrDD,EAAEge,SAAW,CACjB,GAAKj7B,EAAQo3F,WAAa,CACzB,MAAMoB,EAAYv7E,EAAEge,SAASklB,gCAAiCjjC,GAgB9D,OAdKD,EAAEge,SAAS9Z,MAAMyL,QAAS1P,EAAEwjC,gBAAmB1gD,EAAQo3F,WAAWP,4BACtE55E,EAAEge,SAAS9Z,MAAQ,GAASiK,UAAWlO,EAAE2c,mBAC9B5c,EAAEge,SAAS9Z,MAAMyL,QAAS1P,EAAEwjC,iBAAoB1gD,EAAQo3F,WAAWR,mBAC9E35E,EAAEge,SAAS9Z,MAAQ,GAASiK,UAAWlO,EAAEyjC,qBAGrC1jC,EAAEge,SAAS7Z,IAAIwL,QAAS1P,EAAEwjC,gBAAmB1gD,EAAQo3F,WAAWL,kBACpE95E,EAAEge,SAAS7Z,IAAM,GAASgK,UAAWlO,EAAEyjC,oBAC5B1jC,EAAEge,SAAS7Z,IAAIwL,QAAS1P,EAAEwjC,gBAAmB1gD,EAAQo3F,WAAWN,0BAC3E75E,EAAEge,SAAS7Z,IAAM,GAASgK,UAAWlO,EAAE2c,mBAEvC5c,EAAEge,SAAS7Z,IAAMo3E,EAAUp3E,IAGrB,CAAEnE,GAGVA,EAAEge,SAAWhe,EAAEge,SAASklB,gCAAiCjjC,GAG1D,MAAO,CAAED,KAKVi3E,GAAmB,GAAgB,GAAiB,CAAEj3E,EAAGC,KACnDD,EAAEsjC,eAAe83C,gBAAiBn7E,EAAEiO,YACxClO,EAAEsK,SAAWrK,EAAEqK,SAGhBtK,EAAEsjC,eAAiBtjC,EAAEsjC,eAAeN,iCAAkC/iC,GACtED,EAAE2b,eAAiB3b,EAAE2b,eAAeqnB,iCAAkC/iC,GAE/D,CAAED,KAGVi3E,GAAmB,GAAgB,GAAgB,CAAEj3E,EAAGC,EAAGld,KAQ1D,GAAKid,EAAEsjC,eAAe3zB,QAAS1P,EAAEqjC,iBAAoBtjC,EAAE2b,eAAehM,QAAS1P,EAAE0b,gBAAmB,CAYnG,GAAM54B,EAAQm3F,WAEP,CACN,MAAMhnF,EAAO+M,EAAE0jC,kBAAkBzwC,KAAKpI,QAMtC,OALAoI,EAAK5M,KAAM,GAEX0Z,EAAEsjC,eAAiB,IAAI,GAAUrjC,EAAE0jC,kBAAkBzjD,KAAMgT,GAC3D8M,EAAEsK,QAAU,EAEL,CAAEtK,GART,MAAO,CAAE,IAAI,GAAa,IAuC5B,GACCA,EAAEsjC,eAAe3zB,QAAS1P,EAAEqjC,kBAAqBtjC,EAAE2b,eAAehM,QAAS1P,EAAE0b,kBAC5E54B,EAAQm3F,YAAoC,iBAAtBn3F,EAAQo3F,WAC9B,CACD,MAAMqB,EAAiD,cAAlCx7E,EAAE2b,eAAez7B,KAAK0tB,SACrC6tE,EAAiD,cAAlCx7E,EAAE0b,eAAez7B,KAAK0tB,SAGrC8tE,EAAUF,IAAiBC,EAQjC,GALgBA,IAAiBD,IAGDE,GAAW34F,EAAQg3F,UAElC,CAChB,MAAMz2C,EAAiBrjC,EAAE0b,eAAewnB,gCAAiCljC,GACnE0b,EAAiB3b,EAAE2b,eAAewnB,gCAAiCljC,GAEzE,MAAO,CAAE,IAAI,GAAeqjC,EAAgBtjC,EAAEsK,QAASqR,EAAgB,IAEvE,MAAO,CAAE,IAAI,GAAa,IAmB5B,OAbK3b,EAAEsjC,eAAe83C,gBAAiBn7E,EAAE0b,kBACxC3b,EAAEsK,SAAWrK,EAAEqK,SAGhBtK,EAAEsjC,eAAiBtjC,EAAEsjC,eAAeH,gCAAiCljC,GACrED,EAAE2b,eAAiB3b,EAAE2b,eAAewnB,gCAAiCljC,GAI/DD,EAAE2jC,kBAAkBh0B,QAAS1P,EAAE0jC,oBAAwB5gD,EAAQg3F,YACpE/5E,EAAE2jC,kBAAoB3jC,EAAE2jC,kBAAkBR,gCAAiCljC,IAGrE,CAAED,KAGVi3E,GAAmB,GAAgB,GAAe,CAAEj3E,EAAGC,EAAGld,KAYzD,MAAM44F,EAAe,GAAM7pE,4BAA6B7R,EAAEqjC,eAAgBrjC,EAAEqK,SAE5E,MAAe,UAAVrK,EAAE3c,OAAqBP,EAAQm3F,aAAen3F,EAAQ80F,iBACrD73E,EAAE6jC,iBAAiBu3C,gBAAiBn7E,EAAEqjC,iBAAoBq4C,EAAa3qE,iBAAkBhR,EAAEsjC,gBACxF,CAAE,IAAI,GAAa,KAMvBtjC,EAAEsjC,eAAe83C,gBAAiBn7E,EAAE0b,kBACxC3b,EAAEsK,SAAWrK,EAAEqK,SAGXtK,EAAEsjC,eAAe83C,gBAAiBn7E,EAAEqjC,kBACxCtjC,EAAEsK,SAAWrK,EAAEqK,SAGhBtK,EAAEsjC,eAAiBtjC,EAAEsjC,eAAeL,+BAAgChjC,GACpED,EAAE2b,eAAiB3b,EAAE2b,eAAesnB,+BAAgChjC,GAM9DD,EAAE2jC,kBAAkBh0B,QAAS1P,EAAE0b,kBACpC3b,EAAE2jC,kBAAoB3jC,EAAE2jC,kBAAkBV,+BAAgChjC,IAGpE,CAAED,MAGVi3E,GAAmB,GAAgB,GAAgB,CAAEj3E,EAAGC,EAAGld,KAyE1D,GAxEKkd,EAAE0jC,oBAGN3jC,EAAE2jC,kBAAoB3jC,EAAE2jC,kBAAkBC,0BAA2B3jC,EAAE0jC,kBAAmB,GAYrF3jC,EAAE6jC,iBAAiBl0B,QAAS1P,EAAE0jC,qBAClC3jC,EAAEsK,QAAUrK,EAAEqK,UAwDXtK,EAAE2b,eAAehM,QAAS1P,EAAEwjC,eAAkB,CAClD,MAAMm4C,EAA2B,GAAb37E,EAAEqK,QAChBuxE,EAAwB57E,EAAE0jC,mBAAqB3jC,EAAE6jC,iBAAiBl0B,QAAS1P,EAAE0jC,mBAEnF,GAAKi4C,GAAeC,GAA+C,uBAAtB94F,EAAQo3F,WAGpD,OAFAn6E,EAAEsjC,eAAiBtjC,EAAEsjC,eAAeJ,gCAAiCjjC,GAE9D,CAAED,GAUX,GAAKA,EAAEsjC,eAAe3zB,QAAS1P,EAAEwjC,eAAkB,CAIlD,GAA2B,uBAAtB1gD,EAAQo3F,WAIZ,OAHAn6E,EAAEsK,QAAU,EACZtK,EAAE2b,eAAiB3b,EAAE2b,eAAeunB,gCAAiCjjC,GAE9D,CAAED,GAUV,GAA2B,oBAAtBjd,EAAQo3F,YAAoCn6E,EAAEsjC,eAAe3zC,OAAS,EAI1E,OAHAqQ,EAAEsjC,eAAiBrjC,EAAEyjC,mBAAmB30B,QACxC/O,EAAE2b,eAAiB3b,EAAE2b,eAAeunB,gCAAiCjjC,GAE9D,CAAED,GAaX,OAPKA,EAAEsjC,eAAe83C,gBAAiBn7E,EAAEwjC,iBACxCzjC,EAAEsK,QAAUrK,EAAEwjC,cAAc9zC,QAG7BqQ,EAAEsjC,eAAiBtjC,EAAEsjC,eAAeJ,gCAAiCjjC,GACrED,EAAE2b,eAAiB3b,EAAE2b,eAAeunB,gCAAiCjjC,GAE9D,CAAED,KAKVi3E,GAAmB,GAAe,GAAiB,CAAEj3E,EAAGC,KACvD,MACM8jC,EADY,GAAMjyB,4BAA6B9R,EAAEsjC,eAAgBtjC,EAAEsK,SAC3C04B,iCAAkC/iC,GAAG,GAAS,GAe5E,OAbAD,EAAEsjC,eAAiBS,EAAY7/B,MAC/BlE,EAAEsK,QAAUy5B,EAAY5/B,IAAIxU,OAASo0C,EAAY7/B,MAAMvU,OAQjDqQ,EAAE2b,eAAehM,QAAS1P,EAAEiO,YACjClO,EAAE2b,eAAiB3b,EAAE2b,eAAeqnB,iCAAkC/iC,IAGhE,CAAED,KAGVi3E,GAAmB,GAAe,GAAe,CAAEj3E,EAAGC,EAAGld,KAKxD,MAAMywB,EAAS,GAAM1B,4BAA6B9R,EAAEsjC,eAAgBtjC,EAAEsK,SAChEoJ,EAAS,GAAM5B,4BAA6B7R,EAAEqjC,eAAgBrjC,EAAEqK,SAItE,IAcI85C,EAdA21B,EAAYh3F,EAAQg3F,UAIpBhyF,GAAgBhF,EAAQg3F,UA+B5B,GA5B2B,gBAAtBh3F,EAAQo3F,YAAsD,eAAtBp3F,EAAQs3F,WACpDtyF,GAAe,EACkB,eAAtBhF,EAAQo3F,YAAqD,gBAAtBp3F,EAAQs3F,aAC1DtyF,GAAe,GAOfq8D,EADIpkD,EAAE2b,eAAehM,QAAS1P,EAAE0b,iBAAoB5zB,EAChCiY,EAAE2b,eAAeioB,0BACpC3jC,EAAEqjC,eACFrjC,EAAEqK,SAGiBtK,EAAE2b,eAAe0nB,sBACpCpjC,EAAEqjC,eACFrjC,EAAE0b,eACF1b,EAAEqK,SAUC4wE,GAA2Bl7E,EAAGC,IAAOi7E,GAA2Bj7E,EAAGD,GAGvE,MAAO,CAAEC,EAAE67E,eAcZ,GAJoBtoE,EAAOxC,iBAAkB/Q,EAAE0b,iBAI3BnI,EAAOkxB,cAAehxB,GAAQ,GAMjD,OAHAF,EAAOtP,MAAQsP,EAAOtP,MAAMm/B,sBAAuBpjC,EAAEqjC,eAAgBrjC,EAAE0b,eAAgB1b,EAAEqK,SACzFkJ,EAAOrP,IAAMqP,EAAOrP,IAAIk/B,sBAAuBpjC,EAAEqjC,eAAgBrjC,EAAE0b,eAAgB1b,EAAEqK,SAE9E6wE,GAA+B,CAAE3nE,GAAU4wC,GAQnD,GAFoB1wC,EAAO1C,iBAAkBhR,EAAE2b,iBAE3BjI,EAAOgxB,cAAelxB,GAAQ,GAMjD,OAHAA,EAAOtP,MAAQsP,EAAOtP,MAAMs/B,aAAcvjC,EAAEqjC,eAAgBrjC,EAAEokD,sBAC9D7wC,EAAOrP,IAAMqP,EAAOrP,IAAIq/B,aAAcvjC,EAAEqjC,eAAgBrjC,EAAEokD,sBAEnD82B,GAA+B,CAAE3nE,GAAU4wC,GAanD,MAAM23B,EAASh8E,GAAeC,EAAEsjC,eAAeR,gBAAiB7iC,EAAEqjC,eAAeR,iBAEjF,GAAe,UAAVi5C,GAAgC,aAAVA,EAO1B,OAHAvoE,EAAOtP,MAAQsP,EAAOtP,MAAMm/B,sBAAuBpjC,EAAEqjC,eAAgBrjC,EAAE0b,eAAgB1b,EAAEqK,SACzFkJ,EAAOrP,IAAMqP,EAAOrP,IAAIk/B,sBAAuBpjC,EAAEqjC,eAAgBrjC,EAAE0b,eAAgB1b,EAAEqK,SAE9E6wE,GAA+B,CAAE3nE,GAAU4wC,GAcpC,UAAVpkD,EAAE1c,MAA8B,UAAV2c,EAAE3c,MAAqBP,EAAQi3F,YAAej3F,EAAQ80F,gBAE3D,UAAV73E,EAAE1c,MAA8B,UAAV2c,EAAE3c,MAAqBP,EAAQm3F,YAAen3F,EAAQ80F,kBACvFkC,GAAY,GAFZA,GAAY,EAOb,MAAM7oE,EAAS,GAIT8zB,EAAaxxB,EAAOuxB,cAAerxB,GAEzC,IAAM,MAAMpB,KAAS0yB,EAAa,CAEjC1yB,EAAMpO,MAAQoO,EAAMpO,MAAM0/B,0BAA2B3jC,EAAEqjC,eAAgBrjC,EAAEqK,SACzEgI,EAAMnO,IAAMmO,EAAMnO,IAAIy/B,0BAA2B3jC,EAAEqjC,eAAgBrjC,EAAEqK,SAGrE,MAAM0xE,EAAuG,QAAxFj8E,GAAeuS,EAAMpO,MAAM4+B,gBAAiB7iC,EAAEokD,qBAAqBvhB,iBAClFzuB,EAAY/B,EAAM8wB,2BAA4BnjC,EAAEokD,qBAAsBpkD,EAAEqK,QAAS0xE,GAEvF9qE,EAAO5qB,QAAS+tB,GAIjB,MAAM4wB,EAASzxB,EAAO0oB,gBAAiBxoB,GA+BvC,OA7BgB,OAAXuxB,GAAmB80C,IAEvB90C,EAAO/gC,MAAQ+gC,EAAO/gC,MAAMs/B,aAAcvjC,EAAEqjC,eAAgBrjC,EAAEokD,sBAC9Dpf,EAAO9gC,IAAM8gC,EAAO9gC,IAAIq/B,aAAcvjC,EAAEqjC,eAAgBrjC,EAAEokD,sBAQnC,IAAlBnzC,EAAO9rB,OACX8rB,EAAO5qB,KAAM2+C,GAGa,GAAjB/zB,EAAO9rB,OACXsuB,EAAOxP,MAAMhD,SAAUsS,EAAOtP,QAAWwP,EAAOxP,MAAMyL,QAAS6D,EAAOtP,OAC1EgN,EAAO1Q,QAASykC,GAEhB/zB,EAAO5qB,KAAM2+C,GAMd/zB,EAAO/nB,OAAQ,EAAG,EAAG87C,IAIA,IAAlB/zB,EAAO9rB,OAGJ,CAAE,IAAI,GAAa4a,EAAEsjD,cAGtB63B,GAA+BjqE,EAAQkzC,KAG/C6yB,GAAmB,GAAe,GAAgB,CAAEj3E,EAAGC,EAAGld,KACzD,IAAIqhE,EAAoBpkD,EAAE2b,eAAe5M,QAKnC/O,EAAE2b,eAAehM,QAAS1P,EAAE2c,oBAAwB3c,EAAE0jC,mBAA2C,mBAAtB5gD,EAAQo3F,aACxF/1B,EAAoBpkD,EAAE2b,eAAeunB,gCAAiCjjC,IAUvE,MAAM4kC,EAAY,GAAM/yB,4BAA6B9R,EAAEsjC,eAAgBtjC,EAAEsK,SAEzE,GAAKu6B,EAAU1gC,IAAIwL,QAAS1P,EAAE2c,mBAS7B,OANM3c,EAAE0jC,mBACP3jC,EAAEsK,UAGHtK,EAAE2b,eAAiByoC,EAEZ,CAAEpkD,GAmBV,GAAK6kC,EAAU3gC,MAAMk3E,gBAAiBn7E,EAAEwjC,gBAAmBoB,EAAU7zB,iBAAkB/Q,EAAEwjC,eAAkB,CAC1G,IAAIw4C,EAAa,IAAI,GAAOh8E,EAAEwjC,cAAeoB,EAAU1gC,KACvD83E,EAAaA,EAAW/4C,gCAAiCjjC,GAOzD,OAAOk7E,GALQ,CACd,IAAI,GAAOt2C,EAAU3gC,MAAOjE,EAAEwjC,eAC9Bw4C,GAG6C73B,GAQ1CpkD,EAAE2b,eAAehM,QAAS1P,EAAEwjC,gBAAyC,kBAAtB1gD,EAAQo3F,aAC3D/1B,EAAoBnkD,EAAEyjC,oBAwBlB1jC,EAAE2b,eAAehM,QAAS1P,EAAE2c,oBAA6C,iBAAtB75B,EAAQo3F,aAC/D/1B,EAAoBpkD,EAAE2b,gBAKvB,MACMzK,EAAS,CADK2zB,EAAU3B,gCAAiCjjC,IAO/D,GAAKA,EAAE0jC,kBAAoB,CAC1B,MAAMu4C,EAAwBr3C,EAAU3gC,MAAMyL,QAAS1P,EAAE0jC,oBAAuBkB,EAAU7zB,iBAAkB/Q,EAAE0jC,mBAEzG3jC,EAAEsK,QAAU,GAAK4xE,IAA0Bn5F,EAAQi3F,YACvD9oE,EAAO5qB,KAAM,GAAMwrB,4BAA6B7R,EAAE2c,kBAAmB,IAIvE,OAAOu+D,GAA+BjqE,EAAQkzC,KAG/C6yB,GAAmB,GAAe,GAAgB,CAAEj3E,EAAGC,EAAGld,KACzD,MAAMwgD,EAAa,GAAMzxB,4BAA6B9R,EAAEsjC,eAAgBtjC,EAAEsK,SAE1E,GAAKrK,EAAE4jC,iBAAiBu3C,gBAAiBp7E,EAAEsjC,iBAAoBC,EAAWvyB,iBAAkB/Q,EAAEqjC,gBAC7F,GAAe,UAAVtjC,EAAE1c,MAAqBP,EAAQ80F,iBA6CnC,GAAkB,GAAb73E,EAAEsK,QACN,OAAMvnB,EAAQm3F,YAGbl6E,EAAEsjC,eAAiBrjC,EAAE0jC,kBAAkB50B,QACvC/O,EAAE2b,eAAiB3b,EAAE2b,eAAewnB,gCAAiCljC,GAE9D,CAAED,IALF,CAAE,IAAI,GAAa,SArC5B,IAAMjd,EAAQi3F,WAAa,CAC1B,MAAM53E,EAAU,GAEhB,IAAI+5E,EAAel8E,EAAE0jC,kBAAkB50B,QACnCqtE,EAAuBn8E,EAAE0b,eAAewnB,gCAAiCljC,GAExED,EAAEsK,QAAU,IAChBlI,EAAQ9b,KAAM,IAAI,GAAe0Z,EAAEsjC,eAAgBtjC,EAAEsK,QAAU,EAAGtK,EAAE2b,eAAgB,IAEpFwgE,EAAeA,EAAa94C,sBAAuBrjC,EAAEsjC,eAAgBtjC,EAAE2b,eAAgB3b,EAAEsK,QAAU,GACnG8xE,EAAuBA,EAAqB/4C,sBAAuBrjC,EAAEsjC,eAAgBtjC,EAAE2b,eAAgB3b,EAAEsK,QAAU,IAGpH,MAAM+xE,EAAep8E,EAAE4jC,iBAAiBL,aAAcxjC,EAAEsjC,eAAgBtjC,EAAE2b,gBACpE2gE,EAAS,IAAI,GAAeH,EAAc,EAAGE,EAAc,GAE3DE,EAA2BD,EAAOj4B,qBAAqBnxD,KAAKpI,QAClEyxF,EAAyBj2F,KAAM,GAE/B,MAAMk2F,EAAuB,IAAI,GAAUF,EAAO3gE,eAAez7B,KAAMq8F,GACvEH,EAAuBA,EAAqB/4C,sBAAuB84C,EAAcE,EAAc,GAC/F,MAAMI,EAAiB,IAAI,GAAeL,EAAsBn8E,EAAEqK,QAASkyE,EAAsB,GAKjG,OAHAp6E,EAAQ9b,KAAMg2F,GACdl6E,EAAQ9b,KAAMm2F,GAEPr6E,EAwBV,MACM2hC,EADY,GAAMjyB,4BAA6B9R,EAAEsjC,eAAgBtjC,EAAEsK,SAC3C64B,gCAAiCljC,GAM/D,OAJAD,EAAEsjC,eAAiBS,EAAY7/B,MAC/BlE,EAAEsK,QAAUy5B,EAAY5/B,IAAIxU,OAASo0C,EAAY7/B,MAAMvU,OACvDqQ,EAAE2b,eAAiB3b,EAAE2b,eAAewnB,gCAAiCljC,GAE9D,CAAED,KAKVi3E,GAAmB,GAAiB,GAAiB,CAAEj3E,EAAGC,KACzDD,EAAEkO,SAAWlO,EAAEkO,SAAS80B,iCAAkC/iC,GAEnD,CAAED,KAGVi3E,GAAmB,GAAiB,GAAgB,CAAEj3E,EAAGC,IAKnDD,EAAEkO,SAASyB,QAAS1P,EAAE4jC,mBAC1B7jC,EAAEkO,SAAWjO,EAAE0jC,kBAAkB50B,QACjC/O,EAAEkO,SAASg0B,WAAa,SAEjB,CAAEliC,KAGVA,EAAEkO,SAAWlO,EAAEkO,SAASi1B,gCAAiCljC,GAElD,CAAED,KAGVi3E,GAAmB,GAAiB,GAAe,CAAEj3E,EAAGC,KACvDD,EAAEkO,SAAWlO,EAAEkO,SAAS+0B,+BAAgChjC,GAEjD,CAAED,KAGVi3E,GAAmB,GAAiB,GAAiB,CAAEj3E,EAAGC,EAAGld,KAC5D,GAAKid,EAAEkO,SAASyB,QAAS1P,EAAEiO,UAAa,CACvC,IAAKnrB,EAAQg3F,UAGZ,MAAO,CAAE,IAAI,GAAa,IAF1B/5E,EAAE+kD,QAAU9kD,EAAEie,QAMhB,MAAO,CAAEle,KAGVi3E,GAAmB,GAAiB,GAAgB,CAAEj3E,EAAGC,KAiBxD,GAA+C,QAA1CF,GAHcC,EAAEkO,SAAShb,KACZ+M,EAAEwjC,cAAcX,mBAEwB7iC,EAAE0jC,kBAAoB,CAC/E,MAAM+4C,EAAc,IAAI,GAAiB18E,EAAEkO,SAASyD,aAAc,GAAK3R,EAAE+kD,QAAS/kD,EAAEke,QAAS,GAE7F,MAAO,CAAEle,EAAG08E,GAOb,OAFA18E,EAAEkO,SAAWlO,EAAEkO,SAASg1B,gCAAiCjjC,GAElD,CAAED,KAKVi3E,GAAmB,GAAwB,GAAwB,CAAEj3E,EAAGC,EAAGld,KAC1E,GAAKid,EAAE9f,OAAS+f,EAAE/f,MAAQ8f,EAAE7d,MAAQ8d,EAAE9d,IAAM,CAC3C,IAAMY,EAAQg3F,WAAa/5E,EAAE3R,WAAa4R,EAAE5R,SAC3C,MAAO,CAAE,IAAI,GAAa,IAE1B2R,EAAEkL,SAAWjL,EAAE5R,SAIjB,MAAO,CAAE2R,KAKVi3E,GAAmB,GAAgB,GAAiB,CAAEj3E,EAAGC,KAGnDD,EAAEyjC,cAAc23C,gBAAiBn7E,EAAEiO,WAAclO,EAAEyjC,cAAc9zC,OAASsQ,EAAEiO,SAASve,SACzFqQ,EAAEsK,SAAWrK,EAAEqK,SAGhBtK,EAAEyjC,cAAgBzjC,EAAEyjC,cAAcT,iCAAkC/iC,GACpED,EAAE4c,kBAAoB,GAAeqoC,qBAAsBjlD,EAAEyjC,eAEtD,CAAEzjC,KAGVi3E,GAAmB,GAAgB,GAAgB,CAAEj3E,EAAGC,EAAGld,KAqD1D,IAAMid,EAAE2jC,oBAAsB5gD,EAAQm3F,YAAcl6E,EAAEyjC,cAAc23C,gBAAiBn7E,EAAEqjC,gBAAmB,CACzG,MAAMq5C,EAAY18E,EAAE0jC,kBAAkBzwC,KAAKpI,QAC3C6xF,EAAUr2F,KAAM,GAEhB,MAAMm9C,EAAgB,IAAI,GAAUxjC,EAAE0jC,kBAAkBzjD,KAAMy8F,GACxD//D,EAAoB,GAAeqoC,qBAAsB,IAAI,GAAUhlD,EAAE0jC,kBAAkBzjD,KAAMy8F,IAEjGC,EAAkB,IAAI,GAAgBn5C,EAAe,EAAG,KAAM,GAQpE,OAPAm5C,EAAgBhgE,kBAAoBA,EAEpC5c,EAAEyjC,cAAgBzjC,EAAEyjC,cAAcN,gCAAiCljC,GACnED,EAAE4c,kBAAoB,GAAeqoC,qBAAsBjlD,EAAEyjC,eAC7DzjC,EAAE2jC,kBAAoBi5C,EAAgBhgE,kBAAkB7N,QACxD/O,EAAE2jC,kBAAkBzB,WAAa,SAE1B,CAAE06C,EAAiB58E,GAoB3B,OAfKA,EAAEyjC,cAAc23C,gBAAiBn7E,EAAE4jC,oBAAuB7jC,EAAEyjC,cAAclzB,QAAStQ,EAAE4jC,mBACzF7jC,EAAEsK,UAGEtK,EAAEyjC,cAAc23C,gBAAiBn7E,EAAE0b,kBACvC3b,EAAEsK,SAAWrK,EAAEqK,SAGhBtK,EAAEyjC,cAAgBzjC,EAAEyjC,cAAcN,gCAAiCljC,GACnED,EAAE4c,kBAAoB,GAAeqoC,qBAAsBjlD,EAAEyjC,eAExDzjC,EAAE2jC,oBACN3jC,EAAE2jC,kBAAoB3jC,EAAE2jC,kBAAkBR,gCAAiCljC,IAGrE,CAAED,KAGVi3E,GAAmB,GAAgB,GAAe,CAAEj3E,EAAGC,EAAGld,KACzD,MAAM85F,EAAc,GAAM/qE,4BAA6B7R,EAAEqjC,eAAgBrjC,EAAEqK,SAE3E,GAAKtK,EAAE2jC,kBAAoB,CAO1B,MAAMm5C,EAAiBD,EAAY34E,MAAMyL,QAAS3P,EAAE2jC,oBAAuBk5C,EAAY7rE,iBAAkBhR,EAAE2jC,mBAE3G,IAAM5gD,EAAQm3F,YAAc4C,EAAiB,CAC5C,MAAMx5C,EAAiBtjC,EAAEyjC,cAAcR,+BAAgChjC,GAEjE88E,EAAoB/8E,EAAE2jC,kBAAkBV,+BAAgChjC,GACxE+8E,EAAgBD,EAAkB7pF,KAAKpI,QAC7CkyF,EAAc12F,KAAM,GAEpB,MAAM89D,EAAoB,IAAI,GAAU24B,EAAkB78F,KAAM88F,GAGhE,MAAO,CAFQ,IAAI,GAAe15C,EAAgBtjC,EAAEsK,QAAS85C,EAAmB,IAKjFpkD,EAAE2jC,kBAAoB3jC,EAAE2jC,kBAAkBV,+BAAgChjC,GAoB3E,GAAKD,EAAEyjC,cAAc23C,gBAAiBn7E,EAAEqjC,iBAAoBu5C,EAAY7rE,iBAAkBhR,EAAEyjC,eAAkB,CAC7G,MAAMw5C,EAAiBh9E,EAAEqK,SAAYtK,EAAEyjC,cAAc9zC,OAASsQ,EAAEqjC,eAAe3zC,QAU/E,OATAqQ,EAAEsK,SAAW2yE,EAERj9E,EAAEyjC,cAAc23C,gBAAiBn7E,EAAE0b,iBAAoB3b,EAAEyjC,cAAc9zC,OAASsQ,EAAE0b,eAAehsB,SACrGqQ,EAAEsK,SAAWrK,EAAEqK,SAGhBtK,EAAEyjC,cAAgBxjC,EAAEqjC,eAAev0B,QACnC/O,EAAE4c,kBAAoB,GAAeqoC,qBAAsBjlD,EAAEyjC,eAEtD,CAAEzjC,GAYV,OAFsBA,EAAEyjC,cAAc9zB,QAAS1P,EAAE0b,iBAEH,kBAAtB54B,EAAQs3F,YAAwD,eAAtBt3F,EAAQo3F,YAWpEl6E,EAAEqjC,eAAe3zB,QAAS1P,EAAE0b,kBAC5B3b,EAAEyjC,cAAc23C,gBAAiBn7E,EAAEqjC,iBAAoBtjC,EAAEyjC,cAAc9zC,QAAUsQ,EAAEqjC,eAAe3zC,SACtGqQ,EAAEsK,SAAWrK,EAAEqK,SAGXtK,EAAEyjC,cAAc23C,gBAAiBn7E,EAAE0b,iBAAoB3b,EAAEyjC,cAAc9zC,OAASsQ,EAAE0b,eAAehsB,SACrGqQ,EAAEsK,SAAWrK,EAAEqK,UAKjBtK,EAAEyjC,cAAcvB,WAAa,SAC7BliC,EAAEyjC,cAAgBzjC,EAAEyjC,cAAcR,+BAAgChjC,GAClED,EAAEyjC,cAAcvB,WAAa,SAExBliC,EAAE2jC,kBACN3jC,EAAE4c,kBAAoB5c,EAAE4c,kBAAkBqmB,+BAAgChjC,GAE1ED,EAAE4c,kBAAoB,GAAeqoC,qBAAsBjlD,EAAEyjC,eAGvD,CAAEzjC,KA/BRA,EAAEsK,SAAWrK,EAAEqK,QACftK,EAAEyjC,cAAgBzjC,EAAEyjC,cAAcG,0BAA2B3jC,EAAEqjC,eAAgBrjC,EAAEqK,SACjFtK,EAAE4c,kBAAoB,GAAeqoC,qBAAsBjlD,EAAEyjC,eAEtD,CAAEzjC,MA8BXi3E,GAAmB,GAAgB,GAAgB,CAAEj3E,EAAGC,EAAGld,KAiB1D,GAAKid,EAAEyjC,cAAc9zB,QAAS1P,EAAEwjC,eAAkB,CACjD,IAAMzjC,EAAE2jC,oBAAsB1jC,EAAE0jC,kBAC/B,MAAO,CAAE,IAAI,GAAa,IAG3B,GAAK3jC,EAAE2jC,mBAAqB1jC,EAAE0jC,mBAAqB3jC,EAAE2jC,kBAAkBh0B,QAAS1P,EAAE0jC,mBACjF,MAAO,CAAE,IAAI,GAAa,IAK3B,GAA2B,eAAtB5gD,EAAQo3F,WASZ,OAPAn6E,EAAEsK,QAAU,EAKZtK,EAAE2jC,kBAAoB3jC,EAAE2jC,kBAAkBT,gCAAiCjjC,GAEpE,CAAED,GAgBX,GAAKA,EAAE2jC,mBAAqB1jC,EAAE0jC,mBAAqB3jC,EAAE2jC,kBAAkBh0B,QAAS1P,EAAE0jC,mBAAsB,CACvG,MAAMu5C,EAAgD,cAAjCl9E,EAAEyjC,cAAcvjD,KAAK0tB,SACpCuvE,EAAgD,cAAjCl9E,EAAEwjC,cAAcvjD,KAAK0tB,SAGpC8tE,EAAUwB,IAAiBC,EAQjC,GALgBA,IAAiBD,IAGDxB,GAAW34F,EAAQg3F,UAElC,CAChB,MAAM50F,EAAS,GAcf,OAVK8a,EAAEqK,SACNnlB,EAAOmB,KAAM,IAAI,GAAe2Z,EAAEyjC,mBAAoBzjC,EAAEqK,QAASrK,EAAEwjC,cAAe,IAK9EzjC,EAAEsK,SACNnlB,EAAOmB,KAAM,IAAI,GAAe0Z,EAAEyjC,cAAezjC,EAAEsK,QAAStK,EAAE0jC,mBAAoB,IAG5Ev+C,EAEP,MAAO,CAAE,IAAI,GAAa,IAa5B,GATK6a,EAAE2jC,oBACN3jC,EAAE2jC,kBAAoB3jC,EAAE2jC,kBAAkBT,gCAAiCjjC,IAQvED,EAAEyjC,cAAc9zB,QAAS1P,EAAE2c,oBAA6C,eAAtB75B,EAAQo3F,WAG9D,OAFAn6E,EAAEsK,UAEK,CAAEtK,GAOV,GAAKC,EAAEwjC,cAAc9zB,QAAS3P,EAAE4c,oBAA6C,eAAtB75B,EAAQs3F,WAA8B,CAC5F,MAAM+C,EAAkBn9E,EAAE2c,kBAAkB1pB,KAAKpI,QACjDsyF,EAAgB92F,KAAM,GAEtB,MAAM81B,EAAc,IAAI,GAAUnc,EAAE2c,kBAAkB18B,KAAMk9F,GAG5D,MAAO,CAAEp9E,EAFM,IAAI,GAAeA,EAAE4c,kBAAmB,EAAGR,EAAa,IAcxE,OAPKpc,EAAEyjC,cAAc23C,gBAAiBn7E,EAAEwjC,gBAAmBzjC,EAAEyjC,cAAc9zC,OAASsQ,EAAEwjC,cAAc9zC,SACnGqQ,EAAEsK,SAAWrK,EAAEqK,SAGhBtK,EAAEyjC,cAAgBzjC,EAAEyjC,cAAcP,gCAAiCjjC,GACnED,EAAE4c,kBAAoB,GAAeqoC,qBAAsBjlD,EAAEyjC,eAEtD,CAAEzjC,KCjvEK,MAAM,WAAoB0wE,GACxC,YAAa9wE,GACZ3c,MAAO2c,GAWPvc,KAAKg6F,OAAS,GAQdh6F,KAAKi6F,gBAAkB,IAAIrxD,QAG3B5oC,KAAK+pE,UAEL/pE,KAAKmR,SAAUoL,EAAO5c,KAAM,MAAO,IAAMK,KAAKk6F,cAM/C,UACCl6F,KAAKsvC,UAAYtvC,KAAKg6F,OAAOj4F,OAAS,EASvC,SAAUopD,GACT,MAAMgvC,EAAen6F,KAAKuc,OAAOysC,MAAMhoD,SAASopB,UAE1CA,EAAY,CACjByD,OAAQssE,EAAarwC,YAAc3gD,MAAMiK,KAAM+mF,EAAajqE,aAAgB,GAC5EF,WAAYmqE,EAAanqE,YAG1BhwB,KAAKg6F,OAAO/2F,KAAM,CAAEkoD,QAAO/gC,cAC3BpqB,KAAK+pE,UAMN,aACC/pE,KAAKg6F,OAAS,GACdh6F,KAAK+pE,UAYN,kBAAmBl8C,EAAQmC,EAAYkxB,GACtC,MAAM8H,EAAQhpD,KAAKuc,OAAOysC,MACpBhoD,EAAWgoD,EAAMhoD,SAGjBo5F,EAAkB,GAGlBC,EAAyBxsE,EAAOxjB,IAAK4kB,GAASA,EAAMqrE,2BAA4Bp5C,IAChFq5C,EAAYF,EAAuB13B,OAEzC,IAAM,MAAM63B,KAAcH,EAAyB,CAElD,MAAM35C,EAAc85C,EAClBx2F,OAAQirB,GAASA,EAAMpyB,MAAQmE,EAAS6/C,WACxC78C,OAAQirB,IAAUwrE,GAAiCxrE,EAAOsrE,IAGtD75C,EAAY3+C,SAMlB24F,GAAiBh6C,GAKjB05C,EAAgBn3F,KAAMy9C,EAAa,KAM/B05C,EAAgBr4F,QACpBinD,EAAM5L,OAAQprB,IACbA,EAAOyI,aAAc2/D,EAAiB,CAAEzpE,SAAUX,MAarD,MAAO2qE,EAAaC,GACnB,MAAM5xC,EAAQhpD,KAAKuc,OAAOysC,MACpBhoD,EAAWgoD,EAAMhoD,SAGvBhB,KAAKi6F,gBAAgBrrF,IAAKgsF,GAE1B,MAAMC,EAAmBF,EAAYz5C,WAAWz5C,QAAQzD,OAAQ07C,GAAaA,EAAU8J,qBACvFqxC,EAAiB/6D,UAIjB,IAAM,MAAMg7D,KAAmBD,EAAmB,CACjD,MAAME,EAAkBD,EAAgB76B,YAAc,EAChD+6B,EAAoB7xF,MAAMiK,KAAMpS,EAAS0oE,QAAQuxB,cAAeF,IAahEG,EAXkB/G,GACvB,CAAE2G,EAAgBrC,eAClBuC,EACA,CACCzG,cAAc,EACdvzF,SAAUhB,KAAKuc,OAAOysC,MAAMhoD,SAC5Bw0F,cAAc,EACdhB,iBAAiB,IAIwBJ,YAG3C,IAAM,MAAM10C,KAAaw7C,EAExBN,EAAa54B,aAActiB,GAC3BsJ,EAAMiZ,eAAgBviB,GAEtB1+C,EAAS0oE,QAAQyxB,qBAAsBL,EAAiBp7C,KAU5D,SAASg7C,GAAiB7sE,GACzBA,EAAO3J,KAAM,CAAEvH,EAAGC,IAAOD,EAAEkE,MAAMhD,SAAUjB,EAAEiE,QAAW,EAAI,GAE5D,IAAM,IAAItjB,EAAI,EAAGA,EAAIswB,EAAO9rB,OAAQxE,IAAM,CACzC,MACM69F,EADgBvtE,EAAQtwB,EAAI,GACA89F,UAAWxtE,EAAQtwB,IAAK,GAErD69F,IAEJ79F,IACAswB,EAAO/nB,OAAQvI,EAAG,EAAG69F,KAKxB,SAASX,GAAiCxrE,EAAOpB,GAChD,OAAOA,EAAOsL,KAAM5L,GAAcA,IAAe0B,GAAS1B,EAAW8zB,cAAepyB,GAAO,ICpL7E,MAAM,WAAoB,GAUxC,QAASk8B,EAAQ,MAEhB,MAAMmwC,EAAanwC,EAAQnrD,KAAKg6F,OAAOuB,UAAW5+E,GAAKA,EAAEwuC,OAASA,GAAUnrD,KAAKg6F,OAAOj4F,OAAS,EAE3FM,EAAOrC,KAAKg6F,OAAOl0F,OAAQw1F,EAAY,GAAK,GAC5CV,EAAe56F,KAAKuc,OAAOysC,MAAMomC,YAAa,eAIpDpvF,KAAKuc,OAAOysC,MAAMqC,cAAeuvC,EAAc,KAC9C56F,KAAKw7F,MAAOn5F,EAAK8oD,MAAOyvC,GAExB,MAAM15C,EAAalhD,KAAKuc,OAAOysC,MAAMhoD,SAAS0oE,QAAQuxB,cAAe54F,EAAK8oD,MAAM8U,aAChFjgE,KAAKy7F,kBAAmBp5F,EAAK+nB,UAAUyD,OAAQxrB,EAAK+nB,UAAU4F,WAAYkxB,GAE1ElhD,KAAKqU,KAAM,SAAUhS,EAAK8oD,MAAOyvC,KAGlC56F,KAAK+pE,WC3BQ,MAAM,WAAoB,GASxC,UACC,MAAM1nE,EAAOrC,KAAKg6F,OAAO5wF,MACnBsyF,EAAe17F,KAAKuc,OAAOysC,MAAMomC,YAAa,eAIpDpvF,KAAKuc,OAAOysC,MAAMqC,cAAeqwC,EAAc,KAC9C,MACMX,EADgB14F,EAAK8oD,MAAMjK,WAAY7+C,EAAK8oD,MAAMjK,WAAWn/C,OAAS,GACtCk+D,YAAc,EAC9C/e,EAAalhD,KAAKuc,OAAOysC,MAAMhoD,SAAS0oE,QAAQuxB,cAAeF,GAErE/6F,KAAKy7F,kBAAmBp5F,EAAK+nB,UAAUyD,OAAQxrB,EAAK+nB,UAAU4F,WAAYkxB,GAC1ElhD,KAAKw7F,MAAOn5F,EAAK8oD,MAAOuwC,KAGzB17F,KAAK+pE,WCzBQ,MAAM,WAAoB,GAIxC,wBACC,MAAO,cAMR,YAAaxtD,GACZ3c,MAAO2c,GAwBPvc,KAAK27F,eAAiB,IAAI/yD,QAM3B,OACC,MAAMrsB,EAASvc,KAAKuc,OAGpBvc,KAAK47F,aAAe,IAAI,GAAar/E,GACrCvc,KAAK67F,aAAe,IAAI,GAAat/E,GAGrCA,EAAO24C,SAAStmD,IAAK,OAAQ5O,KAAK47F,cAClCr/E,EAAO24C,SAAStmD,IAAK,OAAQ5O,KAAK67F,cAElC77F,KAAKmR,SAAUoL,EAAOysC,MAAO,iBAAkB,CAAElyC,EAAKzF,KACrD,MAAMquC,EAAYruC,EAAM,GAOxB,IAAMquC,EAAU8J,oBACf,OAGD,MAAM2B,EAAQzL,EAAUyL,MAElB2wC,EAAc97F,KAAK67F,aAAa5B,gBAAgBvwF,IAAKyhD,GACrD4wC,EAAc/7F,KAAK47F,aAAa3B,gBAAgBvwF,IAAKyhD,GACjCnrD,KAAK27F,eAAejyF,IAAKyhD,IAGT,eAAdA,EAAMlrD,OAA0B67F,IAAgBC,IAGtED,EAEJ97F,KAAK47F,aAAaI,SAAU7wC,GAChB4wC,IAGZ/7F,KAAK47F,aAAaI,SAAU7wC,GAC5BnrD,KAAK67F,aAAa3B,cAKpBl6F,KAAK27F,eAAe/sF,IAAKu8C,KACvB,CAAE16C,SAAU,YAEfzQ,KAAKmR,SAAUnR,KAAK47F,aAAc,SAAU,CAAE9kF,EAAKmlF,EAAarB,KAC/D56F,KAAK67F,aAAaG,SAAUpB,KAG7Br+E,EAAOi4D,WAAW/qE,IAAK,SAAU,QACjC8S,EAAOi4D,WAAW/qE,IAAK,SAAU,QACjC8S,EAAOi4D,WAAW/qE,IAAK,eAAgB,SCpH1B,oVCAA,iVCoBA,MAAM,WAAe,GAInC,OACC,MAAM8S,EAASvc,KAAKuc,OACdN,EAASM,EAAON,OAChBxd,EAAI8d,EAAO9d,EAEXy9F,EAAkD,OAA9BjgF,EAAOX,oBAA+B6gF,GAAWC,GACrEC,EAAkD,OAA9BpgF,EAAOX,oBAA+B8gF,GAAWD,GAE3En8F,KAAKs8F,WAAY,OAAQ79F,EAAG,QAAU,SAAUy9F,GAChDl8F,KAAKs8F,WAAY,OAAQ79F,EAAG,QAAU,SAAU49F,GAYjD,WAAYv+F,EAAM4yB,EAAOkE,EAAW2nE,GACnC,MAAMhgF,EAASvc,KAAKuc,OAEpBA,EAAOL,GAAG+5D,iBAAiBrnE,IAAK9Q,EAAMme,IACrC,MAAM+4C,EAAUz4C,EAAO24C,SAAS92D,IAAKN,GAC/B43B,EAAO,IAAI,GAAYzZ,GAgB7B,OAdAyZ,EAAKjsB,IAAK,CACTinB,QACA01D,KAAMmW,EACN3nE,YACA0xD,SAAS,IAGV5wD,EAAK32B,KAAM,aAAc6U,GAAIohD,EAAS,aAEtCh1D,KAAKmR,SAAUukB,EAAM,UAAW,KAC/BnZ,EAAO04C,QAASn3D,GAChBye,EAAO83D,QAAQ3+C,KAAK7F,UAGd6F,KCsCK,MAAM,WAAa,GAIjC,sBACC,MAAO,CAAE,GAAa,IAMvB,wBACC,MAAO,QCvFM,MAAM8mE,GAMpB,YAAa98F,GAOZM,KAAKN,QAAUA,EAMhB,UACCM,KAAKsR,gBAMN,6BACC,OAAO,GAITkD,GAAKgoF,GAAe,ICNL,MAAM,WAAuBA,GAI3C,wBACC,MAAO,iBAMR,OAQCx8F,KAAKyJ,IAAK,UAAU,GAQpBzJ,KAAKy8F,SAAW,IAAI,GAAY,CAAErnF,WAAY,QAC9CpV,KAAKy8F,SAASlrE,SAAU,MAAO,UAAW3d,GAAI5T,MAY/C,IAAKK,GACJ,GAAwB,iBAAZA,EAMX,MAAM,IAAI,KAAe,qCAAsCL,MAGhE,MAAMgjC,EAAS/kC,OAAOY,OAAQ,IAM9B,OAJAmkC,EAAOv5B,IAAK,UAAWpJ,GACvBL,KAAKy8F,SAAS7tF,IAAKo0B,GACnBhjC,KAAK08F,QAAS,EAEP15D,EAQR,OAAQA,GACPhjC,KAAKy8F,SAASt4F,OAAQ6+B,GACtBhjC,KAAK08F,SAAW18F,KAAKy8F,SAAS16F,OAQ/B,YACC,OAAO/B,KAAKy8F,SAASr+F,IAAK,GAQ3B,CAAEE,OAAOiW,YACR,OAAOvU,KAAKy8F,SAAUn+F,OAAOiW,aCzHhB,MAAMooF,GAIpB,cACC,MAAMC,EAAS,IAAIz/F,OAAOw/F,WAQ1B38F,KAAK68F,QAAUD,EAEf58F,KAAKy9B,WAAQn3B,EASbtG,KAAKyJ,IAAK,SAAU,GAEpBmzF,EAAOE,WAAahmF,IACnB9W,KAAKsY,OAASxB,EAAIwB,QASpB,YACC,OAAOtY,KAAK68F,QAAQz8F,MASrB,WACC,OAAOJ,KAAKy9B,MAUb,KAAMs/D,GACL,MAAMH,EAAS58F,KAAK68F,QAGpB,OAFA78F,KAAKg9F,MAAQD,EAAK/zF,KAEX,IAAI+P,QAAS,CAAE/L,EAASgM,KAC9B4jF,EAAOK,OAAS,KACf,MAAMn7F,EAAS86F,EAAO96F,OAEtB9B,KAAKy9B,MAAQ37B,EAEbkL,EAASlL,IAGV86F,EAAOM,QAAU,KAChBlkF,EAAQ,UAGT4jF,EAAOO,QAAU,KAChBnkF,EAAQ,YAGThZ,KAAK68F,QAAQO,cAAeL,KAO9B,QACC/8F,KAAK68F,QAAQQ,SAIf7oF,GAAKmoF,GAAY,ICxEF,MAAM,WAAuB,GAI3C,wBACC,MAAO,iBAMR,sBACC,MAAO,CAAE,IAMV,OAMC38F,KAAKs9F,QAAU,IAAI,GAGnBt9F,KAAKs9F,QAAQp0E,GAAI,MAAO,IAAMlpB,KAAKu9F,wBACnCv9F,KAAKs9F,QAAQp0E,GAAI,SAAU,IAAMlpB,KAAKu9F,wBAQtCv9F,KAAKw9F,YAAc,IAAI1pF,IASvB9T,KAAKy9F,eAAiB,KAqBtBz9F,KAAKyJ,IAAK,WAAY,GAatBzJ,KAAKyJ,IAAK,cAAe,MASzBzJ,KAAKjB,KAAM,mBAAoB6U,GAAI5T,KAAM,WAAYA,KAAM,cAAe,CAAE09F,EAAUV,IAC9EA,EAAUU,EAAWV,EAAQ,IAAQ,GAY9C,UAAWW,GACV,OAAO39F,KAAKw9F,YAAYp/F,IAAKu/F,IAAmB,KAWjD,aAAcA,GACb,IAAM39F,KAAK49F,oBAyBV,OAFA,aAAY,oCAEL,KAGR,MAAMC,EAAS,IAAI,GAAY9kF,QAAQ/L,QAAS2wF,GAAiB39F,KAAK49F,qBAuCtE,OArCA59F,KAAKs9F,QAAQ1uF,IAAKivF,GAClB79F,KAAKw9F,YAAY/zF,IAAKk0F,EAAeE,GAGhCF,aAAyB5kF,SAC7B8kF,EAAOd,KACL7jF,KAAM6jF,IACN/8F,KAAKw9F,YAAY/zF,IAAKszF,EAAMc,KAK5BjkF,MAAO,QAGVikF,EAAO30E,GAAI,kBAAmB,KAC7B,IAAI40E,EAAqB,EAEzB,IAAM,MAAMD,KAAU79F,KAAKs9F,QAC1BQ,GAAsBD,EAAOH,SAG9B19F,KAAK09F,SAAWI,IAGjBD,EAAO30E,GAAI,qBAAsB,KAChC,IAAI60E,EAAkB,EAEtB,IAAM,MAAMF,KAAU79F,KAAKs9F,QACrBO,EAAOG,cACXD,GAAmBF,EAAOG,aAI5Bh+F,KAAKg+F,YAAcD,IAGbF,EASR,cAAeI,GACd,MAAMJ,EAASI,aAAiC,GAAaA,EAAwBj+F,KAAKk+F,UAAWD,GAErGJ,EAAOM,WAEPn+F,KAAKs9F,QAAQn5F,OAAQ05F,GAErB79F,KAAKw9F,YAAY/5F,QAAS,CAAEjF,EAAOM,KAC7BN,IAAUq/F,GACd79F,KAAKw9F,YAAYzpF,OAAQjV,KAU5B,uBACC,MAAMs/F,EAAiBp+F,KAAKuc,OAAOtE,QAAQ7Z,IAAK,IAEhD,GAAK4B,KAAKs9F,QAAQv7F,QACjB,IAAM/B,KAAKy9F,eAAiB,CAC3B,MAAMh/F,EAAIuB,KAAKuc,OAAO9d,EAChB4/F,EAAa7/F,GAAS,GAAIC,EAAG,yBAA4B+1C,SAAUh2C,OAEzEwB,KAAKy9F,eAAiBW,EAAexvF,IAAKyvF,EAAYr+F,KAAKs+F,kBAC3Dt+F,KAAKy9F,eAAe1+F,KAAM,WAAY6U,GAAI5T,KAAM,kBAAmBq+F,SAGpED,EAAej6F,OAAQnE,KAAKy9F,gBAC5Bz9F,KAAKy9F,eAAiB,MAKzBjpF,GAAK,GAAgB,IAOrB,MAAM,GAOL,YAAa+pF,EAAaC,GAOzBx+F,KAAKsC,GAAK,KAQVtC,KAAKy+F,oBAAsBz+F,KAAK0+F,0BAA2BH,GAQ3Dv+F,KAAK2+F,SAAWH,EAAsBx+F,MAQtCA,KAAK68F,QAAU,IAAIF,GA2BnB38F,KAAKyJ,IAAK,SAAU,QASpBzJ,KAAKyJ,IAAK,WAAY,GAStBzJ,KAAKyJ,IAAK,cAAe,MASzBzJ,KAAKjB,KAAM,mBAAoB6U,GAAI5T,KAAM,WAAYA,KAAM,cAAe,CAAE09F,EAAUV,IAC9EA,EAAUU,EAAWV,EAAQ,IAAQ,GAU7Ch9F,KAAKyJ,IAAK,iBAAkB,MAQ7B,WACC,OAAMzJ,KAAKy+F,oBAYHz+F,KAAKy+F,oBAAoB1kF,QAAQb,KAAM6jF,GAAQ/8F,KAAKy+F,oBAAsB1B,EAAO,MAVjFhkF,QAAQ/L,QAAS,MAoB1B,WACC,OAAOhN,KAAK68F,QAAQl9F,KAwBrB,OACC,GAAoB,QAAfK,KAAK4+F,OAMT,MAAM,IAAI,KAAe,mCAAoC5+F,MAK9D,OAFAA,KAAK4+F,OAAS,UAEP5+F,KAAK+8F,KACV7jF,KAAM6jF,GAAQ/8F,KAAK68F,QAAQgC,KAAM9B,IACjC7jF,KAAMvZ,IAGN,GAAqB,YAAhBK,KAAK4+F,OACT,MAAM5+F,KAAK4+F,OAKZ,OAFA5+F,KAAK4+F,OAAS,OAEPj/F,IAEPia,MAAO1Z,IACP,GAAa,YAARA,EAEJ,MADAF,KAAK4+F,OAAS,UACR,UAIP,MADA5+F,KAAK4+F,OAAS,QACR5+F,KAAK68F,QAAQz8F,MAAQJ,KAAK68F,QAAQz8F,MAAQF,IAwBnD,SACC,GAAoB,QAAfF,KAAK4+F,OAMT,MAAM,IAAI,KAAe,qCAAsC5+F,MAKhE,OAFAA,KAAK4+F,OAAS,YAEP5+F,KAAK+8F,KACV7jF,KAAM,IAAMlZ,KAAK2+F,SAASG,UAC1B5lF,KAAMvZ,IACNK,KAAK++F,eAAiBp/F,EACtBK,KAAK4+F,OAAS,OAEPj/F,IAEPia,MAAO1Z,IACP,GAAqB,YAAhBF,KAAK4+F,OACT,KAAM,UAIP,MADA5+F,KAAK4+F,OAAS,QACR1+F,IAOT,QACC,MAAM0+F,EAAS5+F,KAAK4+F,OACpB5+F,KAAK4+F,OAAS,UAER5+F,KAAKy+F,oBAAoBO,YAOT,WAAVJ,EACX5+F,KAAK68F,QAAQQ,QACQ,aAAVuB,GAAyB5+F,KAAK2+F,SAAStB,OAClDr9F,KAAK2+F,SAAStB,SANdr9F,KAAKy+F,oBAAoB1kF,QAAQH,MAAO,QAExC5Z,KAAKy+F,oBAAoBQ,SAAU,YAOpCj/F,KAAKm+F,WAQN,WACCn+F,KAAKy+F,yBAAsBn4F,EAC3BtG,KAAK68F,aAAUv2F,EACftG,KAAK2+F,cAAWr4F,EAChBtG,KAAK++F,oBAAiBz4F,EAWvB,0BAA2Bi4F,GAC1B,MAAMhiE,EAAU,GAiBhB,OAfAA,EAAQxiB,QAAU,IAAIhB,QAAS,CAAE/L,EAASgM,KACzCujB,EAAQ0iE,SAAWjmF,EACnBujB,EAAQyiE,aAAc,EAEtBT,EACErlF,KAAM6jF,IACNxgE,EAAQyiE,aAAc,EACtBhyF,EAAS+vF,KAETnjF,MAAO1Z,IACPq8B,EAAQyiE,aAAc,EACtBhmF,EAAQ9Y,OAIJq8B,GAIT/nB,GAAK,GAAY,IC7iBV,SAAS0qF,KACf,IAAIC,EAgBE,SAAoBrhG,GAC1BA,EAAOA,EAAK20B,cACZ,MAAMnjB,EAAQtO,SAASo+F,OAAO7vF,MAAO,KAErC,IAAM,MAAMC,KAAQF,EAAQ,CAC3B,MAAM+vF,EAAO7vF,EAAKD,MAAO,KAGzB,GAFY+vF,mBAAoBD,EAAM,GAAI/7E,OAAOmP,iBAEpC30B,EACZ,OAAOwhG,mBAAoBD,EAAM,IAInC,OAAO,KA7BKE,CAZa,eAkDnB,IAAoBzhG,EAAMU,EA/BhC,OALM2gG,GAbc,IAaLA,EAAMp9F,SACpBo9F,EA4CF,SAAwBp9F,GACvB,IAAID,EAAS,GACb,MAAM09F,EAAa,IAAIryF,WAAYpL,GAEnC5E,OAAOsiG,OAAOC,gBAAiBF,GAE/B,IAAM,IAAIp+C,EAAI,EAAGA,EAAIo+C,EAAWz9F,OAAQq/C,IAAM,CAC7C,MAAMmoB,EAhEa,uCAgEYpmD,OAAQq8E,EAAYp+C,GAhEhC,uCAgEmDr/C,QACtED,GAAUsO,KAAKC,SAAW,GAAMk5D,EAAUo2B,cAAgBp2B,EAG3D,OAAOznE,EAvDE89F,CAdW,IAiDM9hG,EAlDD,cAkDOU,EAlCD2gG,EAmC/Bn+F,SAASo+F,OAASr6F,mBAAoBjH,GAAS,IAAMiH,mBAAoBvG,GAAU,WAhC5E2gG,ECHO,MAAM,WAA8B,GAIlD,sBACC,MAAO,CAAE,IAMV,wBACC,MAAO,wBAMR,OACC,MAAMU,EAAM7/F,KAAKuc,OAAOV,OAAOzd,IAAK,sBAE9ByhG,IAKN7/F,KAAKuc,OAAOtE,QAAQ7Z,IAAK,IAAiBw/F,oBAAsBC,GAAU,IAAI,GAAeA,EAAQgC,EAAK7/F,KAAKuc,OAAO9d,KAUxH,MAAM,GAQL,YAAao/F,EAAQgC,EAAKphG,GAMzBuB,KAAK69F,OAASA,EAOd79F,KAAK6/F,IAAMA,EAOX7/F,KAAKvB,EAAIA,EASV,SACC,OAAOuB,KAAK69F,OAAOd,KAAK7jF,KAAM6jF,GACtB,IAAIhkF,QAAS,CAAE/L,EAASgM,KAC9BhZ,KAAK8/F,eACL9/F,KAAK+/F,eAAgB/yF,EAASgM,EAAQ+jF,GACtC/8F,KAAKggG,aAAcjD,MAUtB,QACM/8F,KAAKigG,KACTjgG,KAAKigG,IAAI5C,QASX,eACC,MAAM4C,EAAMjgG,KAAKigG,IAAM,IAAIC,eAE3BD,EAAIE,KAAM,OAAQngG,KAAK6/F,KAAK,GAC5BI,EAAIG,aAAe,OAWpB,eAAgBpzF,EAASgM,EAAQ+jF,GAChC,MAAMkD,EAAMjgG,KAAKigG,IACXpC,EAAS79F,KAAK69F,OAEdwC,GAAe5hG,EADXuB,KAAKvB,GACS,uBAA0B,IAAKs+F,EAAKj/F,QAE5DmiG,EAAIhxD,iBAAkB,QAAS,IAAMj2B,EAAQqnF,IAC7CJ,EAAIhxD,iBAAkB,QAAS,IAAMj2B,KACrCinF,EAAIhxD,iBAAkB,OAAQ,KAC7B,MAAMqxD,EAAWL,EAAIK,SAErB,IAAMA,IAAaA,EAAS5C,SAC3B,OAAO1kF,EAAQsnF,GAAYA,EAASlgG,OAASkgG,EAASlgG,MAAMC,QAAUigG,EAASlgG,MAAMC,QAAUggG,GAGhGrzF,EAAS,CACR7F,QAASm5F,EAAST,QAMfI,EAAInB,QACRmB,EAAInB,OAAO7vD,iBAAkB,WAAYn4B,IACnCA,EAAIypF,mBACR1C,EAAOG,YAAclnF,EAAIkmF,MACzBa,EAAOH,SAAW5mF,EAAIwB,UAY1B,aAAcykF,GAEb,MAAMp9F,EAAO,IAAI6gG,SACjB7gG,EAAKk8D,OAAQ,SAAUkhC,GACvBp9F,EAAKk8D,OAAQ,cAAeqjC,MAG5Bl/F,KAAKigG,IAAIQ,KAAM9gG,IC3KF,SAAS,GAAOshB,GAC9B,MAAMy/E,EAAez/E,EAASsK,OAE9B,OAAKm1E,EAAar1E,KACV,KAGDq1E,EAAaliG,MC+BN,SAASmiG,GAAwBpkF,EAAQvE,EAAQyG,EAASmiF,GACxE,IAAI1vF,EACA8jD,EAAU,KAEmB,mBAArB4rC,EACX1vF,EAAW0vF,GAGX5rC,EAAUz4C,EAAO24C,SAAS92D,IAAKwiG,GAE/B1vF,EAAW,KACVqL,EAAO04C,QAAS2rC,KAIlBrkF,EAAOysC,MAAMhoD,SAASkoB,GAAI,cAAe,CAAEpS,EAAKq0C,KAC/C,GAAK6J,IAAYA,EAAQ1lB,YAAct3B,EAAOs3B,UAC7C,OAGD,MAAMrgB,EAAQ,GAAO1S,EAAOysC,MAAMhoD,SAASopB,UAAU8F,aAErD,IAAMjB,EAAMxB,YACX,OAGD,GAAmB,eAAd09B,EAAMlrD,KACV,OAGD,MAAMqlD,EAAUn8C,MAAMiK,KAAMmJ,EAAOysC,MAAMhoD,SAASkkD,OAAOyC,cACnDn+C,EAAQ87C,EAAS,GAGvB,GAAuB,GAAlBA,EAAQvjD,QAA8B,WAAfyH,EAAMvJ,MAAmC,SAAduJ,EAAM1L,MAAmC,GAAhB0L,EAAMzH,OACrF,OAGD,MAAM8+F,EAAgBr3F,EAAMqhB,SAAS9N,OAGrC,GAAK8jF,EAAc1gG,GAAI,UAAW,aACjC,OAKD,GAAK60D,IAA6B,IAAlBA,EAAQx2D,MACvB,OAGD,MAAMsiG,EAAYD,EAAc3jF,SAAU,GACpC6jF,EAAiBxkF,EAAOysC,MAAMjC,cAAe+5C,GAGnD,IAAMC,EAAe1/C,cAAepyB,KAAYA,EAAMnO,IAAIwL,QAASy0E,EAAejgF,KACjF,OAGD,MAAMpF,EAAQ+C,EAAQ5U,KAAMi3F,EAAUnhG,KAAK0S,OAAQ,EAAG4c,EAAMnO,IAAIxU,SAG1DoP,GAKNa,EAAOysC,MAAMqC,cAAer5B,IAE3B,MAAMnR,EAAQmR,EAAOo/B,iBAAkByvC,EAAe,GAChD//E,EAAMkR,EAAOo/B,iBAAkByvC,EAAenlF,EAAO,GAAI3Z,QACzDktB,EAAQ,IAAI,GAAWpO,EAAOC,IAKhB,IAHD5P,EAAU,CAAEwK,WAI9BsW,EAAO7tB,OAAQ8qB,GAGhBA,EAAMid,aC9DM,SAAS80D,GAAyBzkF,EAAQvE,EAAQipF,EAAsBC,GACtF,IAAIC,EACAC,EAECH,aAAgCh3F,OACpCk3F,EAASF,EAETG,EAAeH,EAIhBG,EAAeA,GAAgB,CAAE7uD,IAChC,IAAIzwC,EACJ,MAAMqC,EAAS,GACTk9F,EAAS,GAEf,KAA6C,QAAnCv/F,EAASq/F,EAAOt3F,KAAM0oC,OAE1BzwC,GAAUA,EAAOC,OAAS,IAFoB,CAMnD,IAAI,MACHW,EACA,EAAK4+F,EACL,EAAKp6F,EACL,EAAKq6F,GACFz/F,EAGJ,MAAMiuB,EAAQuxE,EAAUp6F,EAAUq6F,EAClC7+F,GAASZ,EAAQ,GAAIC,OAASguB,EAAMhuB,OAGpC,MAAMy/F,EAAW,CAChB9+F,EACAA,EAAQ4+F,EAAQv/F,QAEX0/F,EAAS,CACd/+F,EAAQ4+F,EAAQv/F,OAASmF,EAAQnF,OACjCW,EAAQ4+F,EAAQv/F,OAASmF,EAAQnF,OAASw/F,EAASx/F,QAGpDoC,EAAOlB,KAAMu+F,GACbr9F,EAAOlB,KAAMw+F,GAEbJ,EAAOp+F,KAAM,CAAEP,EAAQ4+F,EAAQv/F,OAAQW,EAAQ4+F,EAAQv/F,OAASmF,EAAQnF,SAGzE,MAAO,CACNoC,SACAk9F,YAIF9kF,EAAOysC,MAAMhoD,SAASkoB,GAAI,cAAe,CAAEpS,EAAKq0C,KAC/C,GAAmB,eAAdA,EAAMlrD,OAA0B+X,EAAOs3B,UAC3C,OAGD,MAAM0Z,EAAQzsC,EAAOysC,MACf5+B,EAAY4+B,EAAMhoD,SAASopB,UAGjC,IAAMA,EAAUqD,YACf,OAGD,MAAM63B,EAAUn8C,MAAMiK,KAAM41C,EAAMhoD,SAASkkD,OAAOyC,cAC5Cn+C,EAAQ87C,EAAS,GAGvB,GAAuB,GAAlBA,EAAQvjD,QAA8B,WAAfyH,EAAMvJ,MAAmC,SAAduJ,EAAM1L,MAAmC,GAAhB0L,EAAMzH,OACrF,OAGD,MAAM8tB,EAAQzF,EAAUyF,MAClB44B,EAAQ54B,EAAM9S,QACd,KAAEw1B,EAAI,MAAEtjB,GAiDhB,SAA2BA,EAAO+5B,GACjC,IAAInoC,EAAQoO,EAAMpO,MAalB,MAAO,CAAE0xB,KAXIppC,MAAMiK,KAAM6b,EAAMq4B,YAAajwC,OAAQ,CAAEqqF,EAAWnvF,KAExDA,EAAKpS,GAAI,WAAaoS,EAAKpS,GAAI,eAAoBoS,EAAK6M,aAAc,SAC7EyB,EAAQmoC,EAAM2T,oBAAqBpqD,GAE5B,IAGDmvF,EAAYnvF,EAAK5S,KACtB,IAEYsvB,MAAO+5B,EAAM1iB,YAAazlB,EAAOoO,EAAMnO,MA/D7B6gF,CAAkB34C,EAAM1iB,YAAa0iB,EAAMoI,iBAAkB3I,EAAO,GAAK54B,GAASm5B,GACpG44C,EAAaR,EAAc7uD,GAC3BsvD,EAAiBC,GAAoB7yE,EAAMpO,MAAO+gF,EAAWP,OAAQr4C,GACrE+4C,EAAiBD,GAAoB7yE,EAAMpO,MAAO+gF,EAAWz9F,OAAQ6kD,GAEnE64C,EAAe9/F,QAAUggG,EAAehgG,QAKhDinD,EAAMqC,cAAer5B,IAKpB,IAAoB,IAHDkvE,EAAgBlvE,EAAQ6vE,GAQ3C,IAAM,MAAM5yE,KAAS8yE,EAAejiE,UACnC9N,EAAO7tB,OAAQ8qB,OAanB,SAAS6yE,GAAoBjhF,EAAOmhF,EAAQh5C,GAC3C,OAAOg5C,EACLh+F,OAAQkF,QAA0B5C,IAAf4C,EAAO,SAAoC5C,IAAf4C,EAAO,IACtDmB,IAAKnB,GACE8/C,EAAM1iB,YAAazlB,EAAMyN,aAAcplB,EAAO,IAAO2X,EAAMyN,aAAcplB,EAAO,MCZ1F,SAAS+4F,GAAwC1lF,EAAQqpC,GACxD,MAAO,CAAE5zB,EAAQ6vE,KAGhB,IAFgBtlF,EAAO24C,SAAS92D,IAAKwnD,GAEvBtW,UACb,OAAO,EAGR,MAAM4yD,EAAc3lF,EAAOysC,MAAMC,OAAOk5C,eAAgBN,EAAgBj8C,GAExE,IAAM,MAAM32B,KAASizE,EACpBlwE,EAAOtuB,aAAckiD,GAAc,EAAM32B,GAK1C+C,EAAOysC,yBAA0B7Y,ICxKpB,MAAM,WAAyBynC,GAK7C,YAAa9wE,EAAQqpC,GACpBhmD,MAAO2c,GAQPvc,KAAK4lD,aAAeA,EAmBrB,UACC,MAAMoD,EAAQhpD,KAAKuc,OAAOysC,MACpB5hB,EAAM4hB,EAAMhoD,SAElBhB,KAAKxB,MAAQwB,KAAKoiG,gCAClBpiG,KAAKsvC,UAAY0Z,EAAMC,OAAOo5C,0BAA2Bj7D,EAAIhd,UAAWpqB,KAAK4lD,cAuB9E,QAAS1jD,EAAU,IAClB,MAAM8mD,EAAQhpD,KAAKuc,OAAOysC,MAEpB5+B,EADM4+B,EAAMhoD,SACIopB,UAChB5rB,OAAiC8H,IAAvBpE,EAAQogG,YAA8BtiG,KAAKxB,MAAQ0D,EAAQogG,WAE3Et5C,EAAM5L,OAAQprB,IACb,GAAK5H,EAAUqD,YACTjvB,EACJwzB,EAAO87D,sBAAuB9tF,KAAK4lD,cAAc,GAEjD5zB,EAAOysC,yBAA0Bz+D,KAAK4lD,kBAEjC,CACN,MAAM/3B,EAASm7B,EAAMC,OAAOk5C,eAAgB/3E,EAAU8F,YAAalwB,KAAK4lD,cAExE,IAAM,MAAM32B,KAASpB,EACfrvB,EACJwzB,EAAOtuB,aAAc1D,KAAK4lD,aAAcpnD,EAAOywB,GAE/C+C,EAAOptB,gBAAiB5E,KAAK4lD,aAAc32B,MAchD,gCACC,MAAM+5B,EAAQhpD,KAAKuc,OAAOysC,MACpBC,EAASD,EAAMC,OACf7+B,EAAY4+B,EAAMhoD,SAASopB,UAEjC,GAAKA,EAAUqD,YACd,OAAOrD,EAAUlL,aAAclf,KAAK4lD,cAGrC,IAAM,MAAM32B,KAAS7E,EAAU8F,YAC9B,IAAM,MAAM7tB,KAAQ4sB,EAAMq4B,WACzB,GAAK2B,EAAO4K,eAAgBxxD,EAAMrC,KAAK4lD,cACtC,OAAOvjD,EAAK6c,aAAclf,KAAK4lD,cAKlC,OAAO,GCjHM,MAAM,WAAoB,GAIxC,wBACC,MAAO,cAMR,OACC,MAAMrpC,EAASvc,KAAKuc,OAEpBA,EAAOysC,MAAMC,OAAOlyB,OAAQ,QAAS,CAAEigC,gBAxB5B,SAyBXz6C,EAAOysC,MAAMC,OAAOs5C,uBAzBT,OAyBuC,CACjDrV,cAAc,EACdQ,aAAa,IAIdnxE,EAAO+3D,WAAW9U,mBAAoB,CACrCxW,MAhCU,OAiCVtzB,KAAM,SACNkqC,WAAY,CACX,IACA9kC,IACC,MAAM0nE,EAAa1nE,EAAYnb,SAAU,eAEzC,OAAM6iF,EAKa,QAAdA,GAAwBtnF,OAAQsnF,IAAgB,IAC7C,CACN1kG,MAAM,EACN2hB,OAAQ,CAAE,qBAHZ,EAJQ,SAeXlD,EAAO24C,SAAStmD,IAvDL,OAuDgB,IAAI,GAAkB2N,EAvDtC,SA0DXA,EAAOi4D,WAAW/qE,IAAK,SA1DZ,SCSE,MAAM,WAAe,GAInC,OACC,MAAM8S,EAASvc,KAAKuc,OACd9d,EAAI8d,EAAO9d,EAGjB8d,EAAOL,GAAG+5D,iBAAiBrnE,IAhBhB,OAgB2BqN,IACrC,MAAM+4C,EAAUz4C,EAAO24C,SAAS92D,IAjBtB,QAkBJs3B,EAAO,IAAI,GAAYzZ,GAkB7B,OAhBAyZ,EAAKjsB,IAAK,CACTinB,MAAOjyB,EAAG,QACV2nF,KCpCW,suBDqCXxxD,UAAW,SACX0xD,SAAS,EACTL,cAAc,IAGfvwD,EAAK32B,KAAM,OAAQ,aAAc6U,GAAIohD,EAAS,QAAS,aAGvDh1D,KAAKmR,SAAUukB,EAAM,UAAW,KAC/BnZ,EAAO04C,QAhCE,QAiCT14C,EAAO83D,QAAQ3+C,KAAK7F,UAGd6F,KE5BK,MAAM,WAAsB,GAI1C,wBACC,MAAO,gBAMR,OACC,MAAMnZ,EAASvc,KAAKuc,OAGpBA,EAAOysC,MAAMC,OAAOlyB,OAAQ,QAAS,CAAEigC,gBAzB1B,WA0Bbz6C,EAAOysC,MAAMC,OAAOs5C,uBA1BP,SA0BuC,CACnDrV,cAAc,EACdQ,aAAa,IAGdnxE,EAAO+3D,WAAW9U,mBAAoB,CACrCxW,MAhCY,SAiCZtzB,KAAM,IACNkqC,WAAY,CACX,KACA,CACCngD,OAAQ,CACP,aAAc,cAOlBlD,EAAO24C,SAAStmD,IA7CH,SA6CgB,IAAI,GAAkB2N,EA7CtC,WAgDbA,EAAOi4D,WAAW/qE,IAAK,SAhDV,WCSA,MAAM,WAAiB,GAIrC,OACC,MAAM8S,EAASvc,KAAKuc,OACd9d,EAAI8d,EAAO9d,EAGjB8d,EAAOL,GAAG+5D,iBAAiBrnE,IAhBd,SAgB2BqN,IACvC,MAAM+4C,EAAUz4C,EAAO24C,SAAS92D,IAjBpB,UAkBNs3B,EAAO,IAAI,GAAYzZ,GAkB7B,OAhBAyZ,EAAKjsB,IAAK,CACTinB,MAAOjyB,EAAG,UACV2nF,KCpCW,0bDqCXxxD,UAAW,SACX0xD,SAAS,EACTL,cAAc,IAGfvwD,EAAK32B,KAAM,OAAQ,aAAc6U,GAAIohD,EAAS,QAAS,aAGvDh1D,KAAKmR,SAAUukB,EAAM,UAAW,KAC/BnZ,EAAO04C,QAhCI,UAiCX14C,EAAO83D,QAAQ3+C,KAAK7F,UAGd6F,KEhCK,MAAM,WAA0B23D,GAY9C,UACCrtF,KAAKxB,MAAQwB,KAAKyiG,YAClBziG,KAAKsvC,UAAYtvC,KAAK0iG,gBAavB,QAASxgG,EAAU,IAClB,MAAM8mD,EAAQhpD,KAAKuc,OAAOysC,MACpBC,EAASD,EAAMC,OACf7+B,EAAY4+B,EAAMhoD,SAASopB,UAE3Bu4E,EAASx5F,MAAMiK,KAAMgX,EAAU4/B,qBAE/BxrD,OAAiC8H,IAAvBpE,EAAQogG,YAA8BtiG,KAAKxB,MAAQ0D,EAAQogG,WAE3Et5C,EAAM5L,OAAQprB,IACb,GAAMxzB,EAEC,CACN,MAAMokG,EAAgBD,EAAO3+F,OAAQykD,GAG7Bo6C,GAAWp6C,IAAWq6C,GAAkB75C,EAAQR,IAGxDzoD,KAAK+iG,YAAa/wE,EAAQ4wE,QAR1B5iG,KAAKgjG,aAAchxE,EAAQ2wE,EAAO3+F,OAAQ6+F,OAmB7C,YACC,MAEMI,EAAa,GAFDjjG,KAAKuc,OAAOysC,MAAMhoD,SAASopB,UAET4/B,qBAGpC,SAAWi5C,IAAcJ,GAAWI,IASrC,gBACC,GAAKjjG,KAAKxB,MACT,OAAO,EAGR,MAAM4rB,EAAYpqB,KAAKuc,OAAOysC,MAAMhoD,SAASopB,UACvC6+B,EAASjpD,KAAKuc,OAAOysC,MAAMC,OAE3Bg6C,EAAa,GAAO74E,EAAU4/B,qBAEpC,QAAMi5C,GAICH,GAAkB75C,EAAQg6C,GAclC,aAAcjxE,EAAQ2wE,GAErBO,GAAwBlxE,EAAQ2wE,GAAS7iE,UAAUr8B,QAAS0/F,IAC3D,GAAKA,EAAWtiF,MAAMqL,WAAai3E,EAAWriF,IAAI8K,QAGjD,YAFAoG,EAAOk8B,OAAQi1C,EAAWtiF,MAAM9D,QAMjC,GAAKomF,EAAWtiF,MAAMqL,UAAY,CACjC,MAAMk3E,EAAiBpxE,EAAOsqC,qBAAsB6mC,EAAWtiF,MAAM9D,QAIrE,YAFAiV,EAAOuG,KAAM4qE,EAAYC,GAOpBD,EAAWriF,IAAI8K,SACpBoG,EAAOziB,MAAO4zF,EAAWriF,KAK1B,MAAMuiF,EAAgBrxE,EAAO2qC,oBAAqBwmC,EAAWriF,IAAI/D,QAEjEiV,EAAOuG,KAAM4qE,EAAYE,KAW3B,YAAarxE,EAAQ2wE,GACpB,MAAMW,EAAgB,GAGtBJ,GAAwBlxE,EAAQ2wE,GAAS7iE,UAAUr8B,QAAS0/F,IAC3D,IAAI1iF,EAAQoiF,GAAWM,EAAWtiF,OAE5BJ,IACLA,EAAQuR,EAAO3uB,cAAe,cAE9B2uB,EAAOsK,KAAM6mE,EAAY1iF,IAG1B6iF,EAAcrgG,KAAMwd,KAOrB6iF,EAAcxjE,UAAUzoB,OAAQ,CAAEksF,EAAcC,IAC1CD,EAAar1E,aAAes1E,GAChCxxE,EAAOgxC,MAAOhxC,EAAO2qC,oBAAqB4mC,IAEnCA,GAGDC,IAKV,SAASX,GAAWY,GACnB,MAAwC,cAAjCA,EAAkB1mF,OAAOjf,KAAuB2lG,EAAkB1mF,OAAS,KAWnF,SAASmmF,GAAwBlxE,EAAQ2wE,GACxC,IAAIh4E,EACAptB,EAAI,EACR,MAAMswB,EAAS,GAEf,KAAQtwB,EAAIolG,EAAO5gG,QAAS,CAC3B,MAAM0mD,EAAQk6C,EAAQplG,GAChBmmG,EAAYf,EAAQplG,EAAI,GAExBotB,IACLA,EAAgBqH,EAAOsqC,qBAAsB7T,IAGxCi7C,GAAaj7C,EAAMv6B,aAAew1E,IACvC71E,EAAO5qB,KAAM+uB,EAAOsU,YAAa3b,EAAeqH,EAAO2qC,oBAAqBlU,KAC5E99B,EAAgB,MAGjBptB,IAGD,OAAOswB,EAIR,SAASi1E,GAAkB75C,EAAQR,GAElC,MAAMk7C,EAAc16C,EAAOiH,WAAYzH,EAAM1rC,OAAQ,cAC/C6mF,EAAqB36C,EAAOiH,WAAY,CAAE,QAAS,cAAgBzH,GAEzE,OAAOk7C,GAAeC,ECnNR,MAAM,WAA0B,GAI9C,wBACC,MAAO,oBAMR,OACC,MAAMrnF,EAASvc,KAAKuc,OACd0sC,EAAS1sC,EAAOysC,MAAMC,OAE5B1sC,EAAO24C,SAAStmD,IAAK,aAAc,IAAI,GAAmB2N,IAE1D0sC,EAAOipB,SAAU,aAAc,CAC9BvY,WAAY,SACZD,eAAgB,UAIjBzQ,EAAOkpB,cAAe,CAAEh8D,EAAKihD,KAC5B,GAAKjhD,EAAIojD,SAAU,eAAmC,cAAjBnC,EAASt5D,KAC7C,OAAO,IAITye,EAAO+3D,WAAWhV,iBAAkB,CAAEtW,MAAO,aAActzB,KAAM,eAGjEnZ,EAAOysC,MAAMhoD,SAASkvE,kBAAmBl+C,IACxC,MAAMszB,EAAU/oC,EAAOysC,MAAMhoD,SAASkkD,OAAOyC,aAE7C,IAAM,MAAMn+C,KAAS87C,EACpB,GAAmB,UAAd97C,EAAMvJ,KAAmB,CAC7B,MAAM2e,EAAUpV,EAAMqhB,SAASuC,UAE/B,IAAMxO,EAEL,SAGD,GAAKA,EAAQze,GAAI,UAAW,eAAkBye,EAAQ6D,QAIrD,OAFAuP,EAAO7tB,OAAQya,IAER,EACD,GAAKA,EAAQze,GAAI,UAAW,gBAAmB8oD,EAAOiH,WAAY1mD,EAAMqhB,SAAUjM,GAKxF,OAFAoT,EAAOk8B,OAAQtvC,IAER,EACD,GAAKA,EAAQze,GAAI,WAAc,CAErC,MAAM8uB,EAAQ+C,EAAO0iC,cAAe91C,GAEpC,IAAM,MAAM6H,KAASwI,EAAMq4B,WAC1B,GACC7gC,EAAMtmB,GAAI,UAAW,gBACpB8oD,EAAOiH,WAAYl+B,EAAOsqC,qBAAsB71C,GAASA,GAI1D,OAFAuL,EAAOk8B,OAAQznC,IAER,QAIJ,GAAmB,UAAdjd,EAAMvJ,KAAmB,CACpC,MAAM8c,EAASvT,EAAMqhB,SAAS9N,OAE9B,GAAKA,EAAO5c,GAAI,UAAW,eAAkB4c,EAAO0F,QAInD,OAFAuP,EAAO7tB,OAAQ4Y,IAER,EAKV,OAAO,IAOT,YACC,MACMi4C,EADSh1D,KAAKuc,OACG24C,SAAS92D,IAAK,cAOrC4B,KAAKmR,SAAUnR,KAAKuc,OAAO83D,QAAQ3+C,KAAK10B,SAAU,QAAS,CAAE8V,EAAKnX,KACjE,MAAMynC,EAAMpnC,KAAKuc,OAAOysC,MAAMhoD,SACxBy3B,EAAiB2O,EAAIhd,UAAUqH,kBAAkB1U,OAElDqqB,EAAIhd,UAAUqD,aAAegL,EAAehW,SAAWuyC,EAAQx2D,QACnEwB,KAAKuc,OAAO04C,QAAS,cACrBj1D,KAAKuc,OAAO83D,QAAQ3+C,KAAKm3D,uBAEzBltF,EAAKi0C,iBACL98B,EAAIhH,W,MCzGO,MAAM,WAAqB,GAIzC,OACC,MAAMyM,EAASvc,KAAKuc,OACd9d,EAAI8d,EAAO9d,EAEjB8d,EAAOL,GAAG+5D,iBAAiBrnE,IAAK,aAAcqN,IAC7C,MAAM+4C,EAAUz4C,EAAO24C,SAAS92D,IAAK,cAC/BgmF,EAAa,IAAI,GAAYnoE,GAkBnC,OAhBAmoE,EAAW36E,IAAK,CACfinB,MAAOjyB,EAAG,eACV2nF,KCpCW,mZDqCXE,SAAS,EACTL,cAAc,IAIf7B,EAAWrlF,KAAM,OAAQ,aAAc6U,GAAIohD,EAAS,QAAS,aAG7Dh1D,KAAKmR,SAAUizE,EAAY,UAAW,KACrC7nE,EAAO04C,QAAS,cAChB14C,EAAO83D,QAAQ3+C,KAAK7F,UAGdu0D,KE/BK,MAAM,WAAmB,GAIvC,wBACC,MAAO,aAMR,OACC,MAAM7nE,EAASvc,KAAKuc,OACd05D,EAAmB15D,EAAOL,GAAG+5D,iBAC7Bx3E,EAAI8d,EAAO9d,EAEjBw3E,EAAiBrnE,IAAK,WAAYqN,IACjC,MAAM+4C,EAAUz4C,EAAO24C,SAAS92D,IAAK,YAE/BylG,EAAS,IAAI,GAAY5nF,GAe/B,OAbA4nF,EAAOp6F,IAAK,CACXinB,MAAOjyB,EAAG,wBACV2nF,KC1CW,6cD2CXE,SAAS,IAGVud,EAAO9kG,KAAM,aAAc6U,GAAIohD,GAE/B6uC,EAAO36E,GAAI,UAAW,KACrB3M,EAAO04C,QAAS,YAChB14C,EAAO83D,QAAQ3+C,KAAK7F,UAGdg0E,KEhCK,MAAM,WAA0Bx0D,GAI9C,QAAS3J,GACR1lC,KAAKmR,SAAUu0B,EAAS,OAAQ,CAAEz0B,EAAOyiC,KACxC,MAAMne,EAAame,EAAStyC,OAEvBpB,KAAK+zC,iCAAkCxe,IAIjB,OAAtBA,EAAWsR,SACf7mC,KAAK8jG,YAAapwD,IAGjB,CAAE9E,YAAY,IAWlB,YAAa8E,GACP1zC,KAAKsvC,YACTtvC,KAAKgB,SAASqT,KAAM,iBACpBrU,KAAKgB,SAASqT,KAAM,cAAeq/B,KC5BvB,MAAMqwD,GAIpB,cACC/jG,KAAKg6F,OAAS,GAUf,IAAK/qC,EAAYj9B,GAChB,MAAM1xB,EAAQN,KAAKg6F,OAGbgK,EAAS1jG,EAAO,GACtBN,KAAKikG,kBAAmBh1C,GACxB,MAAMi1C,EAAS5jG,EAAO,GAGjB0jG,IAAWE,GAAWC,GAAoBH,EAAQE,IACtDlkG,KAAKqU,KAAM,aAAc,CACxB+vF,cAAeJ,EACfK,cAAeH,EACflyE,WAYH,OAAQ1vB,EAAI0vB,GACX,MAAM1xB,EAAQN,KAAKg6F,OAEbgK,EAAS1jG,EAAO,GACtBN,KAAKskG,kBAAmBhiG,GACxB,MAAM4hG,EAAS5jG,EAAO,GAGjB0jG,IAAWE,GAAWC,GAAoBH,EAAQE,IACtDlkG,KAAKqU,KAAM,aAAc,CACxB+vF,cAAeJ,EACfK,cAAeH,EACflyE,WAYH,kBAAmBi9B,GAClB,MAAM3uD,EAAQN,KAAKg6F,OACbt3F,EAAQpC,EAAMi7F,UAAWl5F,GAAQA,EAAKC,KAAO2sD,EAAW3sD,IAG9D,GAAK6hG,GAAoBl1C,EAAY3uD,EAAOoC,IAC3C,OAIIA,GAAS,GACbpC,EAAMwF,OAAQpD,EAAO,GAKtB,IAAInF,EAAI,EAER,KAAQ+C,EAAO/C,IAAOgnG,GAAkBjkG,EAAO/C,GAAK0xD,IACnD1xD,IAGD+C,EAAMwF,OAAQvI,EAAG,EAAG0xD,GASrB,kBAAmB3sD,GAClB,MAAMhC,EAAQN,KAAKg6F,OACbt3F,EAAQpC,EAAMi7F,UAAWl5F,GAAQA,EAAKC,KAAOA,GAG9CI,GAAS,GACbpC,EAAMwF,OAAQpD,EAAO,IAYxB,SAASyhG,GAAoBxnF,EAAGC,GAC/B,OAAOD,GAAKC,GAAKD,EAAElM,UAAYmM,EAAEnM,UAAY+zF,GAAiB7nF,EAAEgC,UAAa6lF,GAAiB5nF,EAAE+B,SAQjG,SAAS4lF,GAAkB5nF,EAAGC,GAC7B,OAAKD,EAAElM,SAAWmM,EAAEnM,YAERkM,EAAElM,SAAWmM,EAAEnM,WAKpB+zF,GAAiB7nF,EAAEgC,SAAY6lF,GAAiB5nF,EAAE+B,SAQ1D,SAAS6lF,GAAiB7lF,GACzB,OAAOxV,MAAMgC,QAASwT,GAAYA,EAAQuF,OAAOjgB,KAAM,KAAQ0a,EAjChEnK,GAAKuvF,GAAgB,I,MC/GrB,MAAM,GAAO9kB,GAAQ,MACfwlB,GAAwB19F,GAAO/F,SAASq5C,KAyC/B,MAAM,WAAyB,GAI7C,YAAap+B,GACZrc,MAAOqc,GAEP,MAAMld,EAAOiB,KAAKq+E,aASlBr+E,KAAKyJ,IAAK,MAAO,GASjBzJ,KAAKyJ,IAAK,OAAQ,GAiBlBzJ,KAAKyJ,IAAK,WAAY,YAStBzJ,KAAKyJ,IAAK,aAAa,GAUvBzJ,KAAKyJ,IAAK,aAAa,GAQvBzJ,KAAKyJ,IAAK,SAgBVzJ,KAAKkH,QAAUlH,KAAKw9E,mBAEpBx9E,KAAKs+E,YAAa,CACjBl2E,IAAK,MACL9E,WAAY,CACXy6E,MAAO,CACN,KACA,mBACAh/E,EAAK6U,GAAI,WAAYpV,GAAS,oBAAqBA,GACnDO,EAAKi7E,GAAI,YAAa,4BACtBj7E,EAAKi7E,GAAI,YAAa,+BACtBj7E,EAAK6U,GAAI,UAGVxQ,MAAO,CACN0iC,IAAK/mC,EAAK6U,GAAI,MAAO,IACrBmyB,KAAMhnC,EAAK6U,GAAI,OAAQ,MAIzB9L,SAAU9H,KAAKkH,UASjB,OACClH,KAAK0kG,WAAY,EAQlB,OACC1kG,KAAK0kG,WAAY,EAkClB,SAAUxiG,GACTlC,KAAK2kG,OAEL,MAAMC,EAAmB,GAAiBA,iBACpCC,EAAkB5mG,OAAO4nC,OAAQ,GAAI,CAC1CjnB,QAAS5e,KAAK4e,QACdsjE,UAAW,CACV0iB,EAAiBE,gBACjBF,EAAiBG,0BACjBH,EAAiBI,0BACjBJ,EAAiBK,oBACjBL,EAAiBM,oBACjBN,EAAiBO,gBACjBP,EAAiBQ,0BACjBR,EAAiBS,0BACjBT,EAAiBU,oBACjBV,EAAiBW,qBAElBpjB,QAASsiB,GACTriB,eAAe,GACblgF,GAEGsjG,EAAkB,GAAiBhhB,oBAAqBqgB,GAIxD9+D,EAAOyO,SAAUgxD,EAAgBz/D,MACjCD,EAAM0O,SAAUgxD,EAAgB1/D,KAChCjb,EAAW26E,EAAgB1nG,KAEjCG,OAAO4nC,OAAQ7lC,KAAM,CAAE8lC,MAAKC,OAAMlb,aAoCnC,IAAK3oB,GACJlC,KAAKylG,QAELzlG,KAAK0lG,0BAA4B,KAC3B1lG,KAAK0kG,UACT1kG,KAAK2lG,cAAezjG,GAEpBlC,KAAK4lG,gBAIP5lG,KAAK2lG,cAAezjG,GAKpBlC,KAAKmR,SAAUnR,KAAM,mBAAoBA,KAAK0lG,2BAM/C,QACM1lG,KAAK0lG,4BAET1lG,KAAK4lG,eAIL5lG,KAAKsR,cAAetR,KAAM,mBAAoBA,KAAK0lG,2BAEnD1lG,KAAK0lG,0BAA4B,KAEjC1lG,KAAK6lG,QAWP,cAAe3jG,GACdlC,KAAK8lG,SAAU5jG,GAEf,MAAMg/D,EAAgB6kC,GAAe7jG,EAAQd,QACvC82E,EAAiBh2E,EAAQigF,QAAU4jB,GAAe7jG,EAAQigF,SAAYsiB,GAG5EzkG,KAAKmR,SAAUpK,GAAO/F,SAAU,SAAU,CAAE8V,EAAKq4B,KAChD,MAAM62D,EAAe72D,EAAO/tC,OAGtB6kG,EAAuB/kC,GAAiB8kC,EAAa7+D,SAAU+5B,GAG/DglC,EAA8BhuB,GAAkB8tB,EAAa7+D,SAAU+wC,IAIxE+tB,IAAwBC,GAAgChlC,GAAkBgX,GAC9El4E,KAAK8lG,SAAU5jG,IAEd,CAAE0sC,YAAY,IAGjB5uC,KAAKmR,SAAUpK,GAAO5J,OAAQ,SAAU,KACvC6C,KAAK8lG,SAAU5jG,KASjB,eACClC,KAAKsR,cAAevK,GAAO/F,SAAU,UACrChB,KAAKsR,cAAevK,GAAO5J,OAAQ,WAUrC,SAAS4oG,GAAe9mG,GACvB,OAAK,GAAWA,GACRA,EAGHq4C,GAASr4C,GACNA,EAAOg6C,wBAGO,mBAAVh6C,EACJ8mG,GAAe9mG,KAGhB,KA8gBR,SAASknG,GAAanrD,EAAYorD,GACjC,OAAOprD,EAAWlV,IAAMsgE,EAAY1tD,OAAS,GAAiB2tD,oBAS/D,SAASC,GAAatrD,GACrB,OAAOA,EAAWpD,OAAS,GAAiByuD,oBAtgB7C,GAAiBE,sBAAwB,GAmBzC,GAAiBF,oBAAsB,GAQvC,GAAiB7hB,oBAAsBvC,GAyRvC,GAAiB2iB,iBAAmB,CAInC4B,wBAAyB,CAAExrD,EAAYorD,KAAiB,CACvDtgE,IAAKqgE,GAAanrD,EAAYorD,GAC9BrgE,KAAMiV,EAAWjV,KAAO,GAAiBwgE,sBACzCzoG,KAAM,aAGP2oG,8BAA+B,CAAEzrD,EAAYorD,KAAiB,CAC7DtgE,IAAKqgE,GAAanrD,EAAYorD,GAC9BrgE,KAAMiV,EAAWjV,KAA6B,IAApBqgE,EAAYpgE,MAAgB,GAAiBugE,sBACvEzoG,KAAM,cAGP4oG,oBAAqB,CAAE1rD,EAAYorD,KAAiB,CACnDtgE,IAAKqgE,GAAanrD,EAAYorD,GAC9BrgE,KAAMiV,EAAWjV,KAAOqgE,EAAYpgE,MAAQ,EAC5CloC,KAAM,YAGP6oG,8BAA+B,CAAE3rD,EAAYorD,KAAiB,CAC7DtgE,IAAKqgE,GAAanrD,EAAYorD,GAC9BrgE,KAAMiV,EAAWjV,KAA6B,IAApBqgE,EAAYpgE,MAAgB,GAAiBugE,sBACvEzoG,KAAM,cAGP8oG,wBAAyB,CAAE5rD,EAAYorD,KAAiB,CACvDtgE,IAAKqgE,GAAanrD,EAAYorD,GAC9BrgE,KAAMiV,EAAWjV,KAAOqgE,EAAYpgE,MAAQ,GAAiBugE,sBAC7DzoG,KAAM,aAKPwnG,oBAAqB,CAAEtqD,EAAYorD,KAAiB,CACnDtgE,IAAKqgE,GAAanrD,EAAYorD,GAC9BrgE,KAAMiV,EAAWjV,KAAOiV,EAAWhV,MAAQ,EAAI,GAAiBugE,sBAChEzoG,KAAM,aAGPsnG,0BAA2B,CAAEpqD,EAAYorD,KAAiB,CACzDtgE,IAAKqgE,GAAanrD,EAAYorD,GAC9BrgE,KAAMiV,EAAWjV,KAAOiV,EAAWhV,MAAQ,EAA0B,IAApBogE,EAAYpgE,MAAgB,GAAiBugE,sBAC9FzoG,KAAM,cAGPqnG,gBAAiB,CAAEnqD,EAAYorD,KAAiB,CAC/CtgE,IAAKqgE,GAAanrD,EAAYorD,GAC9BrgE,KAAMiV,EAAWjV,KAAOiV,EAAWhV,MAAQ,EAAIogE,EAAYpgE,MAAQ,EACnEloC,KAAM,YAGPunG,0BAA2B,CAAErqD,EAAYorD,KAAiB,CACzDtgE,IAAKqgE,GAAanrD,EAAYorD,GAC9BrgE,KAAMiV,EAAWjV,KAAOiV,EAAWhV,MAAQ,EAA0B,IAApBogE,EAAYpgE,MAAgB,GAAiBugE,sBAC9FzoG,KAAM,cAGPynG,oBAAqB,CAAEvqD,EAAYorD,KAAiB,CACnDtgE,IAAKqgE,GAAanrD,EAAYorD,GAC9BrgE,KAAMiV,EAAWjV,KAAOiV,EAAWhV,MAAQ,EAAIogE,EAAYpgE,MAAQ,GAAiBugE,sBACpFzoG,KAAM,aAKP+oG,wBAAyB,CAAE7rD,EAAYorD,KAAiB,CACvDtgE,IAAKqgE,GAAanrD,EAAYorD,GAC9BrgE,KAAMiV,EAAWtD,MAAQ,GAAiB6uD,sBAC1CzoG,KAAM,aAGPgpG,8BAA+B,CAAE9rD,EAAYorD,KAAiB,CAC7DtgE,IAAKqgE,GAAanrD,EAAYorD,GAC9BrgE,KAAMiV,EAAWtD,MAA8B,IAApB0uD,EAAYpgE,MAAgB,GAAiBugE,sBACxEzoG,KAAM,cAEPipG,oBAAqB,CAAE/rD,EAAYorD,KAAiB,CACnDtgE,IAAKqgE,GAAanrD,EAAYorD,GAC9BrgE,KAAMiV,EAAWtD,MAAQ0uD,EAAYpgE,MAAQ,EAC7CloC,KAAM,YAGPkpG,8BAA+B,CAAEhsD,EAAYorD,KAAiB,CAC7DtgE,IAAKqgE,GAAanrD,EAAYorD,GAC9BrgE,KAAMiV,EAAWtD,MAA8B,IAApB0uD,EAAYpgE,MAAgB,GAAiBugE,sBACxEzoG,KAAM,cAGPmpG,wBAAyB,CAAEjsD,EAAYorD,KAAiB,CACvDtgE,IAAKqgE,GAAanrD,EAAYorD,GAC9BrgE,KAAMiV,EAAWtD,MAAQ0uD,EAAYpgE,MAAQ,GAAiBugE,sBAC9DzoG,KAAM,aAIPopG,wBAAyB,CAAElsD,EAAYorD,KAAiB,CACvDtgE,IAAKwgE,GAAatrD,GAClBjV,KAAMiV,EAAWjV,KAAO,GAAiBwgE,sBACzCzoG,KAAM,aAGPqpG,8BAA+B,CAAEnsD,EAAYorD,KAAiB,CAC7DtgE,IAAKwgE,GAAatrD,GAClBjV,KAAMiV,EAAWjV,KAA6B,IAApBqgE,EAAYpgE,MAAgB,GAAiBugE,sBACvEzoG,KAAM,cAGPspG,oBAAqB,CAAEpsD,EAAYorD,KAAiB,CACnDtgE,IAAKwgE,GAAatrD,GAClBjV,KAAMiV,EAAWjV,KAAOqgE,EAAYpgE,MAAQ,EAC5CloC,KAAM,YAGPupG,8BAA+B,CAAErsD,EAAYorD,KAAiB,CAC7DtgE,IAAKwgE,GAAatrD,GAClBjV,KAAMiV,EAAWjV,KAA6B,IAApBqgE,EAAYpgE,MAAgB,GAAiBugE,sBACvEzoG,KAAM,cAGPwpG,wBAAyB,CAAEtsD,EAAYorD,KAAiB,CACvDtgE,IAAKwgE,GAAatrD,GAClBjV,KAAMiV,EAAWjV,KAAOqgE,EAAYpgE,MAAQ,GAAiBugE,sBAC7DzoG,KAAM,aAKPmnG,oBAAqB,CAAEjqD,EAAYorD,KAAiB,CACnDtgE,IAAKwgE,GAAatrD,GAClBjV,KAAMiV,EAAWjV,KAAOiV,EAAWhV,MAAQ,EAAI,GAAiBugE,sBAChEzoG,KAAM,aAEPinG,0BAA2B,CAAE/pD,EAAYorD,KAAiB,CACzDtgE,IAAKwgE,GAAatrD,GAClBjV,KAAMiV,EAAWjV,KAAOiV,EAAWhV,MAAQ,EAA0B,IAApBogE,EAAYpgE,MAAiB,GAAiBugE,sBAC/FzoG,KAAM,cAGPgnG,gBAAiB,CAAE9pD,EAAYorD,KAAiB,CAC/CtgE,IAAKwgE,GAAatrD,GAClBjV,KAAMiV,EAAWjV,KAAOiV,EAAWhV,MAAQ,EAAIogE,EAAYpgE,MAAQ,EACnEloC,KAAM,YAGPknG,0BAA2B,CAAEhqD,EAAYorD,KAAiB,CACzDtgE,IAAKwgE,GAAatrD,GAClBjV,KAAMiV,EAAWjV,KAAOiV,EAAWhV,MAAQ,EAA0B,IAApBogE,EAAYpgE,MAAiB,GAAiBugE,sBAC/FzoG,KAAM,cAGPonG,oBAAqB,CAAElqD,EAAYorD,KAAiB,CACnDtgE,IAAKwgE,GAAatrD,GAClBjV,KAAMiV,EAAWjV,KAAOiV,EAAWhV,MAAQ,EAAIogE,EAAYpgE,MAAQ,GAAiBugE,sBACpFzoG,KAAM,aAKPypG,wBAAyB,CAAEvsD,EAAYorD,KAAiB,CACvDtgE,IAAKwgE,GAAatrD,GAClBjV,KAAMiV,EAAWtD,MAAQ,GAAiB6uD,sBAC1CzoG,KAAM,aAGP0pG,8BAA+B,CAAExsD,EAAYorD,KAAiB,CAC7DtgE,IAAKwgE,GAAatrD,GAClBjV,KAAMiV,EAAWtD,MAA8B,IAApB0uD,EAAYpgE,MAAgB,GAAiBugE,sBACxEzoG,KAAM,cAGP2pG,oBAAqB,CAAEzsD,EAAYorD,KAAiB,CACnDtgE,IAAKwgE,GAAatrD,GAClBjV,KAAMiV,EAAWtD,MAAQ0uD,EAAYpgE,MAAQ,EAC7CloC,KAAM,YAGP4pG,8BAA+B,CAAE1sD,EAAYorD,KAAiB,CAC7DtgE,IAAKwgE,GAAatrD,GAClBjV,KAAMiV,EAAWtD,MAA8B,IAApB0uD,EAAYpgE,MAAgB,GAAiBugE,sBACxEzoG,KAAM,cAGP6pG,wBAAyB,CAAE3sD,EAAYorD,KAAiB,CACvDtgE,IAAKwgE,GAAatrD,GAClBjV,KAAMiV,EAAWtD,MAAQ0uD,EAAYpgE,MAAQ,GAAiBugE,sBAC9DzoG,KAAM,cC72BD,SAAS8pG,GAAoB9sE,EAAakoB,EAAciG,GAC9D,OAAOnuB,GAAe+sE,GAAU/sE,KAAkBmuB,EAAO4D,SAAU7J,GA8C7D,SAAS8kD,GAAgC19E,GAC/C,OAAOA,EAAUhL,aA1D6B,sBCyBxC,SAASyoF,GAAUt1F,GACzB,QAAMA,EAAKpS,GAAI,cAINoS,EAAKiY,kBAAmB,UAiD3B,SAASu9E,GAAUnpF,EAASoT,EAAQ9vB,EAAU,IACpD,IAAM0c,EAAQze,GAAI,oBAQjB,MAAM,IAAI,KACT,sCACA,KACA,CAAEye,YAyBJ,OArBAoT,EAAOtuB,aAAc,kBAAmB,QAASkb,GAEjDoT,EAAO2K,SAvFyB,YAuFI/d,GACpCoT,EAAOg2E,kBAAmB,UAAU,EAAMppF,GAC1CA,EAAQiI,gBAAkB,GAErB3kB,EAAQwuB,OAqDP,SAAmB9R,EAASqpF,EAAgBj2E,GAClDA,EAAOg2E,kBAAmB,cAAeC,EAAgBrpF,GArDxDspF,CAAUtpF,EAAS1c,EAAQwuB,MAAOsB,GAG9B9vB,EAAQimG,oBA2Td,SAA6BC,EAAep2E,GAC3C,MAAMq2E,EAAkBr2E,EAAOm+B,gBAAiB,MAAO,CAAE4tB,MAAO,mCAAoC,SAAU1oD,GAC7G,MAAME,EAAav1B,KAAKs1B,aAAcD,GAGhC+wD,EAAO,IAAI,GAQjB,OAPAA,EAAK38E,IAAK,UCzbG,6aD4bb28E,EAAK5uD,SAELjC,EAAW3xB,YAAawiF,EAAKxnE,SAEtB2W,KAIRvD,EAAOruB,OAAQquB,EAAOo/B,iBAAkBg3C,EAAe,GAAKC,GAC5Dr2E,EAAO2K,SAAU,CAAE,mCAAqCyrE,GA5UvDE,CAAoB1pF,EAASoT,GAG9Bu2E,GACC3pF,EACAoT,EACA,CAAEpT,EAASqwC,EAAYj9B,IAAYA,EAAO2K,SAAUtiB,GAAS40C,EAAWtwC,SAAWC,GACnF,CAAEA,EAASqwC,EAAYj9B,IAAYA,EAAO6K,YAAaxiB,GAAS40C,EAAWtwC,SAAWC,IAGhFA,EAYD,SAAS2pF,GAAsB3pF,EAASoT,EAAQpjB,EAAKzK,GAC3D,MAAM7D,EAAQ,IAAIyjG,GAElBzjG,EAAM4oB,GAAI,aAAc,CAAEpS,EAAKnX,KACzBA,EAAKykG,eACTjgG,EAAQya,EAASjf,EAAKykG,cAAezkG,EAAKqyB,QAGtCryB,EAAK0kG,eACTz1F,EAAKgQ,EAASjf,EAAK0kG,cAAe1kG,EAAKqyB,UAIzCA,EAAOg2E,kBAAmB,eAAgB,CAAEppF,EAASqwC,EAAYj9B,IAAY1xB,EAAMsO,IAAKqgD,EAAYj9B,GAAUpT,GAC9GoT,EAAOg2E,kBAAmB,kBAAmB,CAAEppF,EAAStc,EAAI0vB,IAAY1xB,EAAM6D,OAAQ7B,EAAI0vB,GAAUpT,GAsB9F,SAAS4pF,GAAU5pF,GACzB,MAAM6pF,EAAe7pF,EAAQ4L,kBAAmB,eAEhD,OAAMi+E,EAIwB,mBAAhBA,EAA6BA,IAAiBA,EAHpD,GA6CF,SAASC,GAAkBl8E,EAAUwF,GAmB3C,OAlBAA,EAAO2K,SAAU,CAAE,sBAAuB,8BAAgCnQ,GAG1EwF,EAAOtuB,aAAc,kBAAmB8oB,EAAS2wB,WAAa,QAAU,OAAQ3wB,GAGhFA,EAAStD,GAAI,oBAAqB,CAAEpS,EAAK5X,EAAUiB,KAClD6xB,EAAOtuB,aAAc,kBAAmBvD,EAAK,QAAU,OAAQqsB,KAGhEA,EAAStD,GAAI,mBAAoB,CAAEpS,EAAK5X,EAAUiB,KAC5CA,EACJ6xB,EAAO2K,SAAU,qCAAsCnQ,GAEvDwF,EAAO6K,YAAa,qCAAsCrQ,KAIrDA,EAmBD,SAASm8E,GAA8Bv+E,EAAW4+B,GACxD,MAAM4/C,EAAkBx+E,EAAUsH,qBAElC,GAAKk3E,EAAkB,CACtB,MAAMC,EAA8Bf,GAAgC19E,GAIpE,GAAKy+E,EACJ,OAAO7/C,EAAMoI,iBAAkBw3C,EAAiBC,GAGjD,GAAK7/C,EAAMC,OAAOC,QAAS0/C,GAC1B,OAAO5/C,EAAM2T,oBAAqBisC,GAIpC,MAAM3F,EAAa74E,EAAU4/B,oBAAoBz+B,OAAO/sB,MAExD,GAAKykG,EAAa,CAGjB,GAAKA,EAAWxgF,QACf,OAAOumC,EAAMoI,iBAAkB6xC,EAAY,GAG5C,MAAMI,EAAgBr6C,EAAM2T,oBAAqBsmC,GAGjD,OAAK74E,EAAUyF,MAAMkxB,WAAYsiD,GACzBA,EAIDr6C,EAAMsT,qBAAsB2mC,GAGpC,OAAO74E,EAAUyF,MAgGX,SAASi5E,GAAuCC,EAAY3C,GAClE,MAAM9qD,EAAe,IAAI,GAAMv0C,GAAO5J,QAChC6rG,EAAiC1tD,EAAazC,gBAAiBkwD,GAE/DE,EAAqB7C,EAAY1tD,OAAS,GAAiB2tD,oBAGjE,GAAK0C,EAAWjjE,IAAMmjE,EAAqB3tD,EAAaxV,KAAOijE,EAAWnxD,OAASqxD,EAAqB3tD,EAAa1D,OACpH,OAAO,KAOR,MAAMoD,EAAaguD,GAAkCD,EAC/ChjE,EAAOiV,EAAWjV,KAAOiV,EAAWhV,MAAQ,EAAIogE,EAAYpgE,MAAQ,EAE1E,MAAO,CACNF,IAAK11B,KAAKsR,IAAKqnF,EAAWjjE,IAAK,GAAM,GAAiBugE,oBACtDtgE,OACAjoC,KAAM,WAOR,SAAS,KACR,OAAO,KE1XD,SAASorG,GAAwB9+E,GACvC,MAAM0Q,EAAc1Q,EAAUsH,qBAE9B,OAAKoJ,GAbC,SAAwBA,GAC9B,QAASA,EAAYtQ,kBAAmB,UAAaq9E,GAAU/sE,GAY3CquE,CAAeruE,GAC3BA,EAGD,KASD,SAAS,GAASkoB,GACxB,QAASA,GAAgBA,EAAa7iD,GAAI,UAAW,SAa/C,SAASipG,GAAapgD,EAAO1lD,EAAa,GAAIq9C,EAAiB,MACrEqI,EAAM5L,OAAQprB,IACb,MAAMq3E,EAAer3E,EAAO3uB,cAAe,QAASC,GAE9CgmG,EAAoB3oD,GAAkBgoD,GAA8B3/C,EAAMhoD,SAASopB,UAAW4+B,GAEpGA,EAAM6pB,cAAew2B,EAAcC,GAG9BD,EAAatsF,QACjBiV,EAAOyI,aAAc4uE,EAAc,QAW/B,SAASE,GAAgBvgD,GAC/B,MAAMC,EAASD,EAAMC,OACf7+B,EAAY4+B,EAAMhoD,SAASopB,UAEjC,OAiCD,SAAiCA,EAAW6+B,EAAQD,GACnD,MAAMjsC,EAoBP,SAA+BqN,EAAW4+B,GACzC,MAEMjsC,EAFW4rF,GAA8Bv+E,EAAW4+B,GAElCjsC,OAExB,GAAKA,EAAO0F,UAAY1F,EAAO5c,GAAI,UAAW,SAC7C,OAAO4c,EAAOA,OAGf,OAAOA,EA7BQysF,CAAsBp/E,EAAW4+B,GAEhD,OAAOC,EAAOiH,WAAYnzC,EAAQ,SApC3B0sF,CAAwBr/E,EAAW6+B,EAAQD,KA0CnD,SAAiC5+B,EAAW6+B,GAC3C,MAAM2/C,EAAkBx+E,EAAUsH,qBAElC,OAAOk3E,GAAmB3/C,EAAO6D,SAAU87C,GA5CzCc,CAAwBt/E,EAAW6+B,IAgDtC,SAAyB7+B,GACxB,MAAO,IAAKA,EAAUyF,MAAMrS,gBAAiB0M,MAAOmQ,IAAaA,EAASl6B,GAAI,UAAW,UAhDxFwpG,CAAgBv/E,GAcX,SAASw/E,GAAsBC,GACrC,MAAMC,EAAiB,GAEvB,IAAM,MAAMC,KAAeF,EAAWnjF,cACrCojF,EAAe7mG,KAAM8mG,GAEhBA,EAAY5pG,GAAI,YACpB2pG,EAAe7mG,QAAS8mG,EAAYrjF,eAItC,OAAOojF,EAAe1zF,KAAM+sB,GAAaA,EAAUhjC,GAAI,UAAW,QCvB5D,SAAS6pG,GAA+BpkD,GAC9C,OAAOZ,IACNA,EAAW97B,GAAI,aAAc08B,UAAuB2L,IAGrD,SAASA,EAAWz6C,EAAKnX,EAAMolD,GAC9B,IAAMA,EAAcqB,WAAWkH,QAAS3tD,EAAK0C,KAAMyU,EAAIhZ,MACtD,OAGD,MAAMkwD,EAAajJ,EAAc/yB,OAE3Bi4E,EAAML,GADG7kD,EAAcpB,OAAOR,cAAexjD,EAAK0C,OAGxD2rD,EAAWtqD,aAAc/D,EAAKimD,aAAcjmD,EAAKmmD,mBAAqB,GAAImkD,ICxF7D,MAAM,WAA2B5c,GAI/C,UACCrtF,KAAKsvC,UAAYi6D,GAAgBvpG,KAAKuc,OAAOysC,OAU9C,QAAS9mD,GACR,MAAM8mD,EAAQhpD,KAAKuc,OAAOysC,MAE1B,IAAM,MAAMkhD,KAAO7vF,GAASnY,EAAQ0I,QACnCw+F,GAAapgD,EAAO,CAAEkhD,SCrBV,MAAM,WAAqB,GAIzC,wBACC,MAAO,eAMR,OACC,MAAM3tF,EAASvc,KAAKuc,OACd0sC,EAAS1sC,EAAOysC,MAAMC,OACtBxqD,EAAI8d,EAAO9d,EACX61E,EAAa/3D,EAAO+3D,WAG1B/3D,EAAO83D,QAAQ3+C,KAAKknB,YAAa,IAGjCqM,EAAOipB,SAAU,QAAS,CACzBplB,UAAU,EACV5D,SAAS,EACTyQ,WAAY,SACZ3C,gBAAiB,CAAE,MAAO,MAAO,YAGlCsd,EAAWjV,IAAK,gBAAiBC,iBAAkB,CAClDtW,MAAO,QACPtzB,KAAM,CAAEstB,GAAgBhxB,YAAcm4E,GAAwBn4E,KAG/DsiD,EAAWjV,IAAK,mBAAoBC,iBAAkB,CACrDtW,MAAO,QACPtzB,KAAM,CAAEstB,GAAgBhxB,YH/CpB,SAAwB8I,EAAa9I,EAAQtB,GAGnD,OAFAsB,EAAOg2E,kBAAmB,SAAS,EAAMltE,GAElCitE,GAAUjtE,EAAa9I,EAAQ,CAAEtB,MAExC,WACC,MACM05E,EADaR,GAAsB9uE,GACd1b,aAAc,OAEzC,OAAOgrF,EAAU,GAAIA,KAAa15E,IAAWA,KGsCN25E,CAAeF,GAAwBn4E,GAAUA,EAAQvzB,EAAG,mBAGnG61E,EAAWjV,IAAK,YACdzwD,IAAKo7F,GAA+B,QACpCp7F,IAAKo7F,GAA+B,QACpCp7F,IFNG,WACN,OAAOo2C,IACNA,EAAW97B,GAAI,yBAA0BqoC,IAG1C,SAASA,EAAWz6C,EAAKnX,EAAMolD,GAC9B,IAAMA,EAAcqB,WAAWkH,QAAS3tD,EAAK0C,KAAMyU,EAAIhZ,MACtD,OAGD,MAAMk0B,EAAS+yB,EAAc/yB,OAEvBi4E,EAAML,GADG7kD,EAAcpB,OAAOR,cAAexjD,EAAK0C,OAGxD,GAAgC,OAA3B1C,EAAKmmD,kBAA6B,CACtC,MAAMwkD,EAAS3qG,EAAKkmD,kBAEfykD,EAAO3qG,OACXqyB,EAAOptB,gBAAiB,SAAUqlG,GAClCj4E,EAAOptB,gBAAiB,QAASqlG,GAE5BK,EAAOtkE,OACXhU,EAAOptB,gBAAiB,QAASqlG,QAG7B,CACN,MAAMK,EAAS3qG,EAAKmmD,kBAEfwkD,EAAO3qG,OACXqyB,EAAOtuB,aAAc,SAAU4mG,EAAO3qG,KAAMsqG,GAE5Cj4E,EAAOtuB,aAAc,QAAS,QAASumG,GAElCK,EAAOtkE,OACXhU,EAAOtuB,aAAc,QAAS4mG,EAAOtkE,MAAOikE,ME5BxCM,IAEPj2B,EAAWjV,IAAK,UACdC,iBAAkB,CAClB5pC,KAAM,CACL53B,KAAM,MACNwF,WAAY,CACX4mG,KAAK,IAGPlhD,MAAO,CAAEwhD,GAAax4E,YAAcA,EAAO3uB,cAAe,QAAS,CAAE6mG,IAAKM,EAAUprF,aAAc,WAElGsgD,qBAAsB,CACtBhqC,KAAM,CACL53B,KAAM,MACNgB,IAAK,OAENkqD,MAAO,QAEP0W,qBAAsB,CACtBhqC,KAAM,CACL53B,KAAM,MACNgB,IAAK,UAENkqD,MAAO,CACNlqD,IAAK,SACLN,MAAOgsG,IACN,MAAMhsG,EAAQ,CACbmB,KAAM6qG,EAAUprF,aAAc,WAO/B,OAJKorF,EAAUtrF,aAAc,WAC5B1gB,EAAMwnC,MAAQwkE,EAAUprF,aAAc,UAGhC5gB,MAIToQ,IFvFG,WACN,OAAOo2C,IACNA,EAAW97B,GAAI,iBAAkBqoC,IAGlC,SAASA,EAAWz6C,EAAKnX,EAAMolD,GAE9B,IAAMA,EAAcqB,WAAWj8C,KAAMxK,EAAKozD,SAAU,CAAEj1D,MAAM,EAAM6gB,QAAS,UAC1E,OAID,MAAM6rF,EAAYZ,GAAsBjqG,EAAKozD,UAG7C,IAAMy3C,IAAcA,EAAUtrF,aAAc,SAAY6lC,EAAcqB,WAAWj8C,KAAMqgG,EAAW,CAAE1sG,MAAM,IACzG,OAID,MAGM2sG,EAAa,GAHM1lD,EAAcoW,YAAaqvC,EAAW7qG,EAAKkzD,aAGzBpP,WAAW6D,YAGhDmjD,IAKN1lD,EAAc+N,gBAAiBnzD,EAAKozD,SAAU03C,GAE9C1lD,EAAcuO,uBAAwBm3C,EAAY9qG,KEsD3C+qG,IAEPnuF,EAAO24C,SAAStmD,IAAK,cAAe,IAAI,GAAoB2N,KAavD,SAAS4tF,GAAwBn4E,GACvC,MAAM24E,EAAe34E,EAAOw8D,mBAAoB,OAC1Coc,EAAS54E,EAAOy+B,uBAAwB,SAAU,CAAEstB,MAAO,UAIjE,OAFA/rD,EAAOruB,OAAQquB,EAAOo/B,iBAAkBw5C,EAAQ,GAAKD,GAE9CC,ECnHO,MAAM,WAAsB,GAC1C,YAAal1E,GACZ91B,MAAO81B,GAEP11B,KAAK8zC,aAAe,YAGrB,WAAYJ,GACX1zC,KAAKqU,KAAMq/B,EAASzzC,KAAMyzC,IC8Eb,MAAM,WAA6B,GAIjD,wBACC,MAAO,uBAMR,YAAan3B,GACZ3c,MAAO2c,GAQPvc,KAAKsD,WAAa,IAAI+U,IAStBrY,KAAK6qG,aAAe,KAMrB,OACC,MAAMtuF,EAASvc,KAAKuc,OACdysC,EAAQzsC,EAAOysC,MACftzB,EAAOnZ,EAAO83D,QAAQ3+C,KACtBzZ,EAASM,EAAON,OAEhBo4C,EAAiBrL,EAAMhoD,SAASopB,UAatCpqB,KAAKmR,SAAUukB,EAAK10B,SAAU,UAAW,CAAE8V,EAAKnX,KAE/C,IAAM00D,EAAe5mC,YACpB,OAKD,GAAK9tB,EAAK+0B,UAAY/0B,EAAK60B,QAAU70B,EAAK80B,QACzC,OAGD,MAAMq2E,EAAoBnrG,EAAK40B,SAAWlB,GAASG,WAC7Cu3E,EAAmBprG,EAAK40B,SAAWlB,GAASC,UAGlD,IAAMw3E,IAAsBC,EAC3B,OAGD,MAAMC,EAAmB/uF,EAAOT,yBAChC,IAAIyvF,GAAoB,EAGvBA,EAD2B,QAArBD,GAA8BF,GAA8C,QAArBE,GAA8BD,EACvE/qG,KAAKkrG,uBAAwBvrG,GAE7BK,KAAKmrG,wBAAyBxrG,IAKxB,IAAtBsrG,GACJn0F,EAAIhH,QAEH,CAAEW,SAAU,GAAWrS,IAAK,QAAW,IAU1C4B,KAAKorG,kCAAmC,EAGxCprG,KAAKmR,SAAUkjD,EAAgB,eAAgB,CAAEv9C,EAAKnX,KAIhDK,KAAKorG,iCACTprG,KAAKorG,kCAAmC,EAOnCprG,KAAKqrG,wBAOL1rG,EAAKuoD,cAAgBojD,GAA8Bj3C,EAAe7iC,mBAAoBxxB,KAAKsD,aAIjGtD,KAAKqkE,qBASP,kBAAmBllD,GAClBnf,KAAKsD,WAAWsL,IAAKuQ,GAWtB,uBAAwBxf,GACvB,MAAM2D,EAAatD,KAAKsD,WAElB8mB,EADQpqB,KAAKuc,OAAOysC,MACFhoD,SAASopB,UAC3BS,EAAWT,EAAUoH,mBAU3B,OAAKxxB,KAAKqrG,yBAWLxgF,EAASqB,YAAaq/E,GAAiBnhF,EAAW9mB,MAWlDgoG,GAA8BzgF,EAAUvnB,IAC5CkoG,GAAsB7rG,GACtBK,KAAKokE,oBACE,QAHR,IAeD,wBAAyBzkE,GACxB,MAAM2D,EAAatD,KAAKsD,WAClB0lD,EAAQhpD,KAAKuc,OAAOysC,MACpB5+B,EAAY4+B,EAAMhoD,SAASopB,UAC3BS,EAAWT,EAAUoH,mBAU3B,OAAKxxB,KAAKqrG,sBACTG,GAAsB7rG,GACtBK,KAAKqkE,kBACLonC,GAAyCziD,EAAO1lD,EAAYunB,IAErD,GAOFA,EAASqB,YACRq/E,GAAiBnhF,EAAW9mB,KAChCkoG,GAAsB7rG,GACtB8rG,GAAyCziD,EAAO1lD,EAAYunB,IAErD,GAgIZ,SAA0CA,EAAUvnB,GAEnD,OAAOgoG,GADgBzgF,EAASyD,cAAe,GACMhrB,GAnH9CooG,CAAiC7gF,EAAUvnB,GAO9CunB,EAASe,UACR2/E,GAAiBnhF,EAAW9mB,IAC7BgoG,GAA8BzgF,EAAUvnB,IAExCkoG,GAAsB7rG,GACtB8rG,GAAyCziD,EAAO1lD,EAAYunB,IAErD,IAKR7qB,KAAKorG,kCAAmC,EACxCprG,KAAKokE,oBAKE,QAzBR,EAqCF,2BACC,QAASpkE,KAAK6qG,aAWf,mBACC7qG,KAAK6qG,aAAe7qG,KAAKuc,OAAOysC,MAAM5L,OAAQprB,GACtCA,EAAO25E,4BAWhB,kBACC3rG,KAAKuc,OAAOysC,MAAM5L,OAAQprB,IACzBA,EAAO45E,wBAAyB5rG,KAAK6qG,cACrC7qG,KAAK6qG,aAAe,QASvB,SAASU,GAAiBnhF,EAAW9mB,GACpC,IAAM,MAAMuoG,KAAqBvoG,EAChC,GAAK8mB,EAAUlL,aAAc2sF,GAC5B,OAAO,EAIT,OAAO,EAUR,SAASJ,GAAyCziD,EAAO1lD,EAAYunB,GACpE,MAAMyC,EAAazC,EAASyC,WAC5B07B,EAAM5L,OAAQprB,IACR1E,EACJ0E,EAAO87D,sBAAuBxgE,EAAWyN,iBAEzC/I,EAAOysC,yBAA0Bn7D,KAQpC,SAASkoG,GAAsB7rG,GAC9BA,EAAKi0C,iBAgBN,SAAS03D,GAA8BzgF,EAAUvnB,GAChD,MAAM,WAAEgqB,EAAU,UAAEF,GAAcvC,EAClC,IAAM,MAAMghF,KAAqBvoG,EAAa,CAC7C,MAAMwoG,EAAax+E,EAAaA,EAAWlO,aAAcysF,QAAsBvlG,EAG/E,IAFkB8mB,EAAYA,EAAUhO,aAAcysF,QAAsBvlG,KAEzDwlG,EAClB,OAAO,EAGT,OAAO,ECzcO,SAASC,GAAoBlhF,EAAUilC,EAAetxD,EAAOwqD,GAC3E,OAAOA,EAAM1iB,YACZ0lE,GAAYnhF,EAAUilC,EAAetxD,GAAO,EAAMwqD,GAClDgjD,GAAYnhF,EAAUilC,EAAetxD,GAAO,EAAOwqD,IAYrD,SAASgjD,GAAYnhF,EAAUilC,EAAetxD,EAAOytG,EAAUjjD,GAG9D,IAAIz2C,EAAOsY,EAAS1M,WAAc8tF,EAAWphF,EAASyC,WAAazC,EAASuC,WAExE8+E,EAAW,KAEf,KAAQ35F,GAAQA,EAAK6M,aAAc0wC,IAAmBtxD,GACrD0tG,EAAW35F,EACXA,EAAO05F,EAAW15F,EAAK4b,gBAAkB5b,EAAK2b,YAG/C,OAAOg+E,EAAWljD,EAAMoI,iBAAkB86C,EAAUD,EAAW,SAAW,SAAYphF,EClCxE,MAAM,GACpB,cAQC7qB,KAAKmsG,aAAe,IAAI9zF,IAUzB,aACC,OAAOrY,KAAKmsG,aAAanjG,KAS1B,IAAK3G,GACC8G,MAAMgC,QAAS9I,GACnBA,EAAKoB,QAASpB,GAAQrC,KAAKmsG,aAAav9F,IAAKvM,IAE7CrC,KAAKmsG,aAAav9F,IAAKvM,GAUzB,gBACC,OAAO2iD,IACNA,EAAW97B,GAAI,qBAAsB,CAAEpS,EAAKnX,EAAMolD,KAKjD,IAAMA,EAAcqB,WAAWj8C,KAAMxK,EAAK0C,KAAM,sBAC/C,OAED,MAAM2rD,EAAajJ,EAAc/yB,OAC3BwI,EAAgBwzB,EAAWhtD,SAASopB,UAE1C,IAAM,MAAM/nB,KAAQrC,KAAKmsG,aAAe,CACvC,MAAMrxE,EAAckzB,EAAW7xB,uBAAwB,IAAK95B,EAAKiB,WAAY,CAC5EmN,SAAU,IAEXu9C,EAAWg6C,kBAAmB,QAAQ,EAAMltE,GACvCz4B,EAAK6O,SAAUvR,EAAKmmD,mBACnBnmD,EAAK0C,KAAKlC,GAAI,aAClB6tD,EAAW1xB,KAAM9B,EAAcjL,gBAAiBuL,GAEhDkzB,EAAW1xB,KAAMyoB,EAAcpB,OAAOsK,YAAatuD,EAAKsvB,OAAS6L,GAGlEkzB,EAAWE,OAAQnJ,EAAcpB,OAAOsK,YAAatuD,EAAKsvB,OAAS6L,KAGnE,CAAErqB,SAAU,UAWjB,8BACC,OAAOu0C,IACNA,EAAW97B,GAAI,2BAA4B,CAAEpS,EAAKnX,EAAMolD,KACvD,MAAMqnD,EAAarnD,EAAcpB,OAAOR,cAAexjD,EAAK0C,MACtDgqG,EAAcljG,MAAMiK,KAAMg5F,EAAW1lF,eAAgBtQ,KAAMqQ,GAAwB,MAAfA,EAAM3oB,MAEhF,IAAM,MAAMuE,KAAQrC,KAAKmsG,aAAe,CACvC,MAAM7oG,EAAagb,GAAOjc,EAAKiB,YAE/B,GAAKjB,EAAK6O,SAAUvR,EAAKmmD,mBACxB,IAAM,MAAQhnD,EAAKoR,KAAS5M,EACd,UAARxE,EACJimD,EAAc/yB,OAAO2K,SAAUzsB,EAAKm8F,GAEpCtnD,EAAc/yB,OAAOtuB,aAAc5E,EAAKoR,EAAKm8F,QAI/C,IAAM,MAAQvtG,EAAKoR,KAAS5M,EACd,UAARxE,EACJimD,EAAc/yB,OAAO6K,YAAa3sB,EAAKm8F,GAEvCtnD,EAAc/yB,OAAOptB,gBAAiB9F,EAAKutG,QCtGpC,OANf,SAAmBnjG,EAAO2X,EAAOC,GAC/B,IAAI/e,EAASmH,EAAMnH,OAEnB,OADA+e,OAAcxa,IAARwa,EAAoB/e,EAAS+e,GAC1BD,GAASC,GAAO/e,EAAUmH,EAAQ,GAAUA,EAAO2X,EAAOC,ICFjEwrF,GAAeriG,OAAO,uFAaX,OAJf,SAAoB2Q,GAClB,OAAO0xF,GAAaniG,KAAKyQ,ICXZ,OAJf,SAAsBA,GACpB,OAAOA,EAAOrL,MAAM,KCClBg9F,GAAW,oBACXC,GAAU,kDACVC,GAAS,2BAETC,GAAc,qBACdC,GAAa,kCACbC,GAAa,qCAIbC,GAPa,MAAQL,GAAU,IAAMC,GAAS,IAOtB,IAGxBK,GAFW,oBAEQD,IADP,gBAAwB,CAACH,GAAaC,GAAYC,IAAY3oG,KAAK,KAAnE,qBAA2F4oG,GAAW,MAElHE,GAAW,MAAQ,CAACL,GAAcF,GAAU,IAAKA,GAASG,GAAYC,GAAYL,IAAUtoG,KAAK,KAAO,IAGxG+oG,GAAY/iG,OAAOwiG,GAAS,MAAQA,GAAS,KAAOM,GAAWD,GAAO,KAa3D,OAJf,SAAwBlyF,GACtB,OAAOA,EAAOc,MAAMsxF,KAAc,ICnBrB,OANf,SAAuBpyF,GACrB,OAAO,GAAWA,GACd,GAAeA,GACf,GAAaA,ICkBJ,ICXA,GDTf,SAAyBoO,GACvB,OAAO,SAASpO,GACdA,EAAS,GAASA,GAElB,IAAIqyF,EAAa,GAAWryF,GACxB,GAAcA,QACdtU,EAEA4mG,EAAMD,EACNA,EAAW,GACXryF,EAAOuI,OAAO,GAEdiyB,EAAW63D,EACX,GAAUA,EAAY,GAAGhpG,KAAK,IAC9B2W,EAAOnT,MAAM,GAEjB,OAAOylG,EAAIlkF,KAAgBosB,GCTd,CAAgB,eCRjC,MAAM+3D,GAAwB,8DACxBC,GAAW,kEAGXC,GAAgB,oFAIhBC,GAAmB,2BAwBlB,SAASC,GAAmBC,GAAM,OAAEx7E,IAE1C,MAAMy7E,EAAcz7E,EAAOmK,uBAAwB,IAAK,CAAEqxE,QAAQ,CAAE/8F,SAAU,IAG9E,OAFAuhB,EAAOg2E,kBAAmB,QAAQ,EAAMyF,GAEjCA,EAcD,SAASC,GAAe7N,GAG9B,OAMD,SAAoBA,GAGnB,OAFsBA,EAAI31F,QAASijG,GAAuB,IAErCzxF,MAAO0xF,IATrBO,CAFP9N,EAAM/zF,OAAQ+zF,IAEYA,EAAM,IAwE1B,SAAS,GAAgBjhF,EAASqqC,GACxC,QAAMrqC,IAICA,EAAQze,GAAI,UAAW,UAAa8oD,EAAO4K,eAAgB,QAAS,aAyBrE,SAAS+5C,GAA6BC,EAAMC,GAClD,MAAMC,GAjBkBvvG,EAiBEqvG,EAhBnBR,GAAcljG,KAAM3L,GAgBQ,UAAYsvG,GAjBzC,IAAkBtvG,EAkBxB,MAAMwvG,IAAqBD,IAAaT,GAAiBnjG,KAAM0jG,GAE/D,OAAOA,GAAQG,EAAmBD,EAAWF,EAAOA,ECrJtC,MAAM,WAAoBxgB,GASxC,YAAa9wE,GACZ3c,MAAO2c,GAWPvc,KAAKiuG,iBAAmB,IAAI,GAS5BjuG,KAAKkuG,oBAAsB,IAAI,GAMhC,+BACC,IAAM,MAAMC,KAAmBnuG,KAAKiuG,iBACnCE,EAAgB3vG,MAAQwB,KAAKouG,4BAA6BD,EAAgB7rG,IAO5E,UACC,MAAM0mD,EAAQhpD,KAAKuc,OAAOysC,MACpB5hB,EAAM4hB,EAAMhoD,SAEZ4nG,EAAkB,GAAOxhE,EAAIhd,UAAU4/B,qBAIxC,GAAgB4+C,EAAiB5/C,EAAMC,SAC3CjpD,KAAKxB,MAAQoqG,EAAgBxpF,aAAc,YAC3Cpf,KAAKsvC,UAAY0Z,EAAMC,OAAO4K,eAAgB+0C,EAAiB,cAE/D5oG,KAAKxB,MAAQ4oC,EAAIhd,UAAUhL,aAAc,YACzCpf,KAAKsvC,UAAY0Z,EAAMC,OAAOo5C,0BAA2Bj7D,EAAIhd,UAAW,aAGzE,IAAM,MAAM+jF,KAAmBnuG,KAAKiuG,iBACnCE,EAAgB3vG,MAAQwB,KAAKouG,4BAA6BD,EAAgB7rG,IAkE5E,QAASkrG,EAAMa,EAAqB,IACnC,MAAMrlD,EAAQhpD,KAAKuc,OAAOysC,MACpB5+B,EAAY4+B,EAAMhoD,SAASopB,UAE3BkkF,EAAyB,GACzBC,EAAwB,GAE9B,IAAM,MAAMzwG,KAAQuwG,EACdA,EAAoBvwG,GACxBwwG,EAAuBrrG,KAAMnF,GAE7BywG,EAAsBtrG,KAAMnF,GAI9BkrD,EAAM5L,OAAQprB,IAEb,GAAK5H,EAAUqD,YAAc,CAC5B,MAAM5C,EAAWT,EAAUoH,mBAG3B,GAAKpH,EAAUlL,aAAc,YAAe,CAE3C,MAAMsvF,EAAYzC,GAAoBlhF,EAAU,WAAYT,EAAUhL,aAAc,YAAc4pC,GAElGh3B,EAAOtuB,aAAc,WAAY8pG,EAAMgB,GAEvCF,EAAuB7qG,QAASpB,IAC/B2vB,EAAOtuB,aAAcrB,GAAM,EAAMmsG,KAGlCD,EAAsB9qG,QAASpB,IAC9B2vB,EAAOptB,gBAAiBvC,EAAMmsG,KAI/Bx8E,EAAOyI,aAAczI,EAAO2qC,oBAAqB6xC,EAAU1tF,IAAIwM,kBAK3D,GAAc,KAATkgF,EAAc,CACvB,MAAMlqG,EAAagb,GAAO8L,EAAU2Q,iBAEpCz3B,EAAWmG,IAAK,WAAY+jG,GAE5Bc,EAAuB7qG,QAASpB,IAC/BiB,EAAWmG,IAAKpH,GAAM,KAGvB,MAAQye,IAAKuiF,GAAkBr6C,EAAM6pB,cAAe7gD,EAAOwiC,WAAYg5C,EAAMlqG,GAAcunB,GAI3FmH,EAAOyI,aAAc4oE,GAKtB,CAAE,cAAeiL,KAA2BC,GAAwB9qG,QAASpB,IAC5E2vB,EAAOysC,yBAA0Bp8D,SAE5B,CAGN,MAAMwrB,EAASm7B,EAAMC,OAAOk5C,eAAgB/3E,EAAU8F,YAAa,YAG7Du+E,EAAgB,GAEtB,IAAM,MAAM7vF,KAAWwL,EAAU4/B,oBAC3BhB,EAAMC,OAAO4K,eAAgBj1C,EAAS,aAC1C6vF,EAAcxrG,KAAM+uB,EAAO+0B,cAAenoC,IAK5C,MAAM8vF,EAAiBD,EAAchnG,QAIrC,IAAM,MAAMwnB,KAASpB,EACf7tB,KAAK2uG,iBAAkB1/E,EAAOw/E,IAClCC,EAAezrG,KAAMgsB,GAIvB,IAAM,MAAMA,KAASy/E,EACpB18E,EAAOtuB,aAAc,WAAY8pG,EAAMv+E,GAEvCq/E,EAAuB7qG,QAASpB,IAC/B2vB,EAAOtuB,aAAcrB,GAAM,EAAM4sB,KAGlCs/E,EAAsB9qG,QAASpB,IAC9B2vB,EAAOptB,gBAAiBvC,EAAM4sB,QAcnC,4BAA6B2/E,GAC5B,MAAM5lD,EAAQhpD,KAAKuc,OAAOysC,MACpB5hB,EAAM4hB,EAAMhoD,SAEZ4nG,EAAkB,GAAOxhE,EAAIhd,UAAU4/B,qBAI7C,OAAK,GAAgB4+C,EAAiB5/C,EAAMC,QACpC2/C,EAAgBxpF,aAAcwvF,GAG/BxnE,EAAIhd,UAAUhL,aAAcwvF,GAWpC,iBAAkB3/E,EAAOw/E,GACxB,IAAM,MAAMI,KAAgBJ,EAE3B,GAAKI,EAAaxtD,cAAepyB,GAChC,OAAO,EAIT,OAAO,GC/QM,MAAM,WAAsBo+D,GAI1C,UACC,MAAMrkC,EAAQhpD,KAAKuc,OAAOysC,MACpB5hB,EAAM4hB,EAAMhoD,SAEZ4nG,EAAkB,GAAOxhE,EAAIhd,UAAU4/B,qBAIxC,GAAgB4+C,EAAiB5/C,EAAMC,QAC3CjpD,KAAKsvC,UAAY0Z,EAAMC,OAAO4K,eAAgB+0C,EAAiB,YAE/D5oG,KAAKsvC,UAAY0Z,EAAMC,OAAOo5C,0BAA2Bj7D,EAAIhd,UAAW,YAiB1E,UACC,MAAM7N,EAASvc,KAAKuc,OACdysC,EAAQhpD,KAAKuc,OAAOysC,MACpB5+B,EAAY4+B,EAAMhoD,SAASopB,UAC3B0kF,EAAcvyF,EAAO24C,SAAS92D,IAAK,QAEzC4qD,EAAM5L,OAAQprB,IAEb,MAAM+8E,EAAiB3kF,EAAUqD,YAChC,CAAEs+E,GACD3hF,EAAUoH,mBACV,WACApH,EAAUhL,aAAc,YACxB4pC,IAEDA,EAAMC,OAAOk5C,eAAgB/3E,EAAU8F,YAAa,YAGrD,IAAM,MAAMjB,KAAS8/E,EAGpB,GAFA/8E,EAAOptB,gBAAiB,WAAYqqB,GAE/B6/E,EACJ,IAAM,MAAMX,KAAmBW,EAAYb,iBAC1Cj8E,EAAOptB,gBAAiBupG,EAAgB7rG,GAAI2sB,MCvDnC,MAAM+/E,GAYpB,aAAa,GAAE1sG,EAAE,MAAEouB,EAAK,WAAEptB,EAAU,aAAEyd,IAMrC/gB,KAAKsC,GAAKA,EAQVtC,KAAKyJ,IAAK,SAOVzJ,KAAK+gB,aAAeA,EAOpB/gB,KAAK0wB,MAAQA,EAQb1wB,KAAKsD,WAAaA,GAIpBkR,GAAKw6F,GAAiB,I,MC/CtB,MAGMC,GAAwB,kBAUf,MAAM,WAAoB,GAIxC,wBACC,MAAO,cAMR,sBAEC,MAAO,CAAE,GAAsB,GAAO,IAMvC,YAAa1yF,GACZ3c,MAAO2c,GAEPA,EAAOV,OAAO5e,OAAQ,OAAQ,CAC7BiyG,0BAA0B,IAO5B,OACC,MAAM3yF,EAASvc,KAAKuc,OAGpBA,EAAOysC,MAAMC,OAAOlyB,OAAQ,QAAS,CAAEigC,gBAAiB,aAExDz6C,EAAO+3D,WAAWjV,IAAK,gBACrBG,mBAAoB,CAAExW,MAAO,WAAYtzB,KAAM63E,KAEjDhxF,EAAO+3D,WAAWjV,IAAK,mBACrBG,mBAAoB,CAAExW,MAAO,WAAYtzB,KAAM,CAAE83E,EAAMzoD,IAChDwoD,GAAmBG,GAAeF,GAAQzoD,KAGnDxoC,EAAO+3D,WAAWjV,IAAK,UACrBI,mBAAoB,CACpB/pC,KAAM,CACL53B,KAAM,IACNwF,WAAY,CACXkqG,MAAM,IAGRxkD,MAAO,CACNlqD,IAAK,WACLN,MAAOs8B,GAAeA,EAAY1b,aAAc,WAKnD7C,EAAO24C,SAAStmD,IAAK,OAAQ,IAAI,GAAa2N,IAC9CA,EAAO24C,SAAStmD,IAAK,SAAU,IAAI,GAAe2N,IAElD,MAAM4yF,EJTD,SAAiC1wG,EAAG2wG,GAC1C,MAAMC,EAA4B,CACjC,oBAAqB5wG,EAAG,qBACxB,aAAgBA,EAAG,iBAUpB,OAPA2wG,EAAW3rG,QAAS6rG,IACdA,EAAU5+E,OAAS2+E,EAA2BC,EAAU5+E,SAC5D4+E,EAAU5+E,MAAQ2+E,EAA2BC,EAAU5+E,QAEjD4+E,IAGDF,EIJiBG,CAAwBhzF,EAAO9d,EJcjD,SAA8B2wG,GACpC,MAAMI,EAAW,GAEjB,GAAKJ,EACJ,IAAM,MAAQtwG,EAAKN,KAAWP,OAAOqL,QAAS8lG,GAAe,CAC5D,MAAME,EAAYrxG,OAAO4nC,OACxB,GACArnC,EACA,CAAE8D,GAAI,OAAQ,GAAYxD,KAE3B0wG,EAASvsG,KAAMqsG,GAIjB,OAAOE,EI5BmDC,CAAqBlzF,EAAOV,OAAOzd,IAAK,qBAEjG4B,KAAK0vG,2BAA4BP,EAAenrG,OAAQ3B,GA5E9B,cA4EsCA,EAAK3D,OACrEsB,KAAK2vG,wBAAyBR,EAAenrG,OAAQ3B,GA5E9B,WA4EsCA,EAAK3D,OAG/B6d,EAAOtE,QAAQ7Z,IAAK,IAC5BwxG,kBAAmB,YCtEjC,SAA0BrzF,EAAQuzC,EAAejpB,EAASzgB,GACxE,MAAMsP,EAAOnZ,EAAO83D,QAAQ3+C,KACtBm6E,EAAsB,IAAIx3F,IAGhCqd,EAAK10B,SAASkvE,kBAAmBl+C,IAChC,MAAM5H,EAAY7N,EAAOysC,MAAMhoD,SAASopB,UACxC,IAAI0hC,GAAU,EAEd,GAAK1hC,EAAUlL,aAAc4wC,GAAkB,CAC9C,MAAMrM,EAAasoD,GAClB3hF,EAAUoH,mBACVs+B,EACA1lC,EAAUhL,aAAc0wC,GACxBvzC,EAAOysC,OAEFzf,EAAYhtB,EAAO83D,QAAQ1wB,OAAOsK,YAAaxK,GAIrD,IAAM,MAAMphD,KAAQknC,EAAU+d,WACxBjlD,EAAKlC,GAAI,UAAW0mC,KAAcxkC,EAAKkd,SAAU6G,KACrD4L,EAAO2K,SAAUvW,EAAW/jB,GAC5BwtG,EAAoBjhG,IAAKvM,GACzBypD,GAAU,GAKb,OAAOA,IAIRvvC,EAAO+3D,WAAWjV,IAAK,mBAAoBzwD,IAAKo2C,IAO/C,SAASuK,IACR75B,EAAK0nB,OAAQprB,IACZ,IAAM,MAAM3vB,KAAQwtG,EAAoBxjG,SACvC2lB,EAAO6K,YAAazW,EAAW/jB,GAC/BwtG,EAAoB97F,OAAQ1R,KAT/B2iD,EAAW97B,GAAI,SAAUqmC,EAAiB,CAAE9+C,SAAU,YACtDu0C,EAAW97B,GAAI,SAAUqmC,EAAiB,CAAE9+C,SAAU,YACtDu0C,EAAW97B,GAAI,YAAaqmC,EAAiB,CAAE9+C,SAAU,YACzDu0C,EAAW97B,GAAI,YAAaqmC,EAAiB,CAAE9+C,SAAU,cDmCzDq/F,CAAiBvzF,EAAQ,WAAY,IArFf,oBAwFtBvc,KAAK+vG,+CAGL/vG,KAAKgwG,2BAGLhwG,KAAKiwG,wBAGLjwG,KAAKkwG,gCAeN,2BAA4BC,GAC3B,MAAM5zF,EAASvc,KAAKuc,OAId2xF,EADU3xF,EAAO24C,SAAS92D,IAAK,QACD8vG,oBAG/B3xF,EAAOV,OAAOzd,IAAK,kCACvB8vG,EAAoBt/F,IAAK,CACxBtM,GAAI,iBACJ5D,KA1HwB,YA2HxBwS,SAAU2uF,GAAOoP,GAAsB9kG,KAAM01F,GAC7Cv8F,WAAY,CACXlC,OAAQ,SACRgvG,IAAK,yBAKRlC,EAAoBt/F,IAAKuhG,GAEpBjC,EAAoBnsG,QACxBwa,EAAO+3D,WAAWjV,IAAK,YAAazwD,IAAKs/F,EAAoBmC,iBAgB/D,wBAAyBC,GACxB,IAAMA,EAA2BvuG,OAChC,OAGD,MAAMwa,EAASvc,KAAKuc,OAEd0xF,EADU1xF,EAAO24C,SAAS92D,IAAK,QACJ6vG,iBAEjCqC,EAA2B7sG,QAAS6rG,IACnC/yF,EAAOysC,MAAMC,OAAOlyB,OAAQ,QAAS,CAAEigC,gBAAiBs4C,EAAUhtG,KAGlE2rG,EAAiBr/F,IAAK,IAAIogG,GAAiBM,IAE3C/yF,EAAO+3D,WAAWjV,IAAK,YAAaG,mBAAoB,CACvDxW,MAAOsmD,EAAUhtG,GACjBozB,KAAM,CAAE66E,GAAuBv+E,aAC9B,GAAKu+E,EAAsB,CAC1B,MAAMjtG,EAAa2qG,EAAiB7vG,IAAKkxG,EAAUhtG,IAAKgB,WAClDsb,EAAUoT,EAAOmK,uBAAwB,IAAK74B,EAAY,CAAEmN,SAAU,IAG5E,OAFAuhB,EAAOg2E,kBAAmB,QAAQ,EAAMppF,GAEjCA,MAIVrC,EAAO+3D,WAAWjV,IAAK,UAAWI,mBAAoB,CACrD/pC,KAAM,CACL53B,KAAM,IACNwF,WAAY2qG,EAAiB7vG,IAAKkxG,EAAUhtG,IAAKgB,YAElD0lD,MAAO,CACNlqD,IAAKwwG,EAAUhtG,QAiBnB,+CACC,MAAMia,EAASvc,KAAKuc,OACdysC,EAAQzsC,EAAOysC,MACf5+B,EAAY4+B,EAAMhoD,SAASopB,UAC3B0kF,EAAcvyF,EAAO24C,SAAS92D,IAAK,QAEzC4B,KAAKmR,SAAU63C,EAAO,gBAAiB,KACtC,MAAM17B,EAAalD,EAAU+E,OAAO7B,WAC9BF,EAAYhD,EAAU+E,OAAO/B,UAW7BhD,EAAUlL,aAAc,aAexBoO,GAiBAA,EAAWpO,aAAc,cAkB1BkO,GAAaA,EAAUlO,aAAc,aAI1C8pC,EAAM5L,OAAQprB,IACbw+E,GAAmCx+E,EAAQ88E,EAAYb,sBAEtD,CAAEx9F,SAAU,QAchB,2BACC,MAAM8L,EAASvc,KAAKuc,OACduyF,EAAcvyF,EAAO24C,SAAS92D,IAAK,QAEzCme,EAAO83D,QAAQ3+C,KAAKknB,YAAa,IAEjC,IAAI6zD,GAAU,EAGdzwG,KAAKmR,SAAUoL,EAAO83D,QAAQ3+C,KAAK10B,SAAU,YAAa,KACzDyvG,GAAU,IAIXzwG,KAAKmR,SAAUoL,EAAO83D,QAAQ3+C,KAAK10B,SAAU,kBAAmB,KAC/D,IAAMyvG,EACL,OAIDA,GAAU,EAEV,MAAMrmF,EAAY7N,EAAOysC,MAAMhoD,SAASopB,UAGxC,IAAMA,EAAUqD,YACf,OAID,IAAMrD,EAAUlL,aAAc,YAC7B,OAGD,MAAM2L,EAAWT,EAAUoH,mBACrBg9E,EAAYzC,GAAoBlhF,EAAU,WAAYT,EAAUhL,aAAc,YAAc7C,EAAOysC,QAIpGn+B,EAASk2B,WAAYytD,EAAU3tF,QAAWgK,EAASk2B,WAAYytD,EAAU1tF,OAC7EvE,EAAOysC,MAAM5L,OAAQprB,IACpBw+E,GAAmCx+E,EAAQ88E,EAAYb,sBAgB3D,wBACC,MAAM1xF,EAASvc,KAAKuc,OACdmZ,EAAOnZ,EAAO83D,QAAQ3+C,KAG5B,IAAIg7E,EAGAC,EAGJ3wG,KAAKmR,SAAUukB,EAAK10B,SAAU,SAAU,KACvC2vG,GAAiB,GACf,CAAElgG,SAAU,SAIfzQ,KAAKmR,SAAUoL,EAAOysC,MAAO,gBAAiB,KAC7C,MAAM5+B,EAAY7N,EAAOysC,MAAMhoD,SAASopB,UAGnCA,EAAUqD,cAKVkjF,EACJA,GAAiB,EAMZC,GAAUr0F,IA6HnB,SAA+BysC,GAC9B,MAAM5+B,EAAY4+B,EAAMhoD,SAASopB,UAC3BymF,EAAgBzmF,EAAUoH,mBAC1Bs/E,EAAe1mF,EAAUqH,kBACzBs/E,EAAsBF,EAAczjF,UAG1C,IAAM2jF,EACL,OAAO,EAIR,IAAMA,EAAoB5wG,GAAI,SAC7B,OAAO,EAIR,IAAM4wG,EAAoB7xF,aAAc,YACvC,OAAO,EAKR,MAAM8xF,EAAqBF,EAAa3yF,UAAY2yF,EAAaxjF,WAGjE,GAAKyjF,IAAwBC,EAC5B,OAAO,EAQR,OAHkBjF,GAAoB8E,EAAe,WAAYE,EAAoB3xF,aAAc,YAAc4pC,GAGhG3H,cAAe2H,EAAM1iB,YAAauqE,EAAeC,IAAgB,GA5J3EG,CAAsB10F,EAAOysC,SACjC0nD,EAAsBtmF,EAAU2Q,mBAE/B,CAAEtqB,SAAU,SAIfzQ,KAAKmR,SAAUoL,EAAOysC,MAAO,gBAAiB,CAAElyC,GAAO8H,MACtD+xF,GAAiB,EAGXC,GAAUr0F,IAIVm0F,IAINn0F,EAAOysC,MAAM5L,OAAQprB,IACpB,IAAM,MAAQ7S,EAAW3gB,KAAWkyG,EACnC1+E,EAAOtuB,aAAcyb,EAAW3gB,EAAOogB,KAIzC8xF,EAAsB,OACpB,CAAEjgG,SAAU,SAiBhB,gCACC,MAAM8L,EAASvc,KAAKuc,OACdysC,EAAQzsC,EAAOysC,MACf5+B,EAAY4+B,EAAMhoD,SAASopB,UAC3BsL,EAAOnZ,EAAO83D,QAAQ3+C,KACtBo5E,EAAcvyF,EAAO24C,SAAS92D,IAAK,QAGzC,IAAI8yG,GAA2B,EAG3BC,GAAsB,EAG1BnxG,KAAKmR,SAAUukB,EAAK10B,SAAU,SAAU,CAAE8V,EAAKnX,KAC9CwxG,EAAsBxxG,EAAK+zC,SAASnf,UAAYlB,GAASK,WACvD,CAAEjjB,SAAU,SAIfzQ,KAAKmR,SAAU63C,EAAO,gBAAiB,KAEtCkoD,GAA2B,EAE3B,MAAMrmF,EAAWT,EAAUoH,mBACrB4/E,EAAWhnF,EAAUhL,aAAc,YAEzC,IAAMgyF,EACL,OAGD,MAAM5C,EAAYzC,GAAoBlhF,EAAU,WAAYumF,EAAUpoD,GAItEkoD,EAA2B1C,EAAU7gF,iBAAkB9C,IAAc2jF,EAAU1tF,IAAIwL,QAASzB,IAC1F,CAAEpa,SAAU,SAGfzQ,KAAKmR,SAAU63C,EAAO,gBAAiB,KAEhCmoD,IAINA,GAAsB,EAGjBD,GAKL30F,EAAOysC,MAAMqC,cAAer5B,IAC3Bw+E,GAAmCx+E,EAAQ88E,EAAYb,sBAEtD,CAAEx9F,SAAU,SAUjB,SAAS+/F,GAAmCx+E,EAAQi8E,GACnDj8E,EAAOysC,yBAA0B,YAEjC,IAAM,MAAM6wC,KAAarB,EACxBj8E,EAAOysC,yBAA0B6wC,EAAUhtG,IAkD7C,SAASsuG,GAAUr0F,GAGlB,OAFcA,EAAOtE,QAAQ7Z,IAAK,SAErBizG,QAAS90F,EAAOysC,MAAM5L,OAAQprB,GAAUA,EAAOm5B,QEtiB9C,MAAM,WAAqBqxC,GAIzC,wBACC,MAAO,eAMR,OAECx8F,KAAKkpB,GAAI,eAAgB,CAAEpS,EAAKnX,KAC/BxC,OAAOm0G,MAAO3xG,EAAKU,UACjB,CAAEoQ,SAAU,WA0BhB,YAAapQ,EAASV,EAAO,IAC5BK,KAAKuxG,kBAAmB,CACvBlxG,UACAJ,KAAM,UACN+9E,UAAWr+E,EAAKq+E,UAChBwzB,MAAO7xG,EAAK6xG,QA2Bd,SAAUnxG,EAASV,EAAO,IACzBK,KAAKuxG,kBAAmB,CACvBlxG,UACAJ,KAAM,OACN+9E,UAAWr+E,EAAKq+E,UAChBwzB,MAAO7xG,EAAK6xG,QAkDd,YAAanxG,EAASV,EAAO,IAC5BK,KAAKuxG,kBAAmB,CACvBlxG,UACAJ,KAAM,UACN+9E,UAAWr+E,EAAKq+E,UAChBwzB,MAAO7xG,EAAK6xG,QAcd,kBAAmB7xG,GAClB,MAAMsR,EAAQ,QAAStR,EAAKM,MAAYN,EAAKq+E,UAAY,IAAKr+E,EAAKq+E,UAAe,IAElFh+E,KAAKqU,KAAMpD,EAAO,CACjB5Q,QAASV,EAAKU,QACdJ,KAAMN,EAAKM,KACXuxG,MAAO7xG,EAAK6xG,OAAS,MCtJT,MAAM,WAAwBnkB,GAI5C,YAAa9wE,GACZ3c,MAAO2c,GAGPvc,KAAKsR,cAAetR,KAAKuc,OAAOysC,MAAMhoD,SAAU,UAGhDhB,KAAKmR,SAAUnR,KAAKuc,OAAOysC,MAAMhoD,SAAU,SAAU,IAAMhB,KAAK+pE,UAAW,CAAEt5D,SAAU,QAMxF,UACC,MAAMghG,EAAezxG,KAAKuc,OAAO24C,SAAS92D,IAAK,eACzC0wG,EAAc9uG,KAAKuc,OAAO24C,SAAS92D,IAAK,QAG9C4B,KAAKsvC,UAAYmiE,EAAaniE,WAAaw/D,EAAYx/D,UAMxD,UACC,MAAM/yB,EAASvc,KAAKuc,OAEdm1F,EAAe1xG,KAAKuc,OAAOV,OAAOzd,IAAK,0BAA6B,QAE1E,GAAqB,SAAhBszG,GAA2C,SAAhBA,EAM/B,MAAM,IAAI,KAAe,gCAAiCn1F,GAG3D,MAAMra,EAAUlC,KAAKuc,OAAOV,OAAOzd,IAAK,qBAAwB,GAEhE8D,EAAQyvG,aAAc,EAGtB,MAAMC,EAAiB1vG,EAAQ2vG,OAGzB3vG,EAAQqY,WACbrY,EAAQqY,SAAWgC,EAAON,OAAOb,YAIlClZ,EAAQ2vG,OAASC,IAEXF,GACJA,EAAgBE,GAGjBA,EAAO5oF,GAAI,eAAgBpS,IAC1B,MAAMo0E,EAAQp0E,EAAInX,KAAKurF,MAAM7wE,UAGvB03F,EAAQ7mB,EAAMlnF,OAAQ+4F,IAASA,EAAKiV,WACpCC,EAAS/mB,EAAMlnF,OAAQ+4F,GAAQA,EAAKiV,WAE1C,IAAM,MAAME,KAAYH,EACvBx1F,EAAO04C,QAAS,OAAQi9C,EAASC,UAGlC,MAAMC,EAAa,GAEnB,IAAM,MAAMC,KAASJ,EAAS,CAC7B,MAAMpS,EAAMwS,EAAMF,SAElBC,EAAWnvG,KAAM48F,GAAYiS,EAAOQ,QAAS,mBAAoB,CAAEvV,KAAMsV,KAGrED,EAAWrwG,QACfwwG,GAAch2F,EAAQ61F,KAIxBN,EAAO5oF,GAAI,2BAA4BpS,IACtC,MAAM07F,EAAa17F,EAAInX,KAAK6yG,WAE5B,GAAMA,EAYND,GAAch2F,EAAQ,CAAEi2F,QAZxB,CACC,MAAMC,EAAel2F,EAAOtE,QAAQ7Z,IAAK,gBACnCK,EAAI8d,EAAON,OAAOxd,EAExBg0G,EAAaC,YAAaj0G,EAAG,uCAAyC,CACrE+yG,MAAO/yG,EAAG,kCACVu/E,UAAW,iBAUf7gF,OAAOw1G,SAAUjB,GAAgBxvG,IAInC,SAASqwG,GAAch2F,EAAQq2F,GAI9B,GAHqBr2F,EAAO24C,SAAS92D,IAAK,eAGvBkxC,UAYnB/yB,EAAO04C,QAAS,cAAe,CAAErqD,OAAQgoG,QAZzC,CACC,MAAMH,EAAel2F,EAAOtE,QAAQ7Z,IAAK,gBACnCK,EAAI8d,EAAON,OAAOxd,EAExBg0G,EAAaC,YAAaj0G,EAAG,mDAAqD,CACjF+yG,MAAO/yG,EAAG,0BACVu/E,UAAW,cC7HC,MAAM,WAAwB,GAI5C,wBACC,MAAO,kBAMR,sBACC,MAAO,CAAE,GAAc,GAAc,IAMtC,OACC,MAAMzhE,EAASvc,KAAKuc,OAEpBA,EAAO24C,SAAStmD,IAAK,WAAY,IAAI,GAAiB2N,KC3BxD,MAAMs2F,GAAwB,uBAKf,MAAM,GAQpB,YAAaC,EAAY3T,EAAO4T,GAC/B,IAAMD,EAML,MAAM,IAAI,KAAe,4BAA6B,MAGvD,IAAM3T,EAML,MAAM,IAAI,KAAe,6BAA8B,MAGxD,IAAM4T,EAML,MAAM,IAAI,KAAe,mCAAoC,MAQ9D/yG,KAAK+8F,KA8NP,SAAoBniF,GACnB,GAAuB,iBAAXA,EACX,OAAO,EAGR,MAAMc,EAAQd,EAAOc,MAAOm3F,IAC5B,SAAWn3F,IAASA,EAAM3Z,QApObixG,CAAWF,GA0LzB,SAAwBG,EAAQC,EAAY,KAC3C,IACC,MAAMC,EAAcF,EAAOv3F,MAAOm3F,IAAyB,GACrDO,EAAalyG,KAAM+xG,EAAO/oG,QAAS2oG,GAAuB,KAE1DQ,EAAa,GAEnB,IAAM,IAAI/mG,EAAS,EAAGA,EAAS8mG,EAAWrxG,OAAQuK,GAAU4mG,EAAY,CACvE,MAAMzrG,EAAQ2rG,EAAW3rG,MAAO6E,EAAQA,EAAS4mG,GAC3CI,EAAc,IAAInqG,MAAO1B,EAAM1F,QAErC,IAAM,IAAIxE,EAAI,EAAGA,EAAIkK,EAAM1F,OAAQxE,IAClC+1G,EAAa/1G,GAAMkK,EAAM8Y,WAAYhjB,GAGtC81G,EAAWpwG,KAAM,IAAIkK,WAAYmmG,IAGlC,OAAO,IAAIC,KAAMF,EAAY,CAAEpzG,KAAMkzG,IACpC,MAAQ/yG,GAMT,MAAM,IAAI,KAAe,yCAA0C,OAnN7BozG,CAAeV,GAAeA,EAQpE9yG,KAAKyzG,OAAStU,EAQdn/F,KAAK0zG,YAAcX,EAUpB,WAAY7hG,GAGX,OAFAlR,KAAKkpB,GAAI,WAAY,CAAEjY,EAAOtR,IAAUuR,EAAUvR,IAE3CK,KAUR,QAASkR,GAGR,OAFAlR,KAAKm0E,KAAM,QAAS,CAAEljE,EAAOtR,IAAUuR,EAAUvR,IAE1CK,KAMR,QACCA,KAAKigG,IAAI5C,QASV,OAIC,OAHAr9F,KAAK2zG,kBACL3zG,KAAK4zG,sBAEE5zG,KAAKggG,eAQb,kBACC,MAAMC,EAAM,IAAIC,eAEhBD,EAAIE,KAAM,OAAQngG,KAAK0zG,aACvBzT,EAAI4T,iBAAkB,gBAAiB7zG,KAAKyzG,OAAOj1G,OACnDyhG,EAAIG,aAAe,OAEnBpgG,KAAKigG,IAAMA,EAQZ,sBACC,MAAM9nF,EAAOnY,KACPigG,EAAMjgG,KAAKigG,IA0BjB,SAAS6T,EAASzzG,GACjB,MAAO,IAAM8X,EAAK9D,KAAM,QAAShU,GAzBlC4/F,EAAIhxD,iBAAkB,QAAS6kE,EAAS,kBACxC7T,EAAIhxD,iBAAkB,QAAS6kE,EAAS,UAGnC7T,EAAInB,QACRmB,EAAInB,OAAO7vD,iBAAkB,WAAYh+B,IACnCA,EAAMsvF,kBACVvgG,KAAKqU,KAAM,WAAY,CACtB2oF,MAAO/rF,EAAM+rF,MACbU,SAAUzsF,EAAMqH,WAMpB2nF,EAAIhxD,iBAAkB,OAAQ,KAC7B,MAAM8kE,EAAa9T,EAAIrB,OACjBoV,EAAc/T,EAAIK,SAExB,GAAKyT,EAAa,KAAOA,EAAa,IACrC,OAAO/zG,KAAKqU,KAAM,QAAS2/F,EAAY3zG,SAAW2zG,EAAY5zG,SAcjE,eACC,MAAM6zG,EAAW,IAAIzT,SACfP,EAAMjgG,KAAKigG,IAIjB,OAFAgU,EAASp4C,OAAQ,OAAQ77D,KAAK+8F,MAEvB,IAAIhkF,QAAS,CAAE/L,EAASgM,KAC9BinF,EAAIhxD,iBAAkB,OAAQ,KAC7B,MAAM8kE,EAAa9T,EAAIrB,OACjBoV,EAAc/T,EAAIK,SAExB,OAAKyT,EAAa,KAAOA,EAAa,IAChCC,EAAY3zG,QAMT2Y,EAAQ,IAAI,KAClB,qCACAhZ,KACA,CAAEK,QAAS2zG,EAAY3zG,WAIlB2Y,EAAQg7F,EAAY5zG,OAGrB4M,EAASgnG,KAGjB/T,EAAIhxD,iBAAkB,QAAS,IAAMj2B,EAAQ,IAAIxZ,MAAO,mBACxDygG,EAAIhxD,iBAAkB,QAAS,IAAMj2B,EAAQ,IAAIxZ,MAAO,WAExDygG,EAAIQ,KAAMwT,MAmBbz/F,GAAK,GAAc,IC9NnB,MAAM0/F,GAAkB,CAAEC,aAAa,GASvC,MAAM,GAWL,YAAaC,EAAwBlyG,EAAUgyG,IAC9C,IAAME,EAML,MAAM,IAAI,KACT,0BACAp0G,MAIGkC,EAAQmyG,WACZr0G,KAAKs0G,oBAAqBpyG,EAAQmyG,WAanCr0G,KAAKyJ,IAAK,QAASvH,EAAQmyG,WAS1Br0G,KAAK0jE,SADiC,mBAA3B0wC,EACKA,EAEA,KAAMG,OA4JKC,EA5JgBJ,EA6JtC,IAAIr7F,QAAS,CAAE/L,EAASgM,KAC9B,MAAMinF,EAAM,IAAIC,eAEhBD,EAAIE,KAAM,MAAOqU,GAEjBvU,EAAIhxD,iBAAkB,OAAQ,KAC7B,MAAM8kE,EAAa9T,EAAIrB,OACjBoV,EAAc/T,EAAIK,SAExB,OAAKyT,EAAa,KAAOA,EAAa,IAM9B/6F,EACN,IAAI,KAAe,kCAAmC,OAIjDhM,EAASgnG,KAGjB/T,EAAIhxD,iBAAkB,QAAS,IAAMj2B,EAAQ,IAAIxZ,MAAO,mBACxDygG,EAAIhxD,iBAAkB,QAAS,IAAMj2B,EAAQ,IAAIxZ,MAAO,WAExDygG,EAAIQ,SA3BN,IAA8B+T,GArJ5Bx0G,KAAKy0G,SAAWx2G,OAAO4nC,OAAQ,GAAIquE,GAAiBhyG,GAQrD,OACC,OAAO,IAAI6W,QAAS,CAAE/L,EAASgM,KACxBhZ,KAAKxB,OAQNwB,KAAKy0G,SAASN,aAClBn0G,KAAK00G,+BAGN1nG,EAAShN,OAXRA,KAAK20G,eACHz7F,KAAMlM,GACN4M,MAAOZ,KAiBZ,eACC,OAAOhZ,KAAK0jE,WACVxqD,KAAM1a,IACNwB,KAAKs0G,oBAAqB91G,GAC1BwB,KAAKyJ,IAAK,QAASjL,GAEdwB,KAAKy0G,SAASN,aAClBn0G,KAAK00G,iCAGNx7F,KAAM,IAAMlZ,MAMf,UACCi2C,aAAcj2C,KAAK40G,sBASpB,oBAAqBC,GAEpB,MAAMC,EAAiC,iBAAfD,EAGlBE,GAAiB,SAAS5qG,KAAM0qG,GAIhCG,EAAcF,GAA+C,IAAnCD,EAAWtlG,MAAO,KAAMxN,OAExD,IAAQgzG,IAAiBC,EAMxB,MAAM,IAAI,KAAe,0BAA2Bh1G,MAStD,+BACC,MAAMi1G,EAA0Bj1G,KAAKk1G,8BAErCj/D,aAAcj2C,KAAK40G,sBAEnB50G,KAAK40G,qBAAuBp/D,WAAY,KACvCx1C,KAAK20G,gBACHM,GAWJ,8BACC,IACC,MAAQ,CAAEE,GAAuBn1G,KAAKxB,MAAM+Q,MAAO,MAC3C6lG,IAAKC,GAAoBx1G,KAAK0+D,MAAOr9D,KAAMi0G,IAEnD,IAAME,EACL,OA1KuC,KA+KxC,OAFgCjlG,KAAKklG,OAA6B,IAAlBD,EAA2BxzF,KAAKC,OAAU,GAGzF,MAAQ5hB,GACT,OAjLwC,MA+L1C,cAAek0G,EAAwBlyG,EAAUgyG,IAGhD,OAFc,IAAI,GAAOE,EAAwBlyG,GAEpCoa,QAIf9H,GAAK,GAAO,IA8CG,UC/OA,MAAM,WAAsBgoF,GAI1C,wBACC,MAAO,gBAMR,OACC,MAEMt6F,EAFSlC,KAAKN,QAAQmc,OAELzd,IAAK,kBAAqB,GAEjD,IAAM,MAAMm3G,KAAcrzG,EACzBlC,KAAMu1G,GAAerzG,EAASqzG,GAkC/B,GAzBAv1G,KAAKw1G,QAAU,IAAI1hG,IAyBb9T,KAAKw0G,SAUX,OAJAx0G,KAAKm/F,MAAQ,IAAI,GAAcsW,MAAOz1G,KAAKw0G,UAE3Cx0G,KAAKw1G,QAAQ/rG,IAAKzJ,KAAKw0G,SAAUx0G,KAAKm/F,OAE/Bn/F,KAAKm/F,MAAM7iF,OATjBtc,KAAKm/F,MAAQ,KAmBf,iBAAkBqV,GAEjB,GAAKx0G,KAAKw1G,QAAQ9rG,IAAK8qG,GACtB,OAAOz7F,QAAQ/L,QAAShN,KAAK01G,YAAalB,IAG3C,MAAMrV,EAAQ,IAAI,GAAcsW,MAAOjB,GAIvC,OAFAx0G,KAAKw1G,QAAQ/rG,IAAK+qG,EAAUrV,GAErBA,EAAM7iF,OASd,YAAak4F,GACZ,MAAMrV,EAAQn/F,KAAKw1G,QAAQp3G,IAAKo2G,GAEhC,IAAMrV,EAML,MAAM,IAAI,KAAe,qCAAsCn/F,MAGhE,OAAOm/F,EAMR,UACCv/F,MAAMsa,UAEN,IAAM,MAAMilF,KAASn/F,KAAKw1G,QAAQnpG,SACjC8yF,EAAMjlF,WAKT,GAAcu7F,MAAQ,GClHP,MAAM,WAAmC,GAIvD,sBACC,MAAO,CAAE,GAAgB,IAM1B,OACC,MAAMl5F,EAASvc,KAAKuc,OAEdo5F,EAAgBp5F,EAAOtE,QAAQ7Z,IAAK,IAEpC+gG,EAAQwW,EAAcxW,MACtByW,EAAYD,EAAcC,UAE1BzW,IAINn/F,KAAK61G,eAAiB,IAAI,GAA2BC,eAAgB3W,EAAOyW,GAE5Er5F,EAAOtE,QAAQ7Z,IAAK,IAAiBw/F,oBAAsBC,GACnD,IAAIkY,GAAS/1G,KAAK61G,eAAgBhY,KAQ5C,MAAMkY,GACL,YAAaC,EAAenY,GAC3B79F,KAAKg2G,cAAgBA,EAErBh2G,KAAK69F,OAASA,EAGf,SACC,OAAO79F,KAAK69F,OAAOd,KAAK7jF,KAAM6jF,IAC7B/8F,KAAKi2G,aAAej2G,KAAKg2G,cAAclX,OAAQ/B,GAE/C/8F,KAAKi2G,aAAa/sF,GAAI,WAAY,CAAEpS,EAAKnX,KACxCK,KAAK69F,OAAOG,YAAcr+F,EAAKq9F,MAC/Bh9F,KAAK69F,OAAOH,SAAW/9F,EAAK+9F,WAGtB19F,KAAKi2G,aAAaxV,SAI3B,QACCzgG,KAAKi2G,aAAa5Y,SAMpB,GAA2ByY,eCtEZ,MAOd,YAAa3W,EAAO4T,GACnB,IAAM5T,EAML,MAAM,IAAI,KAAe,8BAA+B,MAGzD,IAAM4T,EAML,MAAM,IAAI,KAAe,oCAAqC,MAS/D/yG,KAAKyzG,OAAStU,EAQdn/F,KAAK0zG,YAAcX,EAkBpB,OAAQD,GACP,OAAO,IAAI,GAAcA,EAAY9yG,KAAKyzG,OAAQzzG,KAAK0zG,e,MCtCzD,MAAMwC,GAA+B,CAAE,SAAU,SAG3CC,IAA4B,IAAIhhC,WAAYM,gBCvCnC,mIDuCgE,iBAAkBzwE,WAgBlF,MAAM,WAAyB,GAI7C,wBACC,MAAO,mBAMR,YAAauX,GACZ3c,MAAO2c,GAUPvc,KAAKo2G,8BAAgC,KAMtC,OACC,MAAM75F,EAASvc,KAAKuc,OACdk7D,EAAcl7D,EAAO83D,QAAQ3+C,KAInC11B,KAAKkpB,GAAI,mBAAoB,CAAEpS,EAAKnX,EAAM2vC,KACzCmoC,EAAYr6B,OAAQprB,IACnB,IAAM,MAAMn1B,KAAQ46E,EAAYz2E,SAAS6wB,MACnCyd,EACJtd,EAAO6K,YApD8B,kCAoDmBhgC,GAExDm1B,EAAO2K,SAtD8B,kCAsDgB9/B,KAKlDyyC,GACL/yB,EAAOysC,MAAM5L,OAAQprB,IACpBA,EAAOysC,yBhCvFmC,0BgC4F7Cz+D,KAAKq2G,+BACLr2G,KAAKs2G,0CACLt2G,KAAKu2G,4CACLv2G,KAAKw2G,8CACLx2G,KAAKy2G,0DACLz2G,KAAK02G,2BACL12G,KAAK22G,kCAMN,UACC32G,KAAKo2G,8BAAgC,KAatC,iBAAkBQ,EAAoB/rF,GACrC,MAAMtO,EAASvc,KAAKuc,OACdk7D,EAAcl7D,EAAO83D,QAAQ3+C,KAEnCnZ,EAAO04C,QAAS,kBAAmB,CAClCpqC,SAAUtO,EAAOysC,MAAMoI,iBAAkBwlD,EAAoB/rF,KAG9D4sD,EAAY5nD,QACZ4nD,EAAYoV,uBAgBb,mBAAoBt7E,EAASN,EAAOC,EAAUhP,GAC7ClC,KAAKmR,SAAUI,EAASN,EAAO,IAAKI,KAE9BrR,KAAKsvC,WACTp+B,KAAaG,IAEZnP,GAeJ,+CACC,MAEMmyD,EAFSr0D,KAAKuc,OACCysC,MACQhoD,SAASopB,UAChCy+E,EAA8Bf,GAAgCzzC,GAEpE,IAAMw0C,EACL,OAAO,EAGR,MAAMgO,EAAuBxiD,EAAe3iC,qBAI5C,OAFA1xB,KAAK82G,iBAAkBD,EAAsBhO,IAEtC,EAYR,+BACC,MAAMtsF,EAASvc,KAAKuc,OACd0sC,EAAS1sC,EAAOysC,MAAMC,OACtBxqD,EAAI8d,EAAON,OAAOxd,EAClBs4G,EAAe,CACpBC,OAAQv4G,EAAG,iCACXw4G,MAAOx4G,EAAG,iCAGX8d,EAAO83D,QAAQrgB,mBAAmB9qC,GAAI,SAAU,CAAEpS,EAAKnX,EAAMolD,KAC5D,MAAMjqB,EAAciqB,EAAcpB,OAAOR,cAAexjD,EAAK0C,MAGxDulG,GAAoB9sE,EAAan7B,EAAK0C,KAAM4mD,IA8fpD,SAA6B+E,EAAY+oD,EAAcG,GACtD,MAAMC,EAAoBnpD,EAAWmC,gBAAiB,MAAO,CAC5D4tB,MAAO,2CACL,SAAU1oD,GACZ,MAAM+hF,EAAoBp3G,KAAKs1B,aAAcD,GAK7C,OAaF,SAAwB+hF,EAAmBL,GAC1C,IAAM,MAAMlsF,KAAYqrF,GAA+B,CACtD,MAAMmB,EAAiB,IAAI,GAAU,CACpCjvG,IAAK,MACL9E,WAAY,CACXy6E,MAAO,CACN,KACA,iCACA,kCAAmClzD,GAEpC2mF,MAAOuF,EAAclsF,IAEtB/iB,SAAU,CACTsvG,EAAkBthF,cAAcwhF,WAAYnB,IAA2B,MAIzEiB,EAAkBxzG,YAAayzG,EAAe7/E,WAjC9C+/E,CAAeH,EAAmBL,GAsCpC,SAA0BK,GACzB,MAAMI,EAAgB,IAAI,GAAU,CACnCpvG,IAAK,MACL9E,WAAY,CACXy6E,MAAO,CACN,KACA,yCAKHq5B,EAAkBxzG,YAAa4zG,EAAchgF,UAhD5CigF,CAAiBL,GAEVA,KAIRppD,EAAWrqD,OAAQqqD,EAAWoD,iBAAkB8lD,EAAmB,OAASC,GA1gBzEO,CAAoB3yD,EAAc/yB,OAAQ+kF,EAAcj8E,IAEvD,CAAErqB,SAAU,QA8BhB,0DACC,MAAM8L,EAASvc,KAAKuc,OACdysC,EAAQzsC,EAAOysC,MACfqL,EAAiBrL,EAAMhoD,SAASopB,UAChC6+B,EAASD,EAAMC,OACfwuB,EAAcl7D,EAAO83D,QAAQ3+C,KAgGnC,SAASiiF,EAA0B9sF,GAClC,MAAO,yCAA0CA,EA5FlD7qB,KAAK43G,mBAAoBngC,EAAYz2E,SAAU,UAAW,CAAE8V,EAAK83E,KAC3D55D,GAAgB45D,EAAar6D,UACjCv0B,KAAK63G,qBAAsB/gG,EAAK83E,IAE/B,CAAEn+E,SAAU,GAAWrS,IAAK,QAAW,KAM1C4B,KAAK43G,mBAAoBvjD,EAAgB,eAAgB,CAAEv9C,EAAKnX,KAEzDA,EAAKuoD,cAMX3rC,EAAOysC,MAAM5L,OAAQprB,IACpBA,EAAOysC,yBhCzQoC,0BgC+Q7Cz+D,KAAK43G,mBAAoB5uD,EAAMhoD,SAAU,cAAe,KACvD,MAAM61G,EAAuBxiD,EAAe3iC,qBAE5C,GAAKmlF,EAAuB,CAG3B,GAAKjP,GAFuBrrF,EAAO83D,QAAQ1wB,OAAOR,cAAe0zD,GAEnBA,EAAsB5tD,GACnE,OAIF1sC,EAAOysC,MAAM5L,OAAQprB,IACpBA,EAAOysC,yBhC3RoC,0BgCkS7Cz+D,KAAK43G,mBAAoBr7F,EAAO83D,QAAQrgB,mBAAoB,YAAa,CAAEl9C,EAAKnX,EAAMolD,KACrF,MAAM/yB,EAAS+yB,EAAc/yB,OAE7B,GAAKhyB,KAAKo2G,8BAAgC,CACzC,MAAM0B,EAAsB/yD,EAAcpB,OAAOR,cAAenjD,KAAKo2G,+BAEhE0B,IAEJ9lF,EAAO6K,YAAaq5E,GAA6B7rG,IAAKstG,GAA4BG,GAElF93G,KAAKo2G,8BAAgC,MAIvC,MAAMS,EAAuBl3G,EAAKyqB,UAAUsH,qBAE5C,IAAMmlF,EACL,OAGD,MAAMiB,EAAsB/yD,EAAcpB,OAAOR,cAAe0zD,GAEhE,IAAMjP,GAAoBkQ,EAAqBjB,EAAsB5tD,GACpE,OAGD,MAAM4/C,EAA8Bf,GAAgCnoG,EAAKyqB,WAEnEy+E,IAIN72E,EAAO2K,SAAUg7E,EAA0B9O,GAA+BiP,GAI1E93G,KAAKo2G,8BAAgCS,KAGtC72G,KAAK43G,mBAAoBr7F,EAAOL,GAAGg6D,aAAc,mBAAoB,CAAEp/D,EAAKhZ,EAAMqsB,KAC3EA,GACL5N,EAAOysC,MAAM5L,OAAQprB,IACpBA,EAAOysC,yBhC5UmC,0BgCoW9C,qBAAsB3nD,EAAK83E,GAC1B,MAAMryE,EAASvc,KAAKuc,OACdysC,EAAQzsC,EAAOysC,MACfqL,EAAiBrL,EAAMhoD,SAASopB,UAChC6+B,EAASD,EAAMC,OACfwuB,EAAcl7D,EAAO83D,QAAQ3+C,KAG7Bw5C,EAAY/5C,GADFy5D,EAAar6D,QACqBhY,EAAON,OAAOT,0BAC1Ds8F,EAAsBrgC,EAAYz2E,SAASopB,UAAUsH,qBAE3D,IAAIqmF,EAGCnQ,GAAoBkQ,EAJIv7F,EAAO83D,QAAQ1wB,OAAOV,eAAgB60D,GAIC7uD,GACnE8uD,EAA8B/3G,KAAKg4G,qCAAsC9oC,GAIhE7a,EAAe5mC,cACxBsqF,EAA8B/3G,KAAKi4G,+CAAgD/oC,IAG/E6oC,IACJnpB,EAAah7C,iBACb98B,EAAIhH,QAeN,qCAAsCo/D,GACrC,MACMlmB,EADShpD,KAAKuc,OACCysC,MAEf6/C,EAA8Bf,GADb9+C,EAAMhoD,SAASopB,WAGtC,OAAO4+B,EAAM5L,OAAQprB,IAEpB,IAAK62E,EAsBJ,OAFA72E,EAAO87D,sBhCxaoC,qBgCwaoB5e,EAAY,QAAU,WAE9E,EAXP,KAVwB25B,KAAkC35B,EAAY,QAAU,WAa/E,OAFAl9C,EAAOysC,yBhChamC,uBgCkanC,EAWT,OAAO,IAmBT,+CAAgDyQ,GAC/C,MAAM3yD,EAASvc,KAAKuc,OACdysC,EAAQzsC,EAAOysC,MACfC,EAASD,EAAMC,OACfivD,EAAe37F,EAAOtE,QAAQ7Z,IAAK,UAGnC+5G,EAA8BD,EAAaE,iCAAkClpC,GAGnF,QAAK04B,GAF8BrrF,EAAO83D,QAAQ1wB,OAAOR,cAAeg1D,GAEnBA,EAA6BlvD,KACjFD,EAAM5L,OAAQprB,IACbkmF,EAAaG,yBAA0BF,GACvCnmF,EAAO87D,sBhC7coC,qBgC6coB5e,EAAY,SAAW,YAKhF,GAaT,0CACC,MAAM3yD,EAASvc,KAAKuc,OACdk7D,EAAcl7D,EAAO83D,QAAQ3+C,KAEnC11B,KAAK43G,mBAAoBngC,EAAYz2E,SAAU,YAAa,CAAE8V,EAAK83E,KAClE,MAAMiV,EAAwCjV,EAAa/4D,UhC/c3CyiF,QAAS,mCgCidzB,IAAMzU,EACL,OAGD,MAAM0U,EhC1cF,SAAsChjF,GAC5C,OAAOA,EAAWijF,UAAUrxE,SAAU,yCAA4C,SAAW,QgCycpEsxE,CAA6B5U,GAC9CqT,EhChcF,SAAsC3hF,EAAYI,GACxD,MAAM+iF,EAAmBnjF,EAAW+iF,QAAS,cAE7C,OAAO3iF,EAAa4R,aAAcmxE,GgC6bNC,CAA6B9U,EAAQpsB,EAAY9hD,cACrEihF,EAAqBr6F,EAAO83D,QAAQ1wB,OAAOV,eAAgBi0D,GAEjEl3G,KAAK82G,iBAAkBF,EAAoB2B,GAE3C3pB,EAAah7C,iBACb98B,EAAIhH,SAmBN,4CACC,MAAMyM,EAASvc,KAAKuc,OACdk7D,EAAcl7D,EAAO83D,QAAQ3+C,KAEnC11B,KAAK43G,mBAAoBngC,EAAYz2E,SAAU,QAAS,CAAE8V,EAAK83E,KAC9D,MAAMkpB,EAAsBrgC,EAAYz2E,SAASopB,UAAUsH,qBACrDmlF,EAAuBt6F,EAAO83D,QAAQ1wB,OAAOV,eAAgB60D,GAC7D7uD,EAAS1sC,EAAOysC,MAAMC,OAC5B,IAAI2vD,EAIC54G,KAAK64G,+CACTD,GAAa,EAIJhR,GAAoBkQ,EAAqBjB,EAAsB5tD,KACxEjpD,KAAK82G,iBAAkBD,EAAsBjoB,EAAaV,OAAS,SAAW,SAE9E0qB,GAAa,GAGTA,IACJhqB,EAAah7C,iBACb98B,EAAIhH,UAwBP,8CACC,MACM2nE,EADSz3E,KAAKuc,OACO83D,QAAQ3+C,KAC7BojF,EAA+B,CACpCzlF,GAASM,MACTN,GAAStf,OACTsf,GAASK,WAKV1zB,KAAK43G,mBAAoBngC,EAAYz2E,SAAU,UAAW,CAAE8V,EAAK83E,KAE1DkqB,EAA6B1/F,SAAUw1E,EAAar6D,UAAcu7D,GAAsBlB,IAC7F5uF,KAAK64G,gDAEJ,CAAEpoG,SAAU,GAAWrS,IAAK,QAAW,IAa3C,2BACC,MAAMme,EAASvc,KAAKuc,OACdk7D,EAAcl7D,EAAO83D,QAAQ3+C,KAC7BszB,EAAQzsC,EAAOysC,MACfC,EAASD,EAAMC,OAGrBjpD,KAAK43G,mBAAoBngC,EAAYz2E,SAAU,SAAU,CAAE8V,EAAK83E,KAC/D,MAAMia,EAA8Bf,GAAgC9+C,EAAMhoD,SAASopB,WAGnF,IAAMy+E,EACL,OAGD,MAAMj+E,EAAYgkE,EAAahkE,UACzBmuF,EAAsB/vD,EAAMhoD,SAASopB,UAAUsH,qBAG/CsnF,EAA+B,WAAbpuF,EAGxB,GAJ0D,WAAhCi+E,IAE6BmQ,EAGtDz8F,EAAO04C,QAAS,SAAU,CACzB7qC,UAAW4+B,EAAMsL,gBAAiBykD,EAAqB,YAElD,CACN,MAAM9pF,EAAQg6B,EAAO8D,yBACpB/D,EAAMoI,iBAAkB2nD,EAAqBlQ,GAC7Cj+E,GAID,GAAKqE,EAEJ,GAAMA,EAAMxB,YAKL,CACN,MAAMwrF,EAAQjwD,EAAMsL,gBAAiBrlC,EAAMpO,OAK3C,GAJAmoC,EAAMskB,gBAAiB2rC,EAAO,CAAEruF,cAI1BquF,EAAMppF,MAAMvD,QAAS2C,EAAMpO,OAS5B,CACJ,MAAMq4F,EAmIb,SAAyCjwD,EAAQrqC,GAChD,IAAIu6F,EAAuBv6F,EAE3B,IAAM,MAAMyb,KAAYzb,EAAQpB,aAAc,CAAEH,aAAa,IAAW,CACvE,GAAKgd,EAASvT,WAAa,GAAKmiC,EAAOG,QAAS/uB,GAC/C,MAGD8+E,EAAuB9+E,EAGxB,OAAO8+E,EA9IiCC,CAAgCnwD,EAAQh6B,EAAMpO,MAAM9D,QAEtFisC,EAAM8jB,cAAe9jB,EAAMsL,gBAAiB4kD,EAA2B,MAAQ,CAC9EzqC,oBAAoB,SAZrBzlB,EAAM5L,OAAQprB,IACbA,EAAOyI,aAAcxL,GACrB1S,EAAO04C,QAAS+jD,EAAkB,gBAAkB,iBAbtDhwD,EAAM5L,OAAQprB,IACbA,EAAOyI,aAAcxL,GACrB1S,EAAO04C,QAAS+jD,EAAkB,gBAAkB,YA8BxDpqB,EAAah7C,iBACb98B,EAAIhH,QACF,CAAEW,SAAU,GAAWrS,IAAK,QAAW,IAW3C,kCACC,MAAMme,EAASvc,KAAKuc,OACdysC,EAAQhpD,KAAKuc,OAAOysC,MACpBqwD,EAAoBrwD,EAAMhoD,SAASopB,UAEzCpqB,KAAK43G,mBAAoBr7F,EAAOysC,MAAO,gBAAiB,CAAElyC,GAAO5P,EAASynB,MACzE,GAAKA,IAAeA,EAAWxuB,GAAI,qBAClC,OAGD,MAAM0oG,EAA8Bf,GAAgCuR,GAEpE,OAAMxQ,GAIN/xF,EAAIhH,OAEGk5C,EAAM5L,OAAQprB,IACpB,MAAM42E,EAAkByQ,EAAkB3nF,qBACpC7G,EAAWm+B,EAAMoI,iBAAkBw3C,EAAiBC,GACpDz+E,EAAY4H,EAAOsiC,gBAAiBzpC,GAEpC/oB,EAASknD,EAAM6pB,cAAe3rE,EAASkjB,GAI7C,OAFA4H,EAAOyI,aAAcrQ,GAEdtoB,UAfR,GAiBE,CAAE2O,SAAU,U,ME7rBF,SAAS6oG,GAA2BjlC,GAClD,MAAMrrB,EAAQqrB,EAAQrrB,MAEtB,MAAO,CAAElyC,EAAKnX,KACb,MAAM45G,EAAiB55G,EAAK40B,SAAWlB,GAASE,QAC1CimF,EAAmB75G,EAAK40B,SAAWlB,GAASI,UAC5CgmF,EAAkB95G,EAAK+0B,SACvBtK,EAAY4+B,EAAMhoD,SAASopB,UAEjC,IAAMmvF,IAAmBC,EACxB,OAGD,MAAMtqC,EAAYsqC,EAIlB,GAAKC,GA2LP,SAA8BrvF,EAAW8kD,GACxC,OAAQ9kD,EAAUqD,aAAerD,EAAU4F,YAAck/C,EA5LhCwqC,CAAqBtvF,EAAW8kD,GACvD,OAID,MAAMjgD,EAyCR,SAAqColD,EAASjqD,EAAW8kD,GACxD,MAAMlmB,EAAQqrB,EAAQrrB,MAEtB,GAAKkmB,EAAY,CAChB,MAAMvkD,EAAgBP,EAAUqD,YAAcrD,EAAUyF,MAAQzF,EAAUqH,kBACpEgI,EAAckgF,GAA0B3wD,EAAOr+B,EAAe,WAGpE,IAAM8O,EACL,OAAO,KAGR,MAAMxK,EAAQ+5B,EAAM1iB,YAAa3b,EAAe8O,GAC1CmgF,EAAoBC,GAAwB7wD,EAAMC,OAAQh6B,EAAO,YAEvE,OAAK2qF,GAAqBjvF,EAAc9M,SAAU+7F,GAC1C5wD,EAAM1iB,YAAa3b,EAAeivF,GAGnC,KACD,CACN,MAAMngF,EAAcrP,EAAUqD,YAAcrD,EAAUyF,MAAQzF,EAAUoH,mBAClE7G,EAAgBgvF,GAA0B3wD,EAAOvvB,EAAa,YAGpE,IAAM9O,EACL,OAAO,KAGR,MAAMsE,EAAQ+5B,EAAM1iB,YAAa3b,EAAe8O,GAC1CqgF,EAAqBD,GAAwB7wD,EAAMC,OAAQh6B,EAAO,WAExE,OAAK6qF,GAAsBrgF,EAAYvM,QAAS4sF,GACxC9wD,EAAM1iB,YAAawzE,EAAoBrgF,GAGxC,MA7EOsgF,CAA4B1lC,EAASjqD,EAAW8kD,GAExDjgD,IAASA,EAAMxB,aAwIvB,SAA4B4mD,EAAS5wB,EAAYyrB,GAChD,MAAMlmB,EAAQqrB,EAAQrrB,MAChBrzB,EAAe0+C,EAAQ3+C,KAAKC,aAMlC,GAAKu5C,EAAY,CAChB,MAAM+pC,EAAQjwD,EAAMsL,gBAAiB7Q,EAAW5iC,OAEhDmoC,EAAMskB,gBAAiB2rC,GAKjBA,EAAMppF,MAAMjE,SAAY63B,EAAW5iC,MAAMyL,QAAS2sF,EAAMppF,SAC7D4zB,EAAauF,EAAM1iB,YAAa2yE,EAAMppF,MAAO4zB,EAAW3iC,MAI1D,MAAMyoB,EAAY8qC,EAAQ1wB,OAAOsK,YAAaxK,GACxCpd,EAAW1Q,EAAa2nB,eAAgB/T,GACxCuQ,EAAQ,GAAK1B,iBAAkB/R,GAErC,IAAI2zE,EAEJ,IAAM,MAAMphE,KAAQkB,EACnB,QAAkCxzC,IAA7B0zG,EAAL,CAMA,GAAK5pG,KAAK6pG,MAAOrhE,EAAK9S,MAASk0E,EAC9B,OAAO,EAGRA,EAA2B5pG,KAAKsR,IAAKs4F,EAA0B5pG,KAAK6pG,MAAOrhE,EAAKhB,cAT/EoiE,EAA2B5pG,KAAK6pG,MAAOrhE,EAAKhB,QAY9C,OAAO,EAzKDsiE,CAAmB7lC,EAASplD,EAAOigD,KACvClmB,EAAM5L,OAAQprB,IACb,MAAM+G,EAAcm2C,EAAYjgD,EAAMnO,IAAMmO,EAAMpO,MAElD,GAAK44F,EAAkB,CACtB,MAAMnjE,EAAe0S,EAAMsL,gBAAiBlqC,EAAU+E,QACtDmnB,EAAa1kB,SAAUmH,GAEvB/G,EAAOyI,aAAc6b,QAErBtkB,EAAOyI,aAAc1B,KAIvBjiB,EAAIhH,OACJnQ,EAAKi0C,iBACLj0C,EAAKk0C,oBA8DR,SAAS8lE,GAA0B3wD,EAAOr+B,EAAeC,GACxD,MAAMq+B,EAASD,EAAMC,OACfh6B,EAAQ+5B,EAAM0L,cAAe/pC,EAAc9tB,MAE3Cs9G,EAA+B,WAAbvvF,EAAyB,eAAiB,aAElE,IAAM,MAAM,iBAAEe,EAAgB,KAAEtpB,EAAI,KAAEpC,KAAUgvB,EAAMgL,UAAW,CAAEtP,gBAAeC,cAAgB,CACjG,GAAKq+B,EAAOG,QAAS/mD,KAAW4mD,EAAO4D,SAAUxqD,GAChD,OAAOspB,EAIR,GAAK1rB,GAAQk6G,GAAmBlxD,EAAOC,QAAS7mD,GAC/C,OAAO,KAIT,OAAO,KAWR,SAASw3G,GAAwB5wD,EAAQh6B,EAAOrE,GAC/C,MAAMC,EAAwB,YAAbD,EAA0BqE,EAAMnO,IAAMmO,EAAMpO,MAE7D,GAAKooC,EAAOiH,WAAYrlC,EAAU,SACjC,OAAOA,EAGR,IAAM,MAAM,aAAEwB,KAAkB4C,EAAMgL,UAAW,CAAErP,cAClD,GAAKq+B,EAAOiH,WAAY7jC,EAAc,SACrC,OAAOA,EC/HK,MAAM,WAAe,GAInC,wBACC,MAAO,SAMR,sBACC,MAAO,CAAE,IAMV,OACC,MAAMqJ,EAAO11B,KAAKuc,OAAO83D,QAAQ3+C,KAC3B6nC,EAAe7nC,EAAK10B,SAQ1BhB,KAAKo6G,oBAAsB,IAAI/hG,IAI/BrY,KAAKuc,OAAO83D,QAAQrgB,mBAAmB9qC,GAAI,YAAa,CAAEpS,EAAKnX,EAAMolD,KAEpE/kD,KAAKq6G,gCAAiCt1D,EAAc/yB,QAEpD,MAAMg8B,EAAajJ,EAAc/yB,OAC3BwI,EAAgBwzB,EAAWhtD,SAASopB,UACpCw+E,EAAkBpuE,EAAc9I,qBACtC,IAAI4oF,EAAa,KAEjB,IAAM,MAAMrrF,KAASuL,EAActK,YAClC,IAAM,MAAM1xB,KAASywB,EAAQ,CAC5B,MAAM1c,EAAO/T,EAAM6D,KAGdwlG,GAAUt1F,KAAWgoG,GAAShoG,EAAM+nG,KACxCtsD,EAAWrxB,SlCrDyB,qBkCqDapqB,GAEjDvS,KAAKo6G,oBAAoBxrG,IAAK2D,GAC9B+nG,EAAa/nG,EAGRA,GAAQq2F,GACZ56C,EAAWvzB,aAAcD,EAActK,YAAa,CAAEO,MAAM,EAAMC,MAAO83E,GAAUI,QAKrF,CAAEn4F,SAAU,QAGfilB,EAAKknB,YAAa,IAClB58C,KAAKmR,SAAUosD,EAAc,YAAa,IAAKlsD,IAAUrR,KAAKw6G,gBAAiBnpG,IAa/ErR,KAAKmR,SAAUosD,EAAc,UAAW,IAAKlsD,KAC5CrR,KAAKy6G,yCAA0CppG,IAC7C,CAAEZ,SAAU,SAEfzQ,KAAKmR,SAAUosD,EAAc,UAAW,IAAKlsD,KAC5CrR,KAAK06G,kCAAmCrpG,IACtC,CAAEZ,SAAU,GAAWrS,IAAK,QAAW,KAE1C4B,KAAKmR,SAAUosD,EAAc,UAAW+7C,GAA2Bt5G,KAAKuc,OAAO83D,UAG/Er0E,KAAKmR,SAAUosD,EAAc,SAAU,CAAEzmD,EAAKnX,KACxCK,KAAK26G,cAAiC,WAAlBh7G,EAAKirB,aAC7BjrB,EAAKi0C,iBACL98B,EAAIhH,SAEH,CAAEW,SAAU,SAUhB,aAAcuC,EAAW47E,GACxB,MAAMryE,EAASvc,KAAKuc,OACdmZ,EAAOnZ,EAAO83D,QAAQ3+C,KACtB6nC,EAAe7nC,EAAK10B,SAC1B,IAAI4d,EAAUgwE,EAAaxtF,OAG3B,GA0OF,SAAiCwd,GAChC,KAAQA,GAAU,CACjB,GAAKA,EAAQze,GAAI,qBAAwBye,EAAQze,GAAI,eACpD,OAAO,EAIR,GAAK0nG,GAAUjpF,GACd,OAAO,EAGRA,EAAUA,EAAQ7B,OAGnB,OAAO,EAxPD69F,CAAwBh8F,GAAY,CAIxC,IAAO,GAAIgU,UAAY,GAAID,UAAai8D,EAAal7C,SAASmnE,QAAU,EAAI,CAC3E,MAAMl3D,EAASpnC,EAAO83D,QAAQ1wB,OACxB7oB,EAAclc,EAAQze,GAAI,oBAC/Bye,EAAQglB,aAAchlB,IAAYA,EAAQze,GAAI,qBAAyBye,EAClEokC,EAAeW,EAAOV,eAAgBnoB,GAE5C8zD,EAAah7C,iBAEb5zC,KAAKuc,OAAOysC,MAAM5L,OAAQprB,IACzBA,EAAOyI,aAAcuoB,EAAc,QAIrC,OAID,IAAM6kD,GAAUjpF,KACfA,EAAUA,EAAQglB,aAAcikE,KAE1BjpF,GACL,OAIFgwE,EAAah7C,iBAGP2pB,EAAapzC,WAClBuL,EAAK7F,QAIN,MAAMmzB,EAAezmC,EAAO83D,QAAQ1wB,OAAOV,eAAgBrkC,GAE3D5e,KAAKq4G,yBAA0Br1D,GAgBhC,sCAAuChwC,EAAW47E,GACjD,MAAMr6D,EAAUq6D,EAAar6D,QAI7B,IAAMS,GAAgBT,GACrB,OAGD,MAAMy0B,EAAQhpD,KAAKuc,OAAOysC,MACpBC,EAASD,EAAMC,OACfoL,EAAiBrL,EAAMhoD,SAASopB,UAChC0wF,EAAgBzmD,EAAe3iC,qBAC/Bw9C,EAAY/5C,GAAuBZ,EAASv0B,KAAKuc,OAAON,OAAOT,0BAGrE,GAAKs/F,GAAiB7xD,EAAO6D,SAAUguD,GAAkB,CACxD,MAAMjwF,EAAWqkD,EAAY7a,EAAe5iC,kBAAoB4iC,EAAe7iC,mBACzEmJ,EAAWsuB,EAAO8D,yBAA0BliC,EAAUqkD,EAAY,UAAY,YAWpF,YATKv0C,IACJquB,EAAM5L,OAAQprB,IACbA,EAAOyI,aAAcE,KAGtBi0D,EAAah7C,iBACb5gC,EAAUlD,SAQZ,IAAMukD,EAAe5mC,YACpB,OAGD,MAAMstF,EAA+B/6G,KAAKo4G,iCAAkClpC,GAEvE6rC,GAAgC9xD,EAAO6D,SAAUiuD,KACrD/6G,KAAKq4G,yBAA0B0C,GAE/BnsB,EAAah7C,iBACb5gC,EAAUlD,QAeZ,+BAAgCkD,EAAW47E,GAK1C,IAAM55D,GAJU45D,EAAar6D,SAK5B,OAGD,MAAMy0B,EAAQhpD,KAAKuc,OAAOysC,MACpBC,EAASD,EAAMC,OACf6xD,EAAgB9xD,EAAMhoD,SAASopB,UAAUsH,qBAG1CopF,GAAiB7xD,EAAO6D,SAAUguD,KACtClsB,EAAah7C,iBACb5gC,EAAUlD,QAWZ,cAAeo/D,GAEd,GAAKlvE,KAAKuc,OAAO4gC,WAChB,OAGD,MACMkX,EADgBr0D,KAAKuc,OAAOysC,MAAMhoD,SACHopB,UAGrC,IAAMiqC,EAAe5mC,YACpB,OAGD,MAAMqtF,EAAgB96G,KAAKo4G,iCAAkClpC,GAE7D,OAAK4rC,GACJ96G,KAAKuc,OAAOysC,MAAM5L,OAAQprB,IACzB,IAAIgpF,EAAe3mD,EAAellC,OAAOpS,OAGzC,KAAQi+F,EAAav4F,SAAU,CAC9B,MAAMw4F,EAAeD,EACrBA,EAAeC,EAAal+F,OAE5BiV,EAAO7tB,OAAQ82G,GAGhBj7G,KAAKq4G,yBAA0ByC,MAGzB,QAfR,EAyBD,yBAA0Bl8F,GACzB5e,KAAKuc,OAAOysC,MAAM5L,OAAQprB,IACzBA,EAAOyI,aAAczI,EAAO+0B,cAAenoC,MAa7C,iCAAkCm5C,GACjC,MAAM/O,EAAQhpD,KAAKuc,OAAOysC,MACpBC,EAASD,EAAMC,OACfoL,EAAiBrL,EAAMhoD,SAASopB,UAIhC6uF,EAAQjwD,EAAMsL,gBAAiBD,GACrCrL,EAAMskB,gBAAiB2rC,EAAO,CAAEruF,UAAWmtC,EAAU,UAAY,aACjE,MAAM+iD,EAAgB/iD,EAAUkhD,EAAMppF,MAAMvC,WAAa2rF,EAAMppF,MAAMzC,UAErE,OAAO0tF,GAAiB7xD,EAAO6D,SAAUguD,GACjCA,EAGD,KASR,gCAAiC9oF,GAChC,IAAM,MAAMkpF,KAAUl7G,KAAKo6G,oBAC1BpoF,EAAO6K,YlClVgC,qBkCkVSq+E,GAGjDl7G,KAAKo6G,oBAAoB7wG,SA8B3B,SAASgxG,GAAS37F,EAAS7B,GAC1B,QAAMA,GAIC5T,MAAMiK,KAAMwL,EAAQpB,gBAAiBpE,SAAU2D,GCvYxC,MAAM,WAAoCswE,GAYxD,UACC,MAAMzuE,EAAU5e,KAAKuc,OAAOysC,MAAMhoD,SAASopB,UAAUsH,qBAErD1xB,KAAKsvC,UAAY,GAAS1wB,GAErB,GAASA,IAAaA,EAAQM,aAAc,OAChDlf,KAAKxB,MAAQogB,EAAQQ,aAAc,OAEnCpf,KAAKxB,OAAQ,EAWf,QAAS0D,GACR,MAAM8mD,EAAQhpD,KAAKuc,OAAOysC,MACpBqgD,EAAergD,EAAMhoD,SAASopB,UAAUsH,qBAE9Cs3B,EAAM5L,OAAQprB,IACbA,EAAOtuB,aAAc,MAAOxB,EAAQ8I,SAAUq+F,MClClC,MAAM,WAAoC,GAIxD,wBACC,MAAO,8BAMR,OACCrpG,KAAKuc,OAAO24C,SAAStmD,IAAK,uBAAwB,IAAI,GAA6B5O,KAAKuc,U,MCqB3E,MAAM,WAAyB,GAa7C,YAAaN,EAAQwzC,GACpB7vD,MAAOqc,GAEP,MAAMk/F,EAAU,yBAA0B,KACpCC,EAAY,gCAAiC,KAOnDp7G,KAAKq7G,UAAY5rD,EAAazvD,KAAMm7G,EAASC,GAQ7Cp7G,KAAKyJ,IAAK,SAQVzJ,KAAKyJ,IAAK,aAAa,GAUvBzJ,KAAKyJ,IAAK,WAAW,GAWrBzJ,KAAKyJ,IAAK,aAAa,GAavBzJ,KAAKyJ,IAAK,YAAa,MAgBvBzJ,KAAKyJ,IAAK,WAAY,MAQtBzJ,KAAKyJ,IAAK,SAQVzJ,KAAKyJ,IAAK,eAOVzJ,KAAK0lF,UAAY1lF,KAAK2lF,iBAAkBw1B,GAQxCn7G,KAAKs7G,WAAat7G,KAAKu7G,kBAAmBH,GAc1Cp7G,KAAKjB,KAAM,eAAgB6U,GAC1B5T,KAAM,YACNA,KAAM,WACN,CAAEw7G,EAAWC,IAAcD,GAAaC,GAGzC,MAAM18G,EAAOiB,KAAKq+E,aAElBr+E,KAAKs+E,YAAa,CACjBl2E,IAAK,MACL9E,WAAY,CACXy6E,MAAO,CACN,KACA,wBACAh/E,EAAK6U,GAAI,SACT7U,EAAKi7E,GAAI,YAAa,cAAex7E,IAAUA,GAC/CO,EAAKi7E,GAAI,UAAW,+BACpBj7E,EAAKi7E,GAAI,YAAa,iCACtBj7E,EAAKi7E,GAAI,cAAe,qCACxBj7E,EAAKi7E,GAAI,YAAa,cAGxBlyE,SAAU,CACT,CACCM,IAAK,MACL9E,WAAY,CACXy6E,MAAO,CACN,KACA,yCAGFj2E,SAAU,CACT9H,KAAKq7G,UACLr7G,KAAK0lF,YAGP1lF,KAAKs7G,cAYR,iBAAkBh5G,GACjB,MAAMojF,EAAY,IAAI,GAAW1lF,KAAKic,QAKtC,OAHAypE,EAAUrmB,IAAM/8D,EAChBojF,EAAU3mF,KAAM,QAAS6U,GAAI5T,KAAM,SAE5B0lF,EAYR,kBAAmB01B,GAClB,MAAME,EAAa,IAAI,GAAMt7G,KAAKic,QAC5Bld,EAAOiB,KAAKq+E,aAqBlB,OAnBAi9B,EAAWh9B,YAAa,CACvBl2E,IAAK,MACL9E,WAAY,CACXy6E,MAAO,CACN,KACA,gCACAh/E,EAAKi7E,GAAI,YAAa,uCACtBj7E,EAAKi7E,GAAI,cAAe,YAAax7E,IAAUA,IAEhD8D,GAAI84G,EACJ38B,KAAM1/E,EAAKi7E,GAAI,YAAa,UAE7BlyE,SAAU,CACT,CACCyqC,KAAMxzC,EAAK6U,GAAI,mBAKX0nG,EAMR,QACCt7G,KAAKq7G,UAAUxrF,S,MCzQF,MAAM,WAAsB,GAI1C,YAAa5T,GACZrc,MAAOqc,GAQPjc,KAAKyJ,IAAK,SAQVzJ,KAAKyJ,IAAK,MAQVzJ,KAAKyJ,IAAK,eAQVzJ,KAAKyJ,IAAK,cAAc,GASxBzJ,KAAKyJ,IAAK,YAAY,GAStBzJ,KAAKyJ,IAAK,qBASVzJ,KAAKk2E,aAAe,IAAI,GAWxBl2E,KAAKjB,KAAM,aAAc6U,GAAI5T,KAAKk2E,cAWlCl2E,KAAKyJ,IAAK,WAAW,GAErB,MAAM1K,EAAOiB,KAAKq+E,aAElBr+E,KAAKs+E,YAAa,CACjBl2E,IAAK,QACL9E,WAAY,CACXrD,KAAM,OACN89E,MAAO,CACN,KACA,WACA,gBACAh/E,EAAKi7E,GAAI,YAAa,oBACtBj7E,EAAKi7E,GAAI,UAAW,uBACpBj7E,EAAKi7E,GAAI,WAAY,aAEtB13E,GAAIvD,EAAK6U,GAAI,MACb8nG,YAAa38G,EAAK6U,GAAI,eACtB+nG,SAAU58G,EAAK6U,GAAI,cACnB,eAAgB7U,EAAKi7E,GAAI,YAAY,GACrC,mBAAoBj7E,EAAK6U,GAAI,sBAE9BsV,GAAI,CACHhc,MAAOnO,EAAK6U,GAAI,SAChBwpC,OAAQr+C,EAAK6U,GAAI5T,KAAK47G,eAAe78G,KAAMiB,UAe9C,SACCJ,MAAM43B,SAENx3B,KAAKk2E,aAAatnE,IAAK5O,KAAK4e,SAE5B5e,KAAK67G,oBAAqB77G,KAAKxB,OAC/BwB,KAAK47G,iBAIL57G,KAAKkpB,GAAI,eAAgB,CAAEpS,EAAKhZ,EAAMU,KACrCwB,KAAK67G,oBAAqBr9G,GAC1BwB,KAAK47G,mBAOP,SACC57G,KAAK4e,QAAQk9F,SAMd,QACC97G,KAAK4e,QAAQiR,QAQd,iBACC7vB,KAAKyiB,SAA+BziB,KAAK4e,QAcvBpgB,MANnB,oBAAqBA,GACpBwB,KAAK4e,QAAQpgB,MAAWA,GAAmB,IAAVA,EAAqBA,EAAL,ICvJ5C,SAASu9G,GAAwBC,EAAkBb,EAASC,GAClE,MAAMa,EAAY,IAAI,GAAeD,EAAiB//F,QAkBtD,OAhBAggG,EAAUxyG,IAAK,CACdnH,GAAI64G,EACJe,kBAAmBd,IAGpBa,EAAUl9G,KAAM,cAAe6U,GAAIooG,EAAkB,YAAax9G,IAAUA,GAC5Ey9G,EAAUl9G,KAAM,YAAa6U,GAAIooG,EAAkB,YAAax9G,KAAWA,GAE3Ey9G,EAAU/yF,GAAI,QAAS,KAGtB8yF,EAAiBR,UAAY,OAG9BQ,EAAiBj9G,KAAM,UAAW,YAAa,eAAgB6U,GAAIqoG,GAE5DA,ECHO,SAASE,GAA6BzmF,GACpDA,EAAKjsB,IAAK,6BAA6B,GAEvCisB,EAAK0mF,sBAAwB,KAC5B1mF,EAAK2mF,2BAA4B,GAGlC3mF,EAAK4mF,qBAAuB,KAC3B5mF,EAAK2mF,2BAA4B,GAGlC3mF,EAAK0kD,eAAgB,CACpB92E,WAAY,CACXy6E,MAAO,CACNroD,EAAK2oD,aAAarE,GAAI,4BAA6B,+BCvBxC,SAASuiC,IAAe,KAAE7mF,IACxCA,EAAKvkB,SAAUukB,EAAK9W,QAAS,SAAU,CAAE9H,EAAKq4B,KAC7CA,EAAOyE,iBACPle,EAAKrhB,KAAM,WACT,CAAEu6B,YAAY,IChDH,qPCAA,2R,WCiCA,MAAM,WAAgC,GAIpD,YAAa3yB,GACZrc,MAAOqc,GAEP,MAAMxd,EAAIuB,KAAKic,OAAOxd,EAQtBuB,KAAKk2E,aAAe,IAAI,GAQxBl2E,KAAKw0E,WAAa,IAAI,GAOtBx0E,KAAKw8G,aAAex8G,KAAKy8G,0BAOzBz8G,KAAK08G,eAAiB18G,KAAK28G,cAAel+G,EAAG,QAAUm+G,GAAW,kBAClE58G,KAAK08G,eAAez8G,KAAO,SAO3BD,KAAK68G,iBAAmB78G,KAAK28G,cAAel+G,EAAG,UAAY,GAAY,mBAAoB,UAS3FuB,KAAK88G,YAAc,IAAI,GASvB98G,KAAKymF,aAAe,IAAIxG,GAAa,CACpCE,WAAYngF,KAAK88G,YACjB5mC,aAAcl2E,KAAKk2E,aACnBgK,iBAAkBlgF,KAAKw0E,WACvB5xC,QAAS,CAER8jD,cAAe,cAGfC,UAAW,SAIb3mF,KAAKs+E,YAAa,CACjBl2E,IAAK,OAEL9E,WAAY,CACXy6E,MAAO,CACN,KACA,2BACA,sBAIDiI,SAAU,MAGXl+E,SAAU,CACT9H,KAAKw8G,aACLx8G,KAAK08G,eACL18G,KAAK68G,oBAIPV,GAA6Bn8G,MAM9B,SACCJ,MAAM43B,SAENx3B,KAAKw0E,WAAWrjE,SAAUnR,KAAK4e,SAE/B29F,GAAe,CAAE7mF,KAAM11B,OAEvB,CAAEA,KAAKw8G,aAAcx8G,KAAK08G,eAAgB18G,KAAK68G,kBAC7Cp5G,QAASs5G,IAET/8G,KAAK88G,YAAYluG,IAAKmuG,GAGtB/8G,KAAKk2E,aAAatnE,IAAKmuG,EAAEn+F,WAc5B,cAAe8R,EAAO01D,EAAMhgE,EAAWrU,GACtC,MAAM8xF,EAAS,IAAI,GAAY7jG,KAAKic,QAkBpC,OAhBA4nF,EAAOp6F,IAAK,CACXinB,QACA01D,OACAE,SAAS,IAGVud,EAAOzpB,eAAgB,CACtB92E,WAAY,CACXy6E,MAAO33D,KAIJrU,GACJ8xF,EAAOtyE,SAAU,WAAY3d,GAAI5T,KAAM+R,GAGjC8xF,EASR,0BACC,MAAMplG,EAAIuB,KAAKic,OAAOxd,EAChB+9G,EAAe,IAAI,GAAkBx8G,KAAKic,OAAQ8/F,IAIxD,OAFAS,EAAa9rF,MAAQjyB,EAAG,oBAEjB+9G,G,YC7KT,MAAM,GAAOv9B,GAAQ,MAsCN,MAAM,WAA0B,GAI9C,wBACC,MAAO,oBAMR,YAAa1iE,GACZ3c,MAAO2c,GAaPvc,KAAKg9G,gBAAkB,KACtB,MAAMtnF,EAAO11B,KAAKuc,OAAO83D,QAAQ3+C,KAE3BrL,EADeqL,EAAK10B,SACWopB,UAAUC,gBAE/C,OAAKA,EACGqL,EAAKC,aAAa6L,aAAcnX,EAAgBxtB,MAGjD,MAURmD,KAAKyJ,IAAK,cAAe,MAQzBzJ,KAAK01B,KAAO,IAAI,GAAkBnZ,EAAON,QACzCM,EAAOL,GAAGwZ,KAAK2kB,KAAKzrC,IAAK5O,KAAK01B,MAC9BnZ,EAAOL,GAAGg6D,aAAatnE,IAAK5O,KAAK01B,KAAK9W,SAQtC5e,KAAKi9G,aAAe,IAAInpG,IAQxB9T,KAAKk9G,WAAa,IAAIppG,IAUtB9T,KAAKyJ,IAAK,kBAAmB,GAU7BzJ,KAAKyJ,IAAK,mBAAmB,GAS7BzJ,KAAKm9G,aAAen9G,KAAKo9G,qBAQzBp9G,KAAKq9G,gBAAkBr9G,KAAKs9G,wBAS7B,QAAS5nF,GACR,OAAOvsB,MAAMiK,KAAMpT,KAAKi9G,aAAaz5G,QAAS4V,SAAUsc,GAezD,IAAK/1B,GACJ,GAAKK,KAAKu9G,QAAS59G,EAAK+1B,MAMvB,MAAM,IAAI,KACT,mCACA,CAAE11B,KAAML,IAIV,MAAM69G,EAAU79G,EAAK69G,SAAW,OAGhC,IAAMx9G,KAAKk9G,WAAWxzG,IAAK8zG,GAS1B,OARAx9G,KAAKk9G,WAAWzzG,IAAK+zG,EAAS,IAAI1pG,IAAK,CAAE,CAAEnU,EAAK+1B,KAAM/1B,MACtDK,KAAKi9G,aAAaxzG,IAAK9J,EAAK+1B,KAAM11B,KAAKk9G,WAAW9+G,IAAKo/G,IACvDx9G,KAAKy9G,gBAAkBz9G,KAAKk9G,WAAWl0G,UAEjChJ,KAAK09G,gBAAiB/9G,EAAKg+G,gBAChC39G,KAAK49G,UAAWJ,IAMlB,MAAMl9G,EAAQN,KAAKk9G,WAAW9+G,IAAKo/G,GAE9B79G,EAAKg+G,gBACT39G,KAAK49G,UAAWJ,GAIjBl9G,EAAMmJ,IAAK9J,EAAK+1B,KAAM/1B,GACtBK,KAAKi9G,aAAaxzG,IAAK9J,EAAK+1B,KAAMp1B,GAG7BA,IAAUN,KAAK09G,eACnB19G,KAAK69G,UAAWl+G,GAYlB,OAAQ+1B,GACP,IAAM11B,KAAKu9G,QAAS7nF,GAMnB,MAAM,IAAI,KACT,0CACA,CAAE11B,KAAM01B,IAIV,MAAMp1B,EAAQN,KAAKi9G,aAAa7+G,IAAKs3B,GAEhC11B,KAAK89G,iBAAmB99G,KAAK+9G,cAAgBroF,IACjD11B,KAAK89G,iBAAkB,GAKnB99G,KAAK+9G,cAAgBroF,IACL,IAAfp1B,EAAM0I,KACLhJ,KAAKk9G,WAAWl0G,KAAO,EAC3BhJ,KAAKg+G,kBAELh+G,KAAK01B,KAAKmwE,OACV7lG,KAAK+9G,YAAc,KACnB/9G,KAAKm9G,aAAac,YAGnBj+G,KAAK69G,UAAW10G,MAAMiK,KAAM9S,EAAM+L,UAAY/L,EAAM0I,KAAO,KAIzC,IAAf1I,EAAM0I,MACVhJ,KAAKk9G,WAAWnpG,OAAQ/T,KAAKk+G,YAAa59G,IAC1CN,KAAKy9G,gBAAkBz9G,KAAKk9G,WAAWl0G,MAEvC1I,EAAMyT,OAAQ2hB,GAGf11B,KAAKi9G,aAAalpG,OAAQ2hB,GAS3B,eAAgB7K,GACVA,IACJ7qB,KAAK09G,cAAct/G,IAAK4B,KAAK+9G,aAAclzF,SAAWA,GAGvD7qB,KAAK01B,KAAKyoF,IAAKn+G,KAAKo+G,uBACpBp+G,KAAKq9G,gBAAgBgB,iBAQtB,UAAW/7G,GACVtC,KAAKs+G,aAAeh8G,EACpB,MAAMhC,EAAQN,KAAKk9G,WAAW9+G,IAAKkE,GAEnC,IAAMhC,EAML,MAAM,IAAI,KACT,8CACAN,MAIGA,KAAK09G,gBAAkBp9G,GAI5BN,KAAK69G,UAAW10G,MAAMiK,KAAM9S,EAAM+L,UAAWjD,OAS9C,oBACC,OAAOpJ,KAAKi9G,aAAa7+G,IAAK4B,KAAK+9G,aAUpC,YAAaz9G,GAGZ,OAFc6I,MAAMiK,KAAMpT,KAAKk9G,WAAW5zG,WAAY8M,KAAM5M,GAASA,EAAO,KAAQlJ,GAEtE,GAQf,iBACC,MAAMi+G,EAASp1G,MAAMiK,KAAMpT,KAAKk9G,WAAW7wG,UAE3C,IAAImyG,EAAYD,EAAOzrG,QAAS9S,KAAK09G,eAAkB,EAEjDa,EAAQC,KACbA,EAAY,GAGbx+G,KAAK49G,UAAW59G,KAAKk+G,YAAaK,EAAQC,KAQ3C,iBACC,MAAMD,EAASp1G,MAAMiK,KAAMpT,KAAKk9G,WAAW7wG,UAE3C,IAAImyG,EAAYD,EAAOzrG,QAAS9S,KAAK09G,eAAkB,EAEjDa,EAAQC,KACbA,EAAYD,EAAOx8G,OAAS,GAG7B/B,KAAK49G,UAAW59G,KAAKk+G,YAAaK,EAAQC,KAS3C,qBACC,MAAM9oF,EAAO,IAAI,GAAa11B,KAAKuc,OAAON,QACpCxd,EAAIuB,KAAKuc,OAAON,OAAOxd,EA2C7B,OAzCAuB,KAAK01B,KAAKxuB,QAAQ0H,IAAK8mB,GAGvBA,EAAK32B,KAAM,uBAAwB6U,GAAI5T,KAAM,kBAAmBA,KAAM,kBAAmB,CAAExB,EAAOigH,KACzFA,GAAoBjgH,EAAQ,GAIrCk3B,EAAKxM,GAAI,6BAA8B,IAAQlpB,KAAKq+G,iBAAoB,CAAE5tG,SAAU,QAGpFilB,EAAK32B,KAAM,WAAY6U,GAAI5T,KAAM,cAAeA,KAAM,kBAAmB,CAAE+9G,EAAaW,KACvF,GAAKA,EAAiB,EACrB,MAAO,GAGR,MAAMxkF,EAAU/wB,MAAMiK,KAAMpT,KAAKk9G,WAAW7wG,UAAWyG,QAAS9S,KAAK09G,eAAkB,EAEvF,OAAOj/G,EAAG,WAAY,CAAEy7B,EAASwkF,MAGlChpF,EAAKipF,eAAez1F,GAAI,UAAW,KAG7BwM,EAAKwgD,aAAa/rD,WACtBnqB,KAAKuc,OAAO83D,QAAQ3+C,KAAK7F,QAG1B7vB,KAAKg+G,mBAGNtoF,EAAKkpF,eAAe11F,GAAI,UAAW,KAG7BwM,EAAKwgD,aAAa/rD,WACtBnqB,KAAKuc,OAAO83D,QAAQ3+C,KAAK7F,QAG1B7vB,KAAK6+G,mBAGCnpF,EAOR,wBACC,MAAMA,EAAO,IAAI,GAAgB11B,KAAKuc,OAAON,OAAQjc,KAAK01B,MAa1D,OAXAA,EAAK32B,KAAM,kBAAmB6U,GAAI5T,KAAM,kBAAmBA,KAAM,kBAAmB,CAAEwgB,EAAQi+F,KACzEA,GAAoBj+F,GAAU,EAE9BpQ,KAAK0M,IAAK0D,EAAS,EAAG,GAAM,GAGjDkV,EAAKvkB,SAAUnR,KAAK01B,KAAM,aAAc,IAAMA,EAAK2oF,kBACnD3oF,EAAKvkB,SAAUnR,KAAK01B,KAAM,cAAe,IAAMA,EAAK2oF,kBAEpDr+G,KAAKuc,OAAOL,GAAGwZ,KAAK2kB,KAAKzrC,IAAK8mB,GAEvBA,EAaR,WAAW,KAAEA,EAAI,iBAAEopF,EAAmB,GAAE,UAAEC,GAAY,EAAI,eAAEpB,GAAiB,IAC5E39G,KAAK01B,KAAKqoD,MAAQ+gC,EAClB9+G,KAAK01B,KAAKqpF,UAAYA,EAEtB/+G,KAAKm9G,aAAa6B,SAAUtpF,GAC5B11B,KAAK+9G,YAAcroF,EACnB11B,KAAK01B,KAAKyoF,IAAKn+G,KAAKo+G,uBACpBp+G,KAAKq9G,gBAAgBgB,iBAEhBV,IACJ39G,KAAK89G,iBAAkB,GAWzB,sBACC,IAAIjzF,EAAW1hB,MAAMiK,KAAMpT,KAAK09G,cAAcrxG,UAAWjD,MAAMyhB,SAU/D,OAPKA,IAAaA,EAASs3D,UAE1Bt3D,EAAW5sB,OAAO4nC,OAAQ,GAAIhb,EAAU,CACvCs3D,QAASniF,KAAKg9G,mBAITnyF,GAWT,MAAM,WAAoB,GAIzB,YAAa5O,GACZrc,MAAOqc,GAEP,MAAMxd,EAAIwd,EAAOxd,EACXM,EAAOiB,KAAKq+E,aAOlBr+E,KAAKyJ,IAAK,uBAAuB,GAOjCzJ,KAAKk2E,aAAe,IAAI,GAOxBl2E,KAAK4+G,eAAiB5+G,KAAKi/G,kBAAmBxgH,EAAG,YCpiBpC,0ND2iBbuB,KAAK2+G,eAAiB3+G,KAAKi/G,kBAAmBxgH,EAAG,QE3iBpC,4NFmjBbuB,KAAKkH,QAAUlH,KAAKw9E,mBAEpBx9E,KAAKs+E,YAAa,CACjBl2E,IAAK,MACL9E,WAAY,CACXy6E,MAAO,CACN,KACA,sBAED,UAAW,MAEZj2E,SAAU,CACT,CACCM,IAAK,MACL9E,WAAY,CACXy6E,MAAO,CACN,iCACAh/E,EAAK6U,GAAI,sBAAuBpV,GAASA,EAAQ,GAAK,eAGxDsJ,SAAU,CACT9H,KAAK4+G,eACL,CACCx2G,IAAK,OAEL9E,WAAY,CACXy6E,MAAO,CACN,gCAIFj2E,SAAU,CACT,CACCyqC,KAAMxzC,EAAK6U,GAAI,cAIlB5T,KAAK2+G,iBAGP,CACCv2G,IAAK,MACL9E,WAAY,CACXy6E,MAAO,+BAERj2E,SAAU9H,KAAKkH,YASnB,SACCtH,MAAM43B,SAENx3B,KAAKk2E,aAAatnE,IAAK5O,KAAK4e,SAQ7B,SAAU8W,GACT11B,KAAKi+G,WACLj+G,KAAKkH,QAAQ0H,IAAK8mB,GAMnB,WACC11B,KAAKkH,QAAQqC,QAWd,kBAAmBmnB,EAAO01D,GACzB,MAAM1wD,EAAO,IAAI,GAAY11B,KAAKic,QAQlC,OANAyZ,EAAKjsB,IAAK,CACTinB,QACA01D,OACAE,SAAS,IAGH5wD,GAQT,MAAM,WAAuB,GAE5B,YAAazZ,EAAQijG,GACpBt/G,MAAOqc,GAEP,MAAMld,EAAOiB,KAAKq+E,aAMlBr+E,KAAKyJ,IAAK,MAAO,GAMjBzJ,KAAKyJ,IAAK,OAAQ,GAMlBzJ,KAAKyJ,IAAK,SAAU,GAMpBzJ,KAAKyJ,IAAK,QAAS,GAMnBzJ,KAAKyJ,IAAK,iBAAkB,GAM5BzJ,KAAKkH,QAAUlH,KAAKw9E,mBAMpBx9E,KAAKm/G,kBAAoBD,EAEzBl/G,KAAKs+E,YAAa,CACjBl2E,IAAK,MACL9E,WAAY,CACXy6E,MAAO,CACN,gBACAh/E,EAAK6U,GAAI,iBAAkB4M,GAAUA,EAAS,GAAK,cAEpDpd,MAAO,CACN0iC,IAAK/mC,EAAK6U,GAAI,MAAO,IACrBmyB,KAAMhnC,EAAK6U,GAAI,OAAQ,IACvBoyB,MAAOjnC,EAAK6U,GAAI,QAAS,IACzB8kC,OAAQ35C,EAAK6U,GAAI,SAAU,MAG7B9L,SAAU9H,KAAKkH,UAGhBlH,KAAKkpB,GAAI,wBAAyB,CAAEpS,EAAKhZ,EAAMytB,EAAMuN,KAC/CvN,EAAOuN,EACX94B,KAAKo/G,WAAY7zF,EAAOuN,GAExB94B,KAAKq/G,cAAevmF,EAAOvN,GAG5BvrB,KAAKq+G,mBAMP,WAAY79F,GACX,KAAQA,KAAW,CAClB,MAAMkV,EAAO,IAAI,GAEjBA,EAAK4oD,YAAa,CAAEl2E,IAAK,QAEzBpI,KAAKkH,QAAQ0H,IAAK8mB,GAClB11B,KAAK49E,cAAeloD,IAMtB,cAAelV,GACd,KAAQA,KAAW,CAClB,MAAMkV,EAAO11B,KAAKkH,QAAQmoB,KAE1BrvB,KAAKkH,QAAQ/C,OAAQuxB,GACrB11B,KAAKs/G,gBAAiB5pF,GACtBA,EAAKxb,WAKP,iBACC,GAAKla,KAAKu/G,eAAiB,CAC1B,MAAM,IAAEz5E,EAAG,KAAEC,GAAS/lC,KAAKm/G,mBACrB,MAAEn5E,EAAK,OAAE0S,GAAW,IAAI,GAAM14C,KAAKm/G,kBAAkBvgG,SAE3D3gB,OAAO4nC,OAAQ7lC,KAAM,CAAE8lC,MAAKC,OAAMC,QAAO0S,aGhuBrC,SAAS8mE,GAAwBjjG,GACvC,MAAMk7D,EAAcl7D,EAAO83D,QAAQ3+C,KAC7BkvE,EAAmB,GAAiBA,iBAE1C,MAAO,CACNxjG,OAAQq2E,EAAY9hD,aAAasO,UAAWwzC,EAAYz2E,SAASopB,UAAUsH,sBAC3EwwD,UAAW,CACV0iB,EAAiBO,gBACjBP,EAAiBU,oBACjBV,EAAiBW,oBACjBX,EAAiBE,gBACjBF,EAAiBK,oBACjBL,EAAiBM,sBCxBL,MAAM,WAA+B,GAInD,sBACC,MAAO,CAAE,IAMV,wBACC,MAAO,yBAMR,OACCllG,KAAK28G,gBACL38G,KAAKy/G,cAMN,UACC7/G,MAAMsa,UAGNla,KAAK0/G,MAAMxlG,UASZ,gBACC,MAAMqC,EAASvc,KAAKuc,OACd9d,EAAI8d,EAAO9d,EAEjB8d,EAAOL,GAAG+5D,iBAAiBrnE,IAAK,uBAAwBqN,IACvD,MAAM+4C,EAAUz4C,EAAO24C,SAAS92D,IAAK,wBAC/Bs3B,EAAO,IAAI,GAAYzZ,GAc7B,OAZAyZ,EAAKjsB,IAAK,CACTinB,MAAOjyB,EAAG,iCACV2nF,KC1EW,8lDD2EXE,SAAS,IAGV5wD,EAAK32B,KAAM,aAAc6U,GAAIohD,EAAS,aAEtCh1D,KAAKmR,SAAUukB,EAAM,UAAW,KAC/B11B,KAAK2/G,cAGCjqF,IAUT,cACC,MAAMnZ,EAASvc,KAAKuc,OAEdghD,EADOhhD,EAAO83D,QAAQ3+C,KACF10B,SAQ1BhB,KAAK4/G,SAAW5/G,KAAKuc,OAAOtE,QAAQ7Z,IAAK,qBAOzC4B,KAAK0/G,MAAQ,IAAI,GAAyBnjG,EAAON,QAGjDjc,KAAK0/G,MAAMloF,SAEXx3B,KAAKmR,SAAUnR,KAAK0/G,MAAO,SAAU,KACpCnjG,EAAO04C,QAAS,uBAAwB,CACvCjqD,SAAUhL,KAAK0/G,MAAMlD,aAAanB,UAAUz8F,QAAQpgB,QAGrDwB,KAAK6/G,WAAW,KAGjB7/G,KAAKmR,SAAUnR,KAAK0/G,MAAO,SAAU,KACpC1/G,KAAK6/G,WAAW,KAIjB7/G,KAAK0/G,MAAMlrC,WAAW/qE,IAAK,MAAO,CAAE9J,EAAMu2C,KACzCl2C,KAAK6/G,WAAW,GAChB3pE,MAIDl2C,KAAKmR,SAAUoL,EAAOL,GAAI,SAAU,KAC7BgtF,GAAwB3rC,EAAanzC,WAE/BpqB,KAAK8/G,YDxHb,SAAsCvjG,GAC5C,MAAMwjG,EAAUxjG,EAAOtE,QAAQ7Z,IAAK,qBAEpC,GAAK8qG,GAAwB3sF,EAAO83D,QAAQ3+C,KAAK10B,SAASopB,WAAc,CACvE,MAAMS,EAAW20F,GAAwBjjG,GAEzCwjG,EAAQ1B,eAAgBxzF,ICmHtBm1F,CAA6BzjG,GAF7Bvc,KAAK6/G,WAAW,KAOlB94B,GAAqB,CACpBx1E,QAASvR,KAAK0/G,MACd14B,UAAW,IAAMhnF,KAAK8/G,WACtB74B,gBAAiB,CAAEjnF,KAAK4/G,SAASlqF,KAAK9W,SACtC1N,SAAU,IAAMlR,KAAK6/G,cASvB,YACC,GAAK7/G,KAAK8/G,WACT,OAGD,MAAMvjG,EAASvc,KAAKuc,OACdy4C,EAAUz4C,EAAO24C,SAAS92D,IAAK,wBAC/Bo+G,EAAex8G,KAAK0/G,MAAMlD,aAEhCx8G,KAAK0/G,MAAMtD,wBAELp8G,KAAKigH,cACVjgH,KAAK4/G,SAAShxG,IAAK,CAClB8mB,KAAM11B,KAAK0/G,MACX70F,SAAU20F,GAAwBjjG,KASpCigG,EAAanB,UAAU78G,MAAQg+G,EAAanB,UAAUz8F,QAAQpgB,MAAQw2D,EAAQx2D,OAAS,GAEvFwB,KAAK0/G,MAAMlD,aAAanB,UAAUS,SAElC97G,KAAK0/G,MAAMpD,uBASZ,UAAW4D,GACJlgH,KAAKigH,eAMNjgH,KAAK0/G,MAAMxpC,aAAa/rD,WAC5BnqB,KAAK0/G,MAAMhD,eAAe7sF,QAG3B7vB,KAAK4/G,SAASz7G,OAAQnE,KAAK0/G,OAEtBQ,GACJlgH,KAAKuc,OAAO83D,QAAQ3+C,KAAK7F,SAU3B,iBACC,OAAO7vB,KAAK4/G,SAAS7B,cAAgB/9G,KAAK0/G,MAS3C,mBACC,OAAO1/G,KAAK4/G,SAASrC,QAASv9G,KAAK0/G,QE7MtB,MAAM,WAA6B,GAIjD,sBACC,MAAO,CAAE,GAA6B,IAMvC,wBACC,MAAO,wB,MCLM,MAAM,WAAc,GAIlC,sBACC,MAAO,CAAE,GAAc,GAAQ,IAMhC,wBACC,MAAO,SCJM,MAAM,WAA6B,GAIjD,YAAazjG,GACZrc,MAAOqc,GAOPjc,KAAKokF,WAAa,IAAI,GAAYnoE,GAQlCjc,KAAKmgH,eAAiB,IAAI,GAAelkG,GAWzCjc,KAAKmgH,eAAephH,KAAM,gBAAiB6U,GAAI5T,MAQ/CA,KAAKmgH,eAAephH,KAAM,sBAAuB6U,GAAI5T,MAcrDA,KAAKmgH,eAAe5uF,SAAU,QAAS3d,GAAI5T,MAE3CA,KAAKs+E,YAAa,CACjBl2E,IAAK,OACL9E,WAAY,CACXy6E,MAAO,yBAERj2E,SAAU,CACT9H,KAAKokF,WACLpkF,KAAKmgH,kBAIPngH,KAAKokF,WAAWl7D,GAAI,UAAW,KAC9BlpB,KAAKmgH,eAAehgB,SAOtB,QACCngG,KAAKokF,WAAWv0D,SAUlB,MAAM,WAAsB,GAI3B,YAAa5T,GACZrc,MAAOqc,GAWPjc,KAAKyJ,IAAK,gBAQVzJ,KAAKyJ,IAAK,sBAAsB,GAEhC,MAAM1K,EAAOiB,KAAKq+E,aAElBr+E,KAAKs+E,YAAa,CACjBl2E,IAAK,QAEL9E,WAAY,CACXy6E,MAAO,CACN,aAED99E,KAAM,OACN+lF,SAAU,KACVo6B,OAAQrhH,EAAK6U,GAAI,gBACjBysG,SAAUthH,EAAK6U,GAAI,uBAGpBsV,GAAI,CAEHk0B,OAAQr+C,EAAK6U,GAA+B,KACtC5T,KAAK4e,SAAW5e,KAAK4e,QAAQssE,OAASlrF,KAAK4e,QAAQssE,MAAMnpF,QAC7D/B,KAAKqU,KAAM,OAAQrU,KAAK4e,QAAQssE,OAGjClrF,KAAK4e,QAAQpgB,MAAQ,QASzB,OACCwB,KAAK4e,QAAQunE,SCjKR,SAASm6B,GAAuB35G,GAEtC,MAAM45G,EAAkB55G,EAAM0D,IAAKpK,GAAQA,EAAKiK,QAAS,IAAK,QAE9D,OAAO,IAAID,OAAQ,aAAcs2G,EAAgBt8G,KAAM,UCDzC,MAAM,WAAsB,GAI1C,wBACC,MAAO,gBAMR,OACC,MAAMsY,EAASvc,KAAKuc,OACd9d,EAAI8d,EAAO9d,EAGjB8d,EAAOL,GAAG+5D,iBAAiBrnE,IAAK,cAAeqN,IAC9C,MAAMyZ,EAAO,IAAI,GAAsBzZ,GACjC+4C,EAAUz4C,EAAO24C,SAAS92D,IAAK,eAC/BoiH,EAAajkG,EAAOV,OAAOzd,IAAK,sBAChCqiH,EAAmBH,GAAuBE,GAuBhD,OArBA9qF,EAAKjsB,IAAK,CACTi3G,aAAcF,EAAWn2G,IAAKpK,GAAQ,SAAUA,GAAUgE,KAAM,KAChE08G,oBAAoB,IAGrBjrF,EAAK0uD,WAAW36E,IAAK,CACpBinB,MAAOjyB,EAAG,gBACV2nF,KCrDW,2XDsDXE,SAAS,IAGV5wD,EAAK0uD,WAAWrlF,KAAM,aAAc6U,GAAIohD,GAExCt/B,EAAKxM,GAAI,OAAQ,CAAEpS,EAAKo0E,KACvB,MAAM01B,EAAiBz3G,MAAMiK,KAAM83E,GAAQlnF,OAAQ+4F,GAAQ0jB,EAAiBt2G,KAAM4yF,EAAK98F,OAElF2gH,EAAe7+G,QACnBwa,EAAO04C,QAAS,cAAe,CAAE8nC,KAAM6jB,MAIlClrF,K,kBEzCK,MAAM,WAA4B,GAIhD,YAAanZ,GACZ3c,MAAO2c,GAQPvc,KAAK07G,YAAc,2BAA6B32G,mBCvCnC,sFD6Cd,OACgB/E,KAAKuc,OAGb83D,QAAQrgB,mBAAmB9qC,GAAI,+BAAgC,IAAK7X,IAAUrR,KAAK6gH,sBAAuBxvG,IAUlH,mBAAoByF,EAAKnX,EAAMolD,GAC9B,MAAMxoC,EAASvc,KAAKuc,OACdkuF,EAAa9qG,EAAK0C,KAClBy+G,EAAWrW,EAAWrrF,aAAc,YAE1C,IAAM2lC,EAAcqB,WAAWkH,QAAS3tD,EAAK0C,KAAMyU,EAAIhZ,MACtD,OAGD,MAAMijH,EAAiBxkG,EAAOtE,QAAQ7Z,IAAK,IACrCwgG,EAASkiB,EAAWnhH,EAAKmmD,kBAAoB,KAC7C41D,EAAc17G,KAAK07G,YACnBtP,EAAa7vF,EAAO83D,QAAQ1wB,OAAOR,cAAesnD,GAClDz8C,EAAajJ,EAAc/yB,OAEjC,GAAe,WAAV4sE,EAMJ,OAHAoiB,GAAoB5U,EAAYp+C,QAChCizD,GAAkBvF,EAAatP,EAAYp+C,GAM5C,GAAe,aAAV4wC,EAAwB,CAC5B,MAAMf,EAASkjB,EAAezjB,QAAQl/F,IAAK0iH,GAiB3C,OAdAE,GAAoB5U,EAAYp+C,QAE1B6vC,GAOLqjB,GAAkB9U,EAAYp+C,GA6ElC,SAA2Bo+C,EAAYp6E,EAAQ6rE,EAAQnoE,GACtD,MAAMyrF,EAuCP,SAA6BnvF,GAC5B,MAAMmvF,EAAcnvF,EAAOm+B,gBAAiB,MAAO,CAAE4tB,MAAO,oBAI5D,OAFA/rD,EAAOg2E,kBAAmB,eAAe,EAAMmZ,GAExCA,EA5CaC,CAAoBpvF,GACxCA,EAAOruB,OAAQquB,EAAOo/B,iBAAkBg7C,EAAY,OAAS+U,GAG7DtjB,EAAO30E,GAAI,yBAA0B,CAAEpS,EAAKhZ,EAAMU,KACjDk3B,EAAK0nB,OAAQprB,IACZA,EAAO0K,SAAU,QAASl+B,EAAQ,IAAK2iH,OAnFtCE,CAAkBjV,EAAYp+C,EAAY6vC,EAAQthF,EAAO83D,QAAQ3+C,MA2KrE,SAA6B02E,EAAYp6E,EAAQ6rE,GAChD,GAAKA,EAAOl+F,KAAO,CAClB,MAAM2hH,EAAU1X,GAAsBwC,GAEtCp6E,EAAOtuB,aAAc,MAAOm6F,EAAOl+F,KAAM2hH,IA9KvCC,CAAoBnV,EAAYp+C,EAAY6vC,IAL5CojB,GAAkBvF,EAAatP,EAAYp+C,IAW9B,YAAV4wC,GAAwBmiB,EAAezjB,QAAQl/F,IAAK0iH,IA8F3D,SAA4B1U,EAAYp6E,EAAQ0D,GAC/C,MAAM8rF,EAAexvF,EAAOm+B,gBAAiB,MAAO,CAAE4tB,MAAO,kCAE7D/rD,EAAOruB,OAAQquB,EAAOo/B,iBAAkBg7C,EAAY,OAASoV,GAE7DhsE,WAAY,KACX9f,EAAK0nB,OAAQprB,GAAUA,EAAO7tB,OAAQ6tB,EAAO+0B,cAAey6D,MAC1D,KApGDC,CAAmBrV,EAAYp+C,EAAYzxC,EAAO83D,QAAQ3+C,MAoF7D,SAA2B02E,EAAYp6E,GACtC0vF,GAAkBtV,EAAYp6E,EAAQ,eAjFrC2vF,CAAkBvV,EAAYp+C,GAC9BkzD,GAAkB9U,EAAYp+C,GAmBhC,SAA4Bo+C,EAAYp6E,GACvCA,EAAO6K,YAAa,YAAauvE,GAnBhCwV,CAAmBxV,EAAYp+C,IAQjC,SAASgzD,GAAoB5U,EAAYp6E,GAClCo6E,EAAW7sF,SAAU,cAC1ByS,EAAO2K,SAAU,YAAayvE,GAiBhC,SAAS6U,GAAkBvF,EAAatP,EAAYp6E,GAC7Co6E,EAAW7sF,SAAU,gCAC1ByS,EAAO2K,SAAU,8BAA+ByvE,GAGjD,MAAMkV,EAAU1X,GAAsBwC,GAEjCkV,EAAQliG,aAAc,SAAYs8F,GACtC1pF,EAAOtuB,aAAc,MAAOg4G,EAAa4F,GAGpCO,GAAezV,EAAY,gBAChCp6E,EAAOruB,OAAQquB,EAAO2qC,oBAAqB2kD,GA4E7C,SAA6BtvF,GAC5B,MAAM0pF,EAAc1pF,EAAOm+B,gBAAiB,MAAO,CAAE4tB,MAAO,iCAI5D,OAFA/rD,EAAOg2E,kBAAmB,eAAe,EAAM0T,GAExCA,EAjFgDoG,CAAoB9vF,IAQ5E,SAASkvF,GAAkB9U,EAAYp6E,GACjCo6E,EAAW7sF,SAAU,gCACzByS,EAAO6K,YAAa,8BAA+BuvE,GAGpDsV,GAAkBtV,EAAYp6E,EAAQ,eA8EvC,SAAS6vF,GAAeE,EAAaC,GACpC,IAAM,MAAMv7F,KAASs7F,EAAYr7F,cAChC,GAAKD,EAAM+D,kBAAmBw3F,GAC7B,OAAOv7F,EAWV,SAASi7F,GAAkBtV,EAAYp6E,EAAQgwF,GAC9C,MAAMpjG,EAAUijG,GAAezV,EAAY4V,GAEtCpjG,GACJoT,EAAO7tB,OAAQ6tB,EAAO+0B,cAAenoC,IEhOxB,MAAM,GAIpB,YAAa5d,GAOZhB,KAAKgB,SAAWA,EAUjB,uBAAwB8G,GACvB,OAAO,IAAI,GAAkB9H,KAAKgB,SAAU8G,GAkB7C,cAAehK,EAAM0nB,EAAO1d,GAC3B,OAAO,IAAI,GAAS9H,KAAKgB,SAAUlD,EAAM0nB,EAAO1d,GASjD,WAAYnI,GACX,OAAO,IAAI,GAAMK,KAAKgB,SAAUrB,GAYjC,MAAOif,EAAS2H,GAAO,GACtB,OAAO3H,EAAQ+H,OAAQJ,GAcxB,YAAa5Q,EAAOiJ,GACnB,OAAOA,EAAQia,aAAcljB,GAe9B,YAAajT,EAAOiT,EAAOiJ,GAC1B,OAAOA,EAAQgH,aAAcljB,EAAOiT,GAcrC,eAAgBjT,EAAOukB,EAASrI,GAC/B,OAAOA,EAAQd,gBAAiBpb,EAAOukB,GASxC,OAAQrI,GACP,MAAM7B,EAAS6B,EAAQ7B,OAEvB,OAAKA,EACG/c,KAAKiiH,eAAgBllG,EAAOE,cAAe2B,GAAW,EAAG7B,GAG1D,GAUR,QAASmlG,EAAY9pF,GACpB,MAAMrb,EAASmlG,EAAWnlG,OAE1B,GAAKA,EAAS,CACb,MAAMra,EAAQqa,EAAOE,cAAeilG,GAKpC,OAHAliH,KAAKiiH,eAAgBv/G,EAAO,EAAGqa,GAC/B/c,KAAKmiH,YAAaz/G,EAAO01B,EAAYrb,IAE9B,EAGR,OAAO,EASR,cAAe6B,GACd,MAAM7B,EAAS6B,EAAQ7B,OAEvB,GAAKA,EAAS,CACb,MAAMra,EAAQqa,EAAOE,cAAe2B,GAEpC5e,KAAKmE,OAAQya,GACb5e,KAAKmiH,YAAaz/G,EAAOkc,EAAQ8H,cAAe3J,IAelD,OAAQ8d,EAASjc,GAChB,MAAMwZ,EAAa,IAAI,GAASp4B,KAAKgB,SAAU65B,EAASjc,EAAQmc,gBAAiBnc,EAAQ8H,eAEzF,OAAO1mB,KAAKkK,QAAS0U,EAASwZ,GAAeA,EAAa,KAa3D,aAAct5B,EAAKN,EAAOogB,GACzBA,EAAQ8Y,cAAe54B,EAAKN,GAY7B,gBAAiBM,EAAK8f,GACrBA,EAAQ+Y,iBAAkB74B,GAa3B,SAAUsnB,EAAWxH,GACpBA,EAAQgZ,UAAWxR,GAapB,YAAaA,EAAWxH,GACvBA,EAAQiZ,aAAczR,GAqBvB,SAAUlnB,EAAUV,EAAOogB,GACrB,EAAe1f,SAA0BoH,IAAZsY,IACjCA,EAAUpgB,GAEXogB,EAAQkZ,UAAW54B,EAAUV,GAiB9B,YAAaU,EAAU0f,GACtBA,EAAQmZ,aAAc74B,GAYvB,kBAAmBJ,EAAKN,EAAOogB,GAC9BA,EAAQ6L,mBAAoB3rB,EAAKN,GAWlC,qBAAsBM,EAAK8f,GAC1B,OAAOA,EAAQoZ,sBAAuBl5B,GAoBvC,iBAAkBiuB,EAAgBzgB,GACjC,OAAO,GAASwe,UAAWiC,EAAgBzgB,GAS5C,oBAAqBjK,GACpB,OAAO,GAASwpB,aAAcxpB,GAS/B,qBAAsBA,GACrB,OAAO,GAAS8pB,cAAe9pB,GAYhC,YAAawe,EAAOC,GACnB,OAAO,IAAI,GAAOD,EAAOC,GAS1B,cAAeze,GACd,OAAO,GAAMwuB,UAAWxuB,GAUzB,cAAeuc,GACd,OAAO,GAAMgS,UAAWhS,GA+DzB,gBAAiB+P,EAAYC,EAAe1sB,GAC3C,OAAO,IAAI,GAAWysB,EAAYC,EAAe1sB,ICtbpC,MAAM,WAA2BmrF,GAI/C,UACC,MAAMgc,EAAerpG,KAAKuc,OAAOysC,MAAMhoD,SAASopB,UAAUsH,qBACpDsgF,EAAU3I,GAAsC,UAAtBA,EAAavrG,OAAoB,EAEjEkC,KAAKsvC,UAAYi6D,GAAgBvpG,KAAKuc,OAAOysC,QAAWgpD,EAUzD,QAAS9vG,GACR,MAAMqa,EAASvc,KAAKuc,OACdysC,EAAQzsC,EAAOysC,MAEf+3D,EAAiBxkG,EAAOtE,QAAQ7Z,IAAK,IAE3C,IAAM,MAAM2+F,KAAQ1iF,GAASnY,EAAQ66F,MACpCqlB,GAAap5D,EAAO+3D,EAAgBhkB,IASvC,SAASqlB,GAAap5D,EAAO+3D,EAAgBhkB,GAC5C,MAAMc,EAASkjB,EAAesB,aAActlB,GAGtCc,GAINuL,GAAapgD,EAAO,CAAE83D,SAAUjjB,EAAOv7F,KC1DzB,MAAM,WAA2B,GAI/C,sBACC,MAAO,CAAE,GAAgB,GAAc,IAGxC,wBACC,MAAO,qBAMR,YAAaia,GACZ3c,MAAO2c,GAEPA,EAAOV,OAAO5e,OAAQ,QAAS,CAC9B6hG,OAAQ,CACPn4F,MAAO,CAAE,OAAQ,MAAO,MAAO,MAAO,OAAQ,WAQjD,OACC,MAAM4V,EAASvc,KAAKuc,OACd6qB,EAAM7qB,EAAOysC,MAAMhoD,SACnBioD,EAAS1sC,EAAOysC,MAAMC,OACtBqrB,EAAa/3D,EAAO+3D,WACpBysC,EAAiBxkG,EAAOtE,QAAQ7Z,IAAK,IAErCoiH,EAAaF,GAAuB/jG,EAAOV,OAAOzd,IAAK,uBAG7D6qD,EAAOlyB,OAAQ,QAAS,CACvBigC,gBAAiB,CAAE,WAAY,kBAIhCz6C,EAAO24C,SAAStmD,IAAK,cAAe,IAAI,GAAoB2N,IAG5D+3D,EAAWjV,IAAK,UACdK,qBAAsB,CACtBhqC,KAAM,CACL53B,KAAM,MACNgB,IAAK,YAENkqD,MAAO,aAOThpD,KAAKmR,SAAUoL,EAAO83D,QAAQ3+C,KAAK10B,SAAU,iBAAkB,CAAE8V,EAAKnX,KAGrE,GAwP6BisF,EAxPRjsF,EAAKisF,aAyPrBziF,MAAMiK,KAAMw4E,EAAajlF,OAAQyS,SAAU,cAAyD,KAAxCwyE,EAAaL,QAAS,aAxPtF,OAuPG,IAAyBK,EApP7B,MAAMqmB,EAAS9oG,MAAMiK,KAAMzT,EAAKisF,aAAaV,OAAQlnF,OAAQ+4F,KAEtDA,GAICyjB,EAAWr2G,KAAM4yF,EAAK98F,OAGxB4tB,EAASluB,EAAK+rF,aAAarhF,IAAKk/B,GAAahtB,EAAO83D,QAAQ1wB,OAAOyQ,aAAc7qB,IAEvFhtB,EAAOysC,MAAM5L,OAAQprB,IAEpBA,EAAOyI,aAAc5M,GAEhBokF,EAAOlwG,SACX+U,EAAIhH,OAGJyM,EAAOysC,MAAMqC,cAAe,UAAW,KACtC9uC,EAAO04C,QAAS,cAAe,CAAE8nC,KAAMkV,WAU3CjyG,KAAKmR,SAAUoL,EAAOtE,QAAQ7Z,IAAK,IAAa,sBAAuB,CAAE0Y,EAAKnX,KAC7E,MAAM2iH,EAAkBn5G,MAAMiK,KAAMmJ,EAAO83D,QAAQ3+C,KAAKg/B,cAAe/0D,EAAKuH,UAC1ElD,OAAQxF,IAAS+jH,UPhEQhwG,EOgEM/T,EAAM6D,MP/D9BlC,GAAI,UAAW,SAAYoS,EAAK6M,aAAc,UAIlD7M,EAAK6M,aAAc,OAAQ1D,MAAO,8BACxCnJ,EAAK6M,aAAc,OAAQ1D,MAAO,cO0DiBld,EAAM6D,KAAK+c,aAAc,mBPhEvE,IAAuB7M,IOiEzBlI,IAAK7L,IAAW,MAAO,CAAEub,SP1FGs4F,EO0FuB7zG,EAAM6D,KPzFtD,IAAI0W,QAAS,CAAE/L,EAASgM,KAC9B,MAAMwpG,EAAWnQ,EAAMjzF,aAAc,OAGrCqjG,MAAOD,GACLtpG,KAAMwpG,GAAYA,EAASC,QAC3BzpG,KAAMypG,IACN,MAAMC,EA+BV,SAA2BD,EAAMzY,GAChC,OAAKyY,EAAK1iH,KACF0iH,EAAK1iH,KACDiqG,EAAIxuF,MAAO,4BACfwuF,EAAIxuF,MAAO,4BAA8B,GAAI+W,cAG7C,aAtCYowF,CAAkBF,EAAMH,GACnCnlC,EAAMulC,EAAS14G,QAAS,SAAU,IAElC6yF,EAAO,IAAI+lB,KAAM,CAAEH,GADR,SAAUtlC,EACgB,CAAEp9E,KAAM2iH,IAEnD51G,EAAS+vF,KAETnjF,MAAOZ,MO2E2DqwF,aAAc7qG,EAAM6D,MP1FnF,IAA0BgwG,IO4F9B,IAAMiQ,EAAgBvgH,OACrB,OAGD,MAAMiwB,EAAS,IAAI,GAAczV,EAAO83D,QAAQ3+C,KAAK10B,UAErD,IAAM,MAAM+hH,KAAkBT,EAAkB,CAE/CtwF,EAAOtuB,aAAc,mBAAmB,EAAMq/G,EAAe1Z,cAE7D,MAAMxL,EAASkjB,EAAesB,aAAcU,EAAehpG,SAEtD8jF,IACJ7rE,EAAOtuB,aAAc,MAAO,GAAIq/G,EAAe1Z,cAC/Cr3E,EAAOtuB,aAAc,WAAYm6F,EAAOv7F,GAAIygH,EAAe1Z,kBAM9D9sF,EAAO83D,QAAQ3+C,KAAK10B,SAASkoB,GAAI,WAAY,CAAEpS,EAAKnX,KACnDA,EAAKi0C,mBAINxM,EAAIle,GAAI,SAAU,KACjB,MAAMo8B,EAAUle,EAAI8d,OAAOyC,WAAY,CAAE8e,2BAA2B,IAEpE,IAAM,MAAMj9D,KAAS87C,EACpB,GAAmB,UAAd97C,EAAMvJ,MAAkC,SAAduJ,EAAM1L,KAAkB,CACtD,MAAMuE,EAAOmH,EAAMqhB,SAASuC,UACtB41F,EAAgD,cAAhCx5G,EAAMqhB,SAAShuB,KAAK0tB,SAE1C,IAAM,MAAM8nF,KAAS4Q,GAAyB1mG,EAAQla,GAAS,CAE9D,MAAMy+G,EAAWzO,EAAMjzF,aAAc,YAErC,IAAM0hG,EACL,SAID,MAAMjjB,EAASkjB,EAAezjB,QAAQl/F,IAAK0iH,GAErCjjB,IAIDmlB,EAEJnlB,EAAOR,QACqB,QAAjBQ,EAAOe,QAElB5+F,KAAKkjH,eAAgBrlB,EAAQwU,QAoBnC,eAAgBxU,EAAQwL,GACvB,MAAM9sF,EAASvc,KAAKuc,OACdysC,EAAQzsC,EAAOysC,MACfvqD,EAAI8d,EAAON,OAAOxd,EAClBsiH,EAAiBxkG,EAAOtE,QAAQ7Z,IAAK,IACrCq0G,EAAel2F,EAAOtE,QAAQ7Z,IAAK,IAMzC,OAJA4qD,EAAMqC,cAAe,cAAer5B,IACnCA,EAAOtuB,aAAc,eAAgB,UAAW2lG,KAG1CxL,EAAOgB,OACZ3lF,KAAM,KACN,MAAMa,EAAU8jF,EAAOiB,SAKvB,GAAK,GAAIlsE,SAAW,CACnB,MACM0uF,EAAU1X,GADGrtF,EAAO83D,QAAQ1wB,OAAOR,cAAekmD,IAGxD9sF,EAAO83D,QAAQ3+C,KAAKy+C,KAAM,SAAU,KAGnC,IAAMmtC,EAAQvkG,OACb,OAGD,MAAMomG,EAAY5mG,EAAO83D,QAAQ3+C,KAAKC,aAAa6L,aAAc8/E,EAAQvkG,QAEzE,IAAMomG,EACL,OAGD,MAAMC,EAAkBD,EAAU//G,MAAMi0E,QAExC8rC,EAAU//G,MAAMi0E,QAAU,OAG1B8rC,EAAUE,QAAUF,EAAUtpE,aAE9BspE,EAAU//G,MAAMi0E,QAAU+rC,IAQ5B,OAJAp6D,EAAMqC,cAAe,cAAer5B,IACnCA,EAAOtuB,aAAc,eAAgB,YAAa2lG,KAG5CtvF,IAEPb,KAAMvZ,IACNqpD,EAAMqC,cAAe,cAAer5B,IACnCA,EAAOo8C,cAAe,CAAEk1C,aAAc,WAAYpZ,IAAKvqG,EAAKwH,SAAWkiG,GACvErpG,KAAKujH,mCAAoC5jH,EAAM0pG,EAAcr3E,KAG9DwxF,MAEA5pG,MAAOxZ,IAGP,GAAuB,UAAlBy9F,EAAOe,QAAwC,YAAlBf,EAAOe,OACxC,MAAMx+F,EAIe,SAAjBy9F,EAAOe,QAAqBx+F,GAChCqyG,EAAaC,YAAatyG,EAAO,CAChCoxG,MAAO/yG,EAAG,iBACVu/E,UAAW,WAIbwlC,IAGAx6D,EAAMqC,cAAe,cAAer5B,IACnCA,EAAO7tB,OAAQklG,OAIlB,SAASma,IACRx6D,EAAMqC,cAAe,cAAer5B,IACnCA,EAAOptB,gBAAiB,WAAYykG,GACpCr3E,EAAOptB,gBAAiB,eAAgBykG,KAGzC0X,EAAe0C,cAAe5lB,IAYhC,mCAAoCl+F,EAAM0yG,EAAOrgF,GAEhD,IAAIi2D,EAAW,EAEf,MAAMy7B,EAAkBzlH,OAAOuF,KAAM7D,GAEnCqE,OAAQlF,IACR,MAAMknC,EAAQwO,SAAU11C,EAAK,IAE7B,IAAM6kH,MAAO39E,GAGZ,OAFAiiD,EAAW73E,KAAKsR,IAAKumE,EAAUjiD,IAExB,IAKR37B,IAAKvL,GAAO,GAAIa,EAAMb,MAAWA,MAGjCmF,KAAM,MAEgB,IAAnBy/G,GACJ1xF,EAAOtuB,aAAc,SAAU,CAC9B/D,KAAM+jH,EACN19E,MAAOiiD,GACLoqB,IAaN,SAAS4Q,GAAyB1mG,EAAQla,GACzC,OAAO8G,MAAMiK,KAAMmJ,EAAOysC,MAAMjC,cAAe1kD,IAC7C2B,OAAQxF,GAASA,EAAM6D,KAAKlC,GAAI,UAAW,UAC3CkK,IAAK7L,GAASA,EAAM6D,MC5TR,MAAM,WAAoB,GAIxC,wBACC,MAAO,cAMR,sBACC,MAAO,CAAE,GAAoB,GAAe,KCtB/B,MAAM,WAAyBgrF,GAY7C,UACC,MAAMrkC,EAAQhpD,KAAKuc,OAAOysC,MAEpBP,EAAQ,GADGO,EAAMhoD,SACOopB,UAAU4/B,qBAExChqD,KAAKxB,QAAUiqD,GAASA,EAAMtoD,GAAI,UAAW,aAC7CH,KAAKsvC,YAAcmZ,GAASm7D,GAAyBn7D,EAAOO,EAAMC,QAanE,QAAS/mD,EAAU,IAClB,MAAM8mD,EAAQhpD,KAAKuc,OAAOysC,MACpBhoD,EAAWgoD,EAAMhoD,SAEvBgoD,EAAM5L,OAAQprB,IACb,MAAM2wE,GAAWzgG,EAAQkoB,WAAappB,EAASopB,WAAY4/B,oBAE3D,IAAM,MAAMvB,KAASk6C,GACdl6C,EAAMtoD,GAAI,UAAW,cAAiByjH,GAAyBn7D,EAAOO,EAAMC,SACjFj3B,EAAOk8C,OAAQzlB,EAAO,gBAa3B,SAASm7D,GAAyBn7D,EAAOQ,GACxC,OAAOA,EAAOiH,WAAYzH,EAAM1rC,OAAQ,eAAkBksC,EAAO6D,SAAUrE,GC3C7D,MAAM,WAA+B4kC,GASnD,QAASnrF,GACR,MAAM8mD,EAAQhpD,KAAKuc,OAAOysC,MAC1B,IAAIn+B,EAAW3oB,EAAQ2oB,SAEvBm+B,EAAM5L,OAAQprB,IACb,MAAMm/B,EAAYn/B,EAAO3uB,cAAe,aAExC,IAAM2lD,EAAMC,OAAOiH,WAAYrlC,EAAS9N,OAAQo0C,GAAc,CAC7D,MAAM0L,EAAgB7T,EAAMC,OAAO6T,kBAAmBjyC,EAAUsmC,GAIhE,IAAM0L,EACL,OAGDhyC,EAAWmH,EAAOziB,MAAOsb,EAAUgyC,GAAgBhyC,SAGpDm+B,EAAM6pB,cAAe1hB,EAAWtmC,GAEhCmH,EAAOyI,aAAc02B,EAAW,SC9BpB,MAAM,WAAkB,GAItC,wBACC,MAAO,YAMR,OACC,MAAM50C,EAASvc,KAAKuc,OACdysC,EAAQzsC,EAAOysC,MAErBzsC,EAAO24C,SAAStmD,IAAK,YAAa,IAAI,GAAkB2N,IACxDA,EAAO24C,SAAStmD,IAAK,kBAAmB,IAAI,GAAwB2N,IAGpEysC,EAAMC,OAAOipB,SAAU,YAAa,CAAE/X,eAAgB,WAEtD59C,EAAO+3D,WAAWhV,iBAAkB,CAAEtW,MAAO,YAAatzB,KAAM,MAGhEnZ,EAAO+3D,WAAWjV,IAAK,UAAWC,iBAAkB,CACnDtW,MAAO,CAAEluB,GAAe9I,YACjB,GAAU6xF,sBAAsBn6G,IAAKoxB,EAAYh9B,MAKlDg9B,EAAYrY,QACT,KAGDuP,EAAO3uB,cAAe,aARrB,KAUTqyB,KAAM,KACN63B,kBAAmB,SAoCtB,GAAUs2D,sBAAwB,IAAIxrG,IAAK,CAC1C,aACA,KACA,MACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,KACA,IACA,KACA,OCnGc,MAAM,WAAuBg1E,GAO3C,YAAa9wE,EAAQunG,GACpBlkH,MAAO2c,GAmBPvc,KAAK8jH,cAAgBA,EAMtB,UACC,MAAMr7D,EAAQ,GAAOzoD,KAAKuc,OAAOysC,MAAMhoD,SAASopB,UAAU4/B,qBAE1DhqD,KAAKxB,QAAUiqD,GAASzoD,KAAK8jH,cAAc1qG,SAAUqvC,EAAM3qD,OAAU2qD,EAAM3qD,KAC3EkC,KAAKsvC,YAAcmZ,GAASzoD,KAAK8jH,cAAc3qF,KAAM4qF,GAAWC,GAAuBv7D,EAAOs7D,EAAS/jH,KAAKuc,OAAOysC,MAAMC,SAW1H,QAAS/mD,GACR,MAAM8mD,EAAQhpD,KAAKuc,OAAOysC,MACpBhoD,EAAWgoD,EAAMhoD,SAEjBgiD,EAAe9gD,EAAQ1D,MAE7BwqD,EAAM5L,OAAQprB,IACb,MAAM2wE,EAASx5F,MAAMiK,KAAMpS,EAASopB,UAAU4/B,qBAC5ChmD,OAAQykD,GACDu7D,GAAuBv7D,EAAOzF,EAAcgG,EAAMC,SAG3D,IAAM,MAAMR,KAASk6C,EACdl6C,EAAMtoD,GAAI,UAAW6iD,IAC1BhxB,EAAOk8C,OAAQzlB,EAAOzF,MAc3B,SAASghE,GAAuBv7D,EAAOs7D,EAAS96D,GAC/C,OAAOA,EAAOiH,WAAYzH,EAAM1rC,OAAQgnG,KAAc96D,EAAO6D,SAAUrE,GCtEzD,MAAM,WAAuB,GAI3C,wBACC,MAAO,iBAMR,YAAalsC,GACZ3c,MAAO2c,GAEPA,EAAOV,OAAO5e,OAAQ,UAAW,CAChCiF,QAAS,CACR,CAAE8mD,MAAO,YAAawoD,MAAO,YAAazzB,MAAO,wBACjD,CAAE/0B,MAAO,WAAYtzB,KAAM,KAAM87E,MAAO,YAAazzB,MAAO,uBAC5D,CAAE/0B,MAAO,WAAYtzB,KAAM,KAAM87E,MAAO,YAAazzB,MAAO,uBAC5D,CAAE/0B,MAAO,WAAYtzB,KAAM,KAAM87E,MAAO,YAAazzB,MAAO,0BAQ/D,sBACC,MAAO,CAAE,IAMV,OACC,MAAMxhE,EAASvc,KAAKuc,OACdra,EAAUqa,EAAOV,OAAOzd,IAAK,mBAE7B0lH,EAAgB,GAEtB,IAAM,MAAMG,KAAU/hH,EAjDI,cAmDpB+hH,EAAOj7D,QAEXzsC,EAAOysC,MAAMC,OAAOipB,SAAU+xC,EAAOj7D,MAAO,CAC3CmR,eAAgB,WAGjB59C,EAAO+3D,WAAWhV,iBAAkB2kD,GAEpCH,EAAc7gH,KAAMghH,EAAOj7D,QAI7BhpD,KAAKkkH,wBAAyB3nG,GAG9BA,EAAO24C,SAAStmD,IAAK,UAAW,IAAI,GAAgB2N,EAAQunG,IAM7D,YAGC,MAAMvnG,EAASvc,KAAKuc,OACd4nG,EAAe5nG,EAAO24C,SAAS92D,IAAK,SACpC8D,EAAUqa,EAAOV,OAAOzd,IAAK,mBAE9B+lH,GACJnkH,KAAKmR,SAAUgzG,EAAc,eAAgB,CAAErtG,EAAKnX,KACnD,MAAM84B,EAAiBlc,EAAOysC,MAAMhoD,SAASopB,UAAUoH,mBAAmBzU,OACxD7a,EAAQi3B,KAAM8qF,GAAUxrF,EAAet4B,GAAI,UAAW8jH,EAAOj7D,UAE5DvwB,EAAet4B,GAAI,UApFd,cAoFgF,IAA9Bs4B,EAAe3R,YACxFnnB,EAAKqyB,OAAOk8C,OAAQz1C,EArFG,eAiG3B,wBAAyBlc,GACxBA,EAAO+3D,WAAWjV,IAAK,UAAWC,iBAAkB,CACnDtW,MAAO,WACPtzB,KAAM,KAGN63B,kBAAmB,GAAWnvD,IAAK,OAAU,KCpGjC,MAAM,GAOpB,YAAakF,EAAYqkB,GAEnBA,GACJ,GAAQ3nB,KAAM2nB,GAIVrkB,GACJtD,KAAKyJ,IAAKnG,IAKbkR,GAAK,GAAO,I,MCdG,MAAM,WAAkB,GAItC,OACC,MAAM+H,EAASvc,KAAKuc,OACd9d,EAAI8d,EAAO9d,EACXyD,ECXD,SAA8Bqa,GACpC,MAAM9d,EAAI8d,EAAO9d,EACX2lH,EAAkB,CACvBC,UAAW5lH,EAAG,aACd,YAAaA,EAAG,aAChB,YAAaA,EAAG,aAChB,YAAaA,EAAG,aAChB,YAAaA,EAAG,aAChB,YAAaA,EAAG,aAChB,YAAaA,EAAG,cAGjB,OAAO8d,EAAOV,OAAOzd,IAAK,mBAAoBiM,IAAK45G,IAClD,MAAMzS,EAAQ4S,EAAiBH,EAAOzS,OAMtC,OAJKA,GAASA,GAASyS,EAAOzS,QAC7ByS,EAAOzS,MAAQA,GAGTyS,IDRSK,CAAqB/nG,GAC/BgoG,EAAe9lH,EAAG,kBAClB+lH,EAAkB/lH,EAAG,WAG3B8d,EAAOL,GAAG+5D,iBAAiBrnE,IAAK,UAAWqN,IAC1C,MAAMwoG,EAAS,GACTC,EAAkB,IAAI,GAEtBC,EAAiBpoG,EAAO24C,SAAS92D,IAAK,WACtCwmH,EAAmBroG,EAAO24C,SAAS92D,IAAK,aAExC82D,EAAW,CAAEyvD,GAEnB,IAAM,MAAMV,KAAU/hH,EAAU,CAC/B,MAAM00D,EAAM,CACX32D,KAAM,SACN+oD,MAAO,IAAI,GAAO,CACjBt4B,MAAOuzF,EAAOzS,MACdzzB,MAAOkmC,EAAOlmC,MACd8mC,UAAU,KAIU,cAAjBZ,EAAOj7D,OACX4N,EAAI5N,MAAMjqD,KAAM,QAAS6U,GAAIgxG,EAAkB,SAC/ChuD,EAAI5N,MAAMv/C,IAAK,cAAe,aAC9ByrD,EAASjyD,KAAM2hH,KAEfhuD,EAAI5N,MAAMjqD,KAAM,QAAS6U,GAAI+wG,EAAgB,QAASnmH,GAASA,IAAUylH,EAAOj7D,OAChF4N,EAAI5N,MAAMv/C,IAAK,CACdsrD,YAAa,UACb+vD,aAAcb,EAAOj7D,SAKvB07D,EAAgB91G,IAAKgoD,GAErB6tD,EAAQR,EAAOj7D,OAAUi7D,EAAOzS,MAGjC,MAAMlqB,EAAeF,GAAgBnrE,GAiCrC,OAhCA0rE,GAAmBL,EAAco9B,GAEjCp9B,EAAalD,WAAW36E,IAAK,CAC5Bs7G,MAAM,EACNF,UAAU,EACVv+B,QAASk+B,IAGVl9B,EAAalN,eAAgB,CAC5B92E,WAAY,CACXy6E,MAAO,CACN,0BAKHuJ,EAAavoF,KAAM,aAAcopB,OAAQ+sC,EAAU,YAAa,IAAK8vD,IAC7DA,EAAW7rF,KAAMmW,GAAaA,IAGtCg4C,EAAalD,WAAWrlF,KAAM,SAAU6U,GAAI+wG,EAAgB,QAASC,EAAkB,QAAS,CAAEpmH,EAAOymH,KACxG,MAAMC,EAAa1mH,GAASymH,GAAQ,YAEpC,OAAOR,EAAQS,GAAeT,EAAQS,GAAeX,IAItDvkH,KAAKmR,SAAUm2E,EAAc,UAAWxwE,IACvCyF,EAAO04C,QAASn+C,EAAIlM,OAAOmqD,YAAaj+C,EAAIlM,OAAOk6G,aAAe,CAAEtmH,MAAOsY,EAAIlM,OAAOk6G,mBAAiBx+G,GACvGiW,EAAO83D,QAAQ3+C,KAAK7F,UAGdy3D,KExDH,SAAS69B,GAAqBC,GACpC,IAAM,MAAM7yG,KAAQ6yG,EAAkB1+F,cACrC,GAAOnU,GAAQA,EAAKpS,GAAI,UAAW,WAClC,OAAOoS,EAIT,OAAO,KAWD,SAAS8yG,GAAmBzmG,GAClC,MAAM7B,EAAS6B,EAAQ7B,OAGvB,MAAqB,cAAhB6B,EAAQ9gB,MAAwBif,GAAyB,UAAfA,EAAOjf,MAAoBif,EAAOwC,SAAU,SACnF,CAAEzhB,MAAM,GAGT,KCvDO,MAAM,WAA4B,GAIhD,wBACC,MAAO,sBAMR,OACC,MAAMye,EAASvc,KAAKuc,OACdmZ,EAAOnZ,EAAO83D,QAAQ3+C,KACtBuzB,EAAS1sC,EAAOysC,MAAMC,OACtBtpD,EAAO4c,EAAO5c,KACd00E,EAAU93D,EAAO83D,QACjB51E,EAAI8d,EAAO9d,EAWjBwqD,EAAOipB,SAAU,UAAW,CAC3BhZ,QAAS,QACTQ,eAAgB,SAChBtQ,SAAS,IAIV7sC,EAAOysC,MAAMhoD,SAASkvE,kBAAmBl+C,GAAUhyB,KAAKslH,kCAAmCtzF,IAG3FzV,EAAO+3D,WAAWjV,IAAK,UAAWC,iBAAkB,CACnD5pC,KAAM2vF,GACNr8D,MAAO,YAKRrpD,EAAKq0D,mBAAmB9qC,GAAI,iBAAkBq8F,GADjBvzF,GAAUA,EAAOy+B,uBAAwB,eACkB,IAGxF,MAAM+0D,EDlDD,SAAgC9vF,EAAMkjD,GAC5C,OAAO5mD,IACN,MAAMxF,EAAWwF,EAAOyzF,sBAAuB,cAS/C,OARAzzF,EAAOg2E,kBAAmB,gBAAgB,EAAMx7E,GAEhD+pD,GAAmB,CAClB7gD,OACA9W,QAAS4N,EACT+lB,KAAMqmC,IAGA8vB,GAAkBl8E,EAAUwF,ICuCH0zF,CAAuBhwF,EAAMj3B,EAAG,wBAChE41E,EAAQrgB,mBAAmB9qC,GAAI,iBAAkBq8F,GAAoBC,IAGrEnxC,EAAQrgB,mBAAmB9qC,GAC1B,SACAlpB,KAAK2lH,sBAAuBhmH,GAAQA,EAAK0C,MACzC,CAAEoO,SAAU,SAIb4jE,EAAQrgB,mBAAmB9qC,GAAI,SAAUlpB,KAAK2lH,sBAAuBhmH,GAAQA,EAAKkrB,SAAS9N,QAAU,CAAEtM,SAAU,SAGjHilB,EAAK10B,SAASkvE,kBAAmBl+C,GAAUhyB,KAAK4lH,yBAA0B5zF,IAW3E,yBAA0Bg8B,GACzB,MAAMrK,EAAS3jD,KAAKuc,OAAO83D,QAAQ1wB,OAC7BkiE,EAAc7lH,KAAK8lH,qBACzB,IAAIC,EAGJ,MAAM1xD,EAAiBr0D,KAAKuc,OAAOysC,MAAMhoD,SAASopB,UAC5Cw+E,EAAkBv0C,EAAe3iC,qBAEvC,GAAKk3E,GAAmBA,EAAgBzoG,GAAI,UAAW,SAAY,CAClE,MAAM6lH,EAAeb,GAAqBvc,GAC1Cmd,EAAcpiE,EAAOR,cAAe6iE,GAIrC,MACMA,EAAeC,GADJ5xD,EAAe7iC,mBACgBzU,QAOhD,GALKipG,IACJD,EAAcpiE,EAAOR,cAAe6iE,IAIhCD,EAEJ,OAAKF,GAECA,IAAgBE,IAGpBG,GAAoBL,EAAa73D,GACjChuD,KAAK8lH,qBAAuBC,GAHrBI,GAAaJ,EAAa/3D,KAQlChuD,KAAK8lH,qBAAuBC,EACrBI,GAAaJ,EAAa/3D,IAIlC,GAAK63D,EAAc,CAClB,MAAMO,EAAeF,GAAoBL,EAAa73D,GAGtD,OAFAhuD,KAAK8lH,qBAAuB,KAErBM,EAEP,OAAO,EAaV,sBAAuBC,GACtB,MAAO,CAAEvvG,EAAKnX,EAAMolD,KACnB,MACMihE,EAAeC,GADRI,EAAY1mH,IAEnBgkD,EAAS3jD,KAAKuc,OAAO83D,QAAQ1wB,OAC7BqK,EAAajJ,EAAc/yB,OAEjC,GAAKg0F,EAAe,CACnB,MAAMD,EAAcpiE,EAAOR,cAAe6iE,GAErCD,IACCC,EAAal/F,WACjBknC,EAAWnxB,YAAa,YAAakpF,GAErC/3D,EAAWrxB,SAAU,YAAaopF,MAevC,kCAAmC/zF,GAClC,MAAMg3B,EAAQhpD,KAAKuc,OAAOysC,MACpB1D,EAAU0D,EAAMhoD,SAASkkD,OAAOyC,aAEhC2+D,EAAuB,GAE7B,IAAM,MAAM98G,KAAS87C,EACpB,GAAmB,UAAd97C,EAAMvJ,MAAkC,SAAduJ,EAAM1L,KAAkB,CACtD,MAAMuE,EAAOmH,EAAMqhB,SAASuC,UAO5B,GALK/qB,EAAKlC,GAAI,UAAW,WAAcglH,GAAqB9iH,IAC3DikH,EAAqBrjH,KAAMZ,IAItBA,EAAKlC,GAAI,UAAW,UAAakC,EAAKykB,WAC3C,IAAM,MAAMy/F,KAAcv9D,EAAM0L,cAAeryD,GAAOilD,WAChDi/D,EAAWpmH,GAAI,UAAW,WAAcglH,GAAqBoB,IACjED,EAAqBrjH,KAAMsjH,GAOhC,IAAM,MAAMlU,KAASiU,EACpBt0F,EAAOw0F,cAAe,UAAWnU,GAGlC,QAASiU,EAAqBvkH,QAUhC,SAASwjH,GAAoBl4D,EAAgBw4C,GAAO,GACnD,MAAO,CAAE/uF,EAAKnX,EAAMolD,KACnB,MAAM0hE,EAAiB9mH,EAAK0C,KAG5B,IAAMokH,EAAe3/F,YAAe++E,IAI/B,GAAS4gB,EAAe1pG,QAAW,CACvC,IAAMgoC,EAAcqB,WAAWkH,QAAS3tD,EAAK0C,KAAM,UAClD,OAGD,MAAMmoG,EAAYzlD,EAAcpB,OAAOR,cAAexjD,EAAKsvB,MAAMpO,MAAM9D,QACjEgpG,EAAc14D,EAAgBtI,EAAc/yB,QAC5Cg8B,EAAajJ,EAAc/yB,OAG3By0F,EAAe3/F,YACpBknC,EAAWrxB,SAAU,YAAaopF,GAetC,SAAmCA,EAAaC,EAAcxb,EAAWzlD,GACxE,MAAMvuB,EAAeuuB,EAAc/yB,OAAOo/B,iBAAkBo5C,EAAW,OAEvEzlD,EAAc/yB,OAAOruB,OAAQ6yB,EAAcuvF,GAC3ChhE,EAAcpB,OAAOrgB,aAAc0iF,EAAcD,GAhB/CW,CAA0BX,EAAapmH,EAAK0C,KAAMmoG,EAAWzlD,KAwBhE,SAASkhE,GAAkB1zG,GAC1B,MACMo0G,EADYp0G,EAAKiL,aAAc,CAAEJ,aAAa,IAC1BhH,KAAMikB,GAA6B,WAAjBA,EAASv8B,MAErD,OAAK6oH,GAAWA,EAAQ5pG,QAAiC,SAAvB4pG,EAAQ5pG,OAAOjf,KACzC6oH,EAGD,KASR,SAAST,GAAoBS,EAAS34D,GACrC,OAAM24D,EAAQ7/F,aAAe6/F,EAAQpnG,SAAU,eAC9CyuC,EAAWrxB,SAAU,YAAagqF,IAC3B,GAYT,SAASR,GAAaQ,EAAS34D,GAC9B,QAAK24D,EAAQpnG,SAAU,eACtByuC,EAAWnxB,YAAa,YAAa8pF,IAC9B,G,MC/RM,MAAM,WAA0Bt5B,GAO9C,YAAa9wE,EAAQkD,GACpB7f,MAAO2c,GAQPvc,KAAK4mH,cAAe,EAQpB5mH,KAAKyf,OAASA,EAAOpI,OAAQ,CAAEoI,EAAQrc,KACtCqc,EAAQrc,EAAMtF,MAASsF,EAElBA,EAAMyjH,YACV7mH,KAAK4mH,aAAexjH,EAAMtF,MAGpB2hB,GACL,IAMJ,UACC,MAAMb,EAAU5e,KAAKuc,OAAOysC,MAAMhoD,SAASopB,UAAUsH,qBAIrD,GAFA1xB,KAAKsvC,UAAY,GAAS1wB,GAEpBA,EAEC,GAAKA,EAAQM,aAAc,cAAiB,CAClD,MAAM4nG,EAAiBloG,EAAQQ,aAAc,cAC7Cpf,KAAKxB,QAAQwB,KAAKyf,OAAQqnG,IAAmBA,OAE7C9mH,KAAKxB,MAAQwB,KAAK4mH,kBALlB5mH,KAAKxB,OAAQ,EAmBf,QAAS0D,GACR,MAAMy5E,EAAYz5E,EAAQ1D,MAEpBwqD,EAAQhpD,KAAKuc,OAAOysC,MACpBqgD,EAAergD,EAAMhoD,SAASopB,UAAUsH,qBAE9Cs3B,EAAM5L,OAAQprB,IAGRhyB,KAAKyf,OAAQk8D,GAAYkrC,UAC7B70F,EAAOptB,gBAAiB,aAAcykG,GAEtCr3E,EAAOtuB,aAAc,aAAci4E,EAAW0tB,MCZlD,SAAS0d,GAAgBjpH,EAAM2hB,GAC9B,IAAM,MAAMrc,KAASqc,EACpB,GAAKrc,EAAMtF,OAASA,EACnB,OAAOsF,ECnFK,kRCAA,oZCAA,yQCAA,4TCgCf,MAAM4jH,GAAgB,CAErBC,KAAM,CACLnpH,KAAM,OACN0zG,MAAO,kBACPprB,KAAM,GACNygC,WAAW,GAIZxwB,KAAM,CACLv4F,KAAM,OACN0zG,MAAO,aACPprB,KAAM,GACNhgE,UAAW,oBAIZ8gG,UAAW,CACVppH,KAAM,YACN0zG,MAAO,qBACPprB,KAAM,GACNhgE,UAAW,0BAIZ+gG,YAAa,CACZrpH,KAAM,cACN0zG,MAAO,iBACPprB,KAAM,GACNhgE,UAAW,4BAIZghG,WAAY,CACXtpH,KAAM,aACN0zG,MAAO,sBACPprB,KAAM,GACNhgE,UAAW,4BAYPihG,GAAe,CACpBJ,KAAM,GACNlhF,KAAM,GACN2R,MAAO,GACP4vE,OAAQ,IASF,SAASC,GAAsBC,EAAmB,IACxD,OAAOA,EAAiBn9G,IAAKo9G,IAQ9B,SAASA,GAAiBrkH,GAEzB,GAAqB,iBAATA,EAAoB,CAC/B,MAAMu4E,EAAYv4E,EAGb4jH,GAAerrC,GAEnBv4E,EAAQnF,OAAO4nC,OAAQ,GAAImhF,GAAerrC,KAU1C,aAAY,wBAAyB,CAAE79E,KAAM69E,IAG7Cv4E,EAAQ,CACPtF,KAAM69E,SAOJ,GAAKqrC,GAAe5jH,EAAMtF,MAAS,CACvC,MAAM8oH,EAAeI,GAAe5jH,EAAMtF,MACpC4pH,EAAgBzpH,OAAO4nC,OAAQ,GAAIziC,GAEzC,IAAM,MAAMg2C,KAAQwtE,EACb3oH,OAAOkB,UAAUC,eAAe1B,KAAM0F,EAAOg2C,KAClDsuE,EAAetuE,GAASwtE,EAAcxtE,IAIxCh2C,EAAQskH,EAST,MAJ0B,iBAAdtkH,EAAMgjF,MAAoBihC,GAAcjkH,EAAMgjF,QACzDhjF,EAAMgjF,KAAOihC,GAAcjkH,EAAMgjF,OAG3BhjF,ECpIO,MAAM,WAA0B,GAI9C,wBACC,MAAO,oBAMR,OACC,MAAMmZ,EAASvc,KAAKuc,OACd0sC,EAAS1sC,EAAOysC,MAAMC,OACtBtpD,EAAO4c,EAAO5c,KACd00E,EAAU93D,EAAO83D,QAGvB93D,EAAOV,OAAO5e,OAAQ,eAAgB,CAAE,OAAQ,SAGhD,MAAMwiB,EAAS8nG,GAAsBhrG,EAAOV,OAAOzd,IAAK,iBAIxD6qD,EAAOlyB,OAAQ,QAAS,CAAEigC,gBAAiB,eAG3C,MAAM2wD,EN9BD,SAAoCloG,GAC1C,MAAO,CAAE3I,EAAKnX,EAAMolD,KACnB,IAAMA,EAAcqB,WAAWkH,QAAS3tD,EAAK0C,KAAMyU,EAAIhZ,MACtD,OAID,MAAM8pH,EAAWb,GAAgBpnH,EAAKmmD,kBAAmBrmC,GACnDooG,EAAWd,GAAgBpnH,EAAKkmD,kBAAmBpmC,GAEnDqb,EAAciqB,EAAcpB,OAAOR,cAAexjD,EAAK0C,MACvD2rD,EAAajJ,EAAc/yB,OAE5B61F,GACJ75D,EAAWnxB,YAAagrF,EAASzhG,UAAW0U,GAGxC8sF,GACJ55D,EAAWrxB,SAAUirF,EAASxhG,UAAW0U,IMYbgtF,CAA2BroG,GACxD40D,EAAQrgB,mBAAmB9qC,GAAI,6BAA8By+F,GAC7DhoH,EAAKq0D,mBAAmB9qC,GAAI,6BAA8By+F,GAG1DhoH,EAAK29D,iBAAiBp0C,GAAI,iBNNrB,SAAoCzJ,GAE1C,MAAMsoG,EAAiBtoG,EAAOzb,OAAQZ,IAAUA,EAAMyjH,WAEtD,MAAO,CAAE/vG,EAAKnX,EAAMolD,KACnB,IAAMplD,EAAK8jD,WACV,OAGD,MAAMukE,EAAoBroH,EAAKozD,SACzBk1D,EAAoB,GAAOtoH,EAAK8jD,WAAW6D,YAGjD,GAAMvC,EAAckE,OAAO4K,eAAgBo0D,EAAmB,cAK9D,IAAM,MAAM7kH,KAAS2kH,EAEfhjE,EAAcqB,WAAWkH,QAAS06D,EAAmB,CAAErpG,QAASvb,EAAMgjB,aAE1E2+B,EAAc/yB,OAAOtuB,aAAc,aAAcN,EAAMtF,KAAMmqH,IMhBnBC,CAA2BzoG,GAAU,CAAEhP,SAAU,QAG7F8L,EAAO24C,SAAStmD,IAAK,aAAc,IAAI,GAAmB2N,EAAQkD,K,MCnCrD,MAAM,WAAqB,GAIzC,wBACC,MAAO,eAiBR,mCACC,MAAMhhB,EAAIuB,KAAKuc,OAAO9d,EAEtB,MAAO,CACN,kBAAmBA,EAAG,mBACtB,aAAcA,EAAG,cACjB,qBAAsBA,EAAG,sBACzB,iBAAkBA,EAAG,kBACrB,sBAAuBA,EAAG,wBAO5B,OACC,MAGM0pH,EAiDR,SAA0B1oG,EAAQglG,GACjC,IAAM,MAAMrhH,KAASqc,EAGfglG,EAAQrhH,EAAMouG,SAClBpuG,EAAMouG,MAAQiT,EAAQrhH,EAAMouG,QAI9B,OAAO/xF,EA1DmB2oG,CAAiBb,GAH3BvnH,KAAKuc,OACYV,OAAOzd,IAAK,iBAEwC4B,KAAKqoH,8BAEzF,IAAM,MAAMjlH,KAAS+kH,EACpBnoH,KAAK28G,cAAev5G,GAUtB,cAAeA,GACd,MAAMmZ,EAASvc,KAAKuc,OAEd+rG,EAAgB,cAAellH,EAAMtF,KAE3Cye,EAAOL,GAAG+5D,iBAAiBrnE,IAAK05G,EAAersG,IAC9C,MAAM+4C,EAAUz4C,EAAO24C,SAAS92D,IAAK,cAC/Bs3B,EAAO,IAAI,GAAYzZ,GAiB7B,OAfAyZ,EAAKjsB,IAAK,CACTinB,MAAOttB,EAAMouG,MACbprB,KAAMhjF,EAAMgjF,KACZE,SAAS,EACTL,cAAc,IAGfvwD,EAAK32B,KAAM,aAAc6U,GAAIohD,EAAS,aACtCt/B,EAAK32B,KAAM,QAAS6U,GAAIohD,EAAS,QAASx2D,GAASA,IAAU4E,EAAMtF,MAEnEkC,KAAKmR,SAAUukB,EAAM,UAAW,KAC/BnZ,EAAO04C,QAAS,aAAc,CAAEz2D,MAAO4E,EAAMtF,OAC7Cye,EAAO83D,QAAQ3+C,KAAK7F,UAGd6F,KCxDK,MAAM,WAAgC,GAIpD,sBACC,MAAO,CAAE,IAMV,wBACC,MAAO,0BAMR,OACC,MAAMnZ,EAASvc,KAAKuc,OAGpB,GAAKA,EAAOtE,QAAQvO,IAAK,kBAAqB,CAC7C,MAAM6+G,EAAiBhsG,EAAOtE,QAAQ7Z,IAAK,kBAE3C4B,KAAKmR,SAAUo3G,EAAgB,OAAQzxG,KAoO1C,SAA2BsT,GAC1B,MAAM0Q,EAAc1Q,EAAUsH,qBAE9B,SAAWoJ,IAAe+sE,GAAU/sE,KAtO5B0tF,CAAkBjsG,EAAO83D,QAAQ3+C,KAAK10B,SAASopB,YACnDtT,EAAIhH,QAEH,CAAEW,SAAU,SAShBzQ,KAAKyoH,oBAAsB,IAAI30G,IAK/B9T,KAAK4/G,SAAW5/G,KAAKuc,OAAOtE,QAAQ7Z,IAAK,qBAEzC4B,KAAKkpB,GAAI,mBAAoB,KAC5BlpB,KAAK0oH,8BAGN1oH,KAAKmR,SAAUoL,EAAOL,GAAI,SAAU,KACnClc,KAAK0oH,8BAIN1oH,KAAKmR,SAAUoL,EAAOL,GAAGg6D,aAAc,mBAAoB,KAC1Dl2E,KAAK0oH,6BACH,CAAEj4G,SAAU,QAGhB,UACC7Q,MAAMsa,UAEN,IAAM,MAAMyuG,KAAiB3oH,KAAKyoH,oBAAoBp8G,SACrDs8G,EAAcjzF,KAAKxb,UAmBrB,SAAU0uG,GAAW,UAAEC,EAAS,MAAElzG,EAAK,kBAAEmzG,EAAiB,iBAAEhK,EAAmB,yBAE9E,IAAMnpG,EAAM5T,OASX,YAFA,aAAY,0BAA2B,CAAE6mH,cAK1C,MAAMrsG,EAASvc,KAAKuc,OACd9d,EAAI8d,EAAO9d,EACX0rF,EAAc,IAAI,GAAa5tE,EAAON,QAI5C,GAFAkuE,EAAY0+B,UAAYA,GAAapqH,EAAG,kBAEnCuB,KAAKyoH,oBAAoB/+G,IAAKk/G,GAOlC,MAAM,IAAI,KAAe,4BAA6B5oH,KAAM,CAAE4oH,cAG/Dz+B,EAAY9R,eAAgB1iE,EAAO4G,EAAOL,GAAG+5D,kBAE7Cj2E,KAAKyoH,oBAAoBh/G,IAAKm/G,EAAW,CACxClzF,KAAMy0D,EACN2+B,oBACAhK,qBASF,4BACC,IAAIiK,EAAyB,EACzBC,EAAwB,KACxBC,EAA2B,KAE/B,IAAM,MAAM1yD,KAAcv2D,KAAKyoH,oBAAoBp8G,SAAW,CAC7D,MAAM68G,EAAiB3yD,EAAWuyD,kBAAmB9oH,KAAKuc,OAAO83D,QAAQ3+C,KAAK10B,SAASopB,WAEvF,GAAMpqB,KAAKsvC,WAAc45E,EAIlB,GAAMlpH,KAAKuc,OAAOL,GAAGg6D,aAAa/rD,UAIlC,CACN,MAAMg/F,EAAsBD,EAAe1rG,eAAezb,OAMrDonH,EAAsBJ,IAC1BA,EAAyBI,EACzBH,EAAwBE,EACxBD,EAA2B1yD,QAbvBv2D,KAAKopH,kBAAmB7yD,IAC5Bv2D,KAAKqpH,aAAc9yD,QALfv2D,KAAKspH,oBAAqB/yD,IAC9Bv2D,KAAKqpH,aAAc9yD,GAqBjB0yD,GACJjpH,KAAKupH,aAAcN,EAA0BD,GAU/C,aAAcQ,GACbxpH,KAAK4/G,SAASz7G,OAAQqlH,EAAkB9zF,MACxC11B,KAAKsR,cAAetR,KAAK4/G,SAAU,sBAcpC,aAAc4J,EAAmBN,GAC3BlpH,KAAKopH,kBAAmBI,GAC5B,GAA6BxpH,KAAKuc,OAAQ2sG,GAC9BlpH,KAAKspH,oBAAqBE,KACtCxpH,KAAK4/G,SAAShxG,IAAK,CAClB8mB,KAAM8zF,EAAkB9zF,KACxB7K,SAAU,GAAwB7qB,KAAKuc,OAAQ2sG,GAC/CpK,iBAAkB0K,EAAkB1K,mBAOrC9+G,KAAKmR,SAAUnR,KAAK4/G,SAAU,qBAAsB,KACnD,IAAM,MAAMrpD,KAAcv2D,KAAKyoH,oBAAoBp8G,SAClD,GAAKrM,KAAKopH,kBAAmB7yD,GAAe,CAC3C,MAAM2yD,EAAiB3yD,EAAWuyD,kBAAmB9oH,KAAKuc,OAAO83D,QAAQ3+C,KAAK10B,SAASopB,WACvF,GAA6BpqB,KAAKuc,OAAQ2sG,OAY/C,kBAAmB9wC,GAClB,OAAOp4E,KAAK4/G,SAAS7B,cAAgB3lC,EAAQ1iD,KAQ9C,oBAAqB0iD,GACpB,OAAOp4E,KAAK4/G,SAASrC,QAASnlC,EAAQ1iD,OAIxC,SAAS,GAA6BnZ,EAAQ2sG,GAC7C,MAAMnJ,EAAUxjG,EAAOtE,QAAQ7Z,IAAK,qBAC9BysB,EAAW,GAAwBtO,EAAQ2sG,GAEjDnJ,EAAQ1B,eAAgBxzF,GAGzB,SAAS,GAAwBtO,EAAQ2sG,GACxC,MAAMzxC,EAAcl7D,EAAO83D,QAAQ3+C,KAC7BkvE,EAAmB,GAAiBA,iBAE1C,MAAO,CACNxjG,OAAQq2E,EAAY9hD,aAAa6L,aAAc0nF,GAC/ChnC,UAAW,CACV0iB,EAAiBO,gBACjBP,EAAiBU,oBACjBV,EAAiBW,oBACjBX,EAAiBE,gBACjBF,EAAiBK,oBACjBL,EAAiBM,oBACjB4D,KCjQY,MAAM,WAAqBzb,GAIzC,YAAa9wE,GACZ3c,MAAO2c,GAQPvc,KAAKypH,eAAiB,GAMvB,WASA,WAAYp4G,GAGX,OAFgBrR,KAAK0pH,0BAENz0D,QAAS5jD,GAQzB,qBAAsB2jD,GACrBh1D,KAAKypH,eAAexmH,KAAM+xD,GAG1BA,EAAQ9rC,GAAI,mBAAoB,IAAMlpB,KAAK0iG,iBAE3C1iG,KAAK0iG,gBAQN,gBACC1iG,KAAKsvC,YAActvC,KAAK0pH,0BASzB,0BACC,OAAO1pH,KAAKypH,eAAerzG,KAAM4+C,GAAWA,EAAQ1lB,YC5EvC,MAAM,WAAsB,GAI1C,wBACC,MAAO,gBAMR,OACC,MAAM/yB,EAASvc,KAAKuc,OAEpBA,EAAO24C,SAAStmD,IAAK,SAAU,IAAI,GAAc2N,IACjDA,EAAO24C,SAAStmD,IAAK,UAAW,IAAI,GAAc2N,KCrCrC,+YCAA,yYCwBA,MAAM,WAAiB,GAIrC,wBACC,MAAO,WAMR,OACC,MAAMA,EAASvc,KAAKuc,OACdN,EAASM,EAAON,OAChBxd,EAAI8d,EAAO9d,EAEXkrH,EAAoD,OAA9B1tG,EAAOX,oBAA+BsuG,GAAaC,GACzEC,EAAqD,OAA9B7tG,EAAOX,oBAA+BuuG,GAAcD,GAEjF5pH,KAAK+pH,cAAe,SAAUtrH,EAAG,mBAAqBkrH,GACtD3pH,KAAK+pH,cAAe,UAAWtrH,EAAG,mBAAqBqrH,GAWxD,cAAe/0D,EAAarkC,EAAO01D,GAClC,MAAM7pE,EAASvc,KAAKuc,OAEpBA,EAAOL,GAAG+5D,iBAAiBrnE,IAAKmmD,EAAa94C,IAC5C,MAAM+4C,EAAUz4C,EAAO24C,SAAS92D,IAAK22D,GAC/Br/B,EAAO,IAAI,GAAYzZ,GAe7B,OAbAyZ,EAAKjsB,IAAK,CACTinB,QACA01D,OACAE,SAAS,IAGV5wD,EAAK32B,KAAM,OAAQ,aAAc6U,GAAIohD,EAAS,QAAS,aAEvDh1D,KAAKmR,SAAUukB,EAAM,UAAW,KAC/BnZ,EAAO04C,QAASF,GAChBx4C,EAAO83D,QAAQ3+C,KAAK7F,UAGd6F,KCtDK,MAAM,WAAsB,GAC1C,YAAaA,GACZ91B,MAAO81B,GAEP11B,KAAK8zC,aAAe,QAGrB,WAAYJ,GACX1zC,KAAKqU,KAAMq/B,EAASzzC,KAAMyzC,I,MCOb,MAAM,WAAqB,GAUzC,YAAaz3B,EAAQ6yF,GACpBlvG,MAAOqc,GAEP,MAAMxd,EAAIwd,EAAOxd,EAQjBuB,KAAKk2E,aAAe,IAAI,GAQxBl2E,KAAKw0E,WAAa,IAAI,GAOtBx0E,KAAKgqH,aAAehqH,KAAKiqH,kBAOzBjqH,KAAK08G,eAAiB18G,KAAK28G,cAAel+G,EAAG,QAAUm+G,GAAW,kBAClE58G,KAAK08G,eAAez8G,KAAO,SAO3BD,KAAK68G,iBAAmB78G,KAAK28G,cAAel+G,EAAG,UAAY,GAAY,mBAAoB,UAW3FuB,KAAKkqH,yBAA2BlqH,KAAKmqH,+BAAgCrb,GAQrE9uG,KAAK8H,SAAW9H,KAAKoqH,oBAAqBtb,EAAYb,kBAStDjuG,KAAK88G,YAAc,IAAI,GASvB98G,KAAKymF,aAAe,IAAIxG,GAAa,CACpCE,WAAYngF,KAAK88G,YACjB5mC,aAAcl2E,KAAKk2E,aACnBgK,iBAAkBlgF,KAAKw0E,WACvB5xC,QAAS,CAER8jD,cAAe,cAGfC,UAAW,SAIb,MAAM6xB,EAAY,CAAE,KAAM,eAAgB,sBAErC1J,EAAYb,iBAAiBlsG,QACjCy2G,EAAUv1G,KAAM,+BAAgC,oBAGjDjD,KAAKs+E,YAAa,CACjBl2E,IAAK,OAEL9E,WAAY,CACXy6E,MAAOy6B,EAGPxyB,SAAU,MAGXl+E,SAAU9H,KAAK8H,WAGhBq0G,GAA6Bn8G,MAW9B,4BACC,OAAOmJ,MAAMiK,KAAMpT,KAAKkqH,0BAA2B7yG,OAAQ,CAAEgzG,EAAaC,KACzED,EAAaC,EAAaxsH,MAASwsH,EAAavF,KACzCsF,GACL,IAMJ,SACCzqH,MAAM43B,SAEN+kF,GAAe,CACd7mF,KAAM11B,OAGY,CAClBA,KAAKgqH,gBACFhqH,KAAKkqH,yBACRlqH,KAAK08G,eACL18G,KAAK68G,kBAGKp5G,QAASs5G,IAEnB/8G,KAAK88G,YAAYluG,IAAKmuG,GAGtB/8G,KAAKk2E,aAAatnE,IAAKmuG,EAAEn+F,WAI1B5e,KAAKw0E,WAAWrjE,SAAUnR,KAAK4e,SAMhC,QACC5e,KAAKymF,aAAaG,aASnB,kBACC,MAAMnoF,EAAIuB,KAAKic,OAAOxd,EAChB+9G,EAAe,IAAI,GAAkBx8G,KAAKic,OAAQ8/F,IAIxD,OAFAS,EAAa9rF,MAAQjyB,EAAG,YAEjB+9G,EAaR,cAAe9rF,EAAO01D,EAAMhgE,EAAWrU,GACtC,MAAM8xF,EAAS,IAAI,GAAY7jG,KAAKic,QAkBpC,OAhBA4nF,EAAOp6F,IAAK,CACXinB,QACA01D,OACAE,SAAS,IAGVud,EAAOzpB,eAAgB,CACtB92E,WAAY,CACXy6E,MAAO33D,KAIJrU,GACJ8xF,EAAOtyE,SAAU,WAAY3d,GAAI5T,KAAM+R,GAGjC8xF,EAWR,+BAAgCiL,GAC/B,MAAMyb,EAAWvqH,KAAKw9E,mBAEtB,IAAM,MAAM2wB,KAAmBW,EAAYb,iBAAmB,CAC7D,MAAMqc,EAAe,IAAI,GAAkBtqH,KAAKic,QAEhDquG,EAAa7gH,IAAK,CACjB3L,KAAMqwG,EAAgB7rG,GACtBouB,MAAOy9E,EAAgBz9E,MACvBm0F,UAAU,IAGXyF,EAAavrH,KAAM,QAASopB,OAAQ,CAAEgmF,EAAiBW,GAAe,QAAS,CAAE0b,EAAgB1F,SACxEx+G,IAAjBw+G,QAAiDx+G,IAAnBkkH,EAA+Brc,EAAgBptF,aAAeypG,GAGpGF,EAAaphG,GAAI,UAAW,KAC3BilF,EAAgB1kG,IAAK,SAAU6gH,EAAavF,QAG7CwF,EAAS37G,IAAK07G,GAGf,OAAOC,EAeR,oBAAqBtc,GACpB,MAAMnmG,EAAW9H,KAAKw9E,mBAItB,GAFA11E,EAAS8G,IAAK5O,KAAKgqH,cAEd/b,EAAiBlsG,OAAS,CAC9B,MAAM0oH,EAAwB,IAAI,GAElCA,EAAsBnsC,YAAa,CAClCl2E,IAAK,KACLN,SAAU9H,KAAKkqH,yBAAyB7/G,IAAKigH,IAAgB,CAC5DliH,IAAK,KACLN,SAAU,CAAEwiH,GACZhnH,WAAY,CACXy6E,MAAO,CACN,KACA,qBAIHz6E,WAAY,CACXy6E,MAAO,CACN,KACA,WACA,cAIHj2E,EAAS8G,IAAK67G,GAMf,OAHA3iH,EAAS8G,IAAK5O,KAAK08G,gBACnB50G,EAAS8G,IAAK5O,KAAK68G,kBAEZ/0G,G,MClTM,MAAM,WAAwB,GAI5C,YAAamU,GACZrc,MAAOqc,GAEP,MAAMxd,EAAIwd,EAAOxd,EAQjBuB,KAAKk2E,aAAe,IAAI,GAQxBl2E,KAAKw0E,WAAa,IAAI,GAOtBx0E,KAAK0qH,kBAAoB1qH,KAAK2qH,uBAO9B3qH,KAAK4qH,iBAAmB5qH,KAAK28G,cAAel+G,EAAG,UCpElC,g0BDoE0D,UAOvEuB,KAAK6qH,eAAiB7qH,KAAK28G,cAAel+G,EAAG,aE3EhC,kfF2E2D,QAQxEuB,KAAKyJ,IAAK,QASVzJ,KAAK88G,YAAc,IAAI,GASvB98G,KAAKymF,aAAe,IAAIxG,GAAa,CACpCE,WAAYngF,KAAK88G,YACjB5mC,aAAcl2E,KAAKk2E,aACnBgK,iBAAkBlgF,KAAKw0E,WACvB5xC,QAAS,CAER8jD,cAAe,cAGfC,UAAW,SAIb3mF,KAAKs+E,YAAa,CACjBl2E,IAAK,MAEL9E,WAAY,CACXy6E,MAAO,CACN,KACA,kBACA,sBAIDiI,SAAU,MAGXl+E,SAAU,CACT9H,KAAK0qH,kBACL1qH,KAAK6qH,eACL7qH,KAAK4qH,oBAQR,SACChrH,MAAM43B,SAEa,CAClBx3B,KAAK0qH,kBACL1qH,KAAK6qH,eACL7qH,KAAK4qH,kBAGKnnH,QAASs5G,IAEnB/8G,KAAK88G,YAAYluG,IAAKmuG,GAGtB/8G,KAAKk2E,aAAatnE,IAAKmuG,EAAEn+F,WAI1B5e,KAAKw0E,WAAWrjE,SAAUnR,KAAK4e,SAMhC,QACC5e,KAAKymF,aAAaG,aAYnB,cAAel2D,EAAO01D,EAAMr0E,GAC3B,MAAM8xF,EAAS,IAAI,GAAY7jG,KAAKic,QAUpC,OARA4nF,EAAOp6F,IAAK,CACXinB,QACA01D,OACAE,SAAS,IAGVud,EAAOtyE,SAAU,WAAY3d,GAAI5T,KAAM+R,GAEhC8xF,EASR,uBACC,MAAMA,EAAS,IAAI,GAAY7jG,KAAKic,QAC9Bld,EAAOiB,KAAKq+E,aACZ5/E,EAAIuB,KAAKvB,EA4Bf,OA1BAolG,EAAOp6F,IAAK,CACXo7G,UAAU,EACVv+B,QAAS7nF,EAAG,0BAGbolG,EAAOzpB,eAAgB,CACtB92E,WAAY,CACXy6E,MAAO,CACN,KACA,4BAEDyvB,KAAMzuG,EAAK6U,GAAI,OAAQ45F,GAAQA,GAAQE,GAAeF,IACtDpsG,OAAQ,SACRgvG,IAAK,yBAIPvM,EAAO9kG,KAAM,SAAU6U,GAAI5T,KAAM,OAAQwtG,GACjCA,GAAQ/uG,EAAG,yBAGnBolG,EAAO9kG,KAAM,aAAc6U,GAAI5T,KAAM,OAAQwtG,KAAUA,GAEvD3J,EAAO1pB,SAAS/xE,IAAM,IACtBy7F,EAAO1pB,SAASG,eAAiB,GAE1BupB,GGlMM,MAAM,WAAe,GAInC,sBACC,MAAO,CAAE,IAMV,wBACC,MAAO,SAMR,OACC,MAAMtnF,EAASvc,KAAKuc,OAEpBA,EAAO83D,QAAQ3+C,KAAKknB,YAAa,IAOjC58C,KAAK8qH,YAAc9qH,KAAK+qH,qBAOxB/qH,KAAKgrH,SAAWhrH,KAAKirH,kBAQrBjrH,KAAK4/G,SAAWrjG,EAAOtE,QAAQ7Z,IAAK,IAGpC4B,KAAKkrH,2BAGLlrH,KAAKmrH,iCAGL5uG,EAAO+3D,WAAWjV,IAAK,mBAAoB+rD,kBAAmB,CAC7DpiE,MA/DkC,UAgElCtzB,KAAM,CACL/W,QAAS,CAAE,6BAKbpC,EAAO+3D,WAAWjV,IAAK,mBAAoBgsD,gBAAiB,CAC3DriE,MAvEkC,UAwElCtzB,KAAM,CACL53B,KAAM,OACN6gB,QAAS,CAAE,yBAA0B,uCAQxC,UACC/e,MAAMsa,UAGNla,KAAKgrH,SAAS9wG,UASf,qBACC,MAAMqC,EAASvc,KAAKuc,OACduuG,EAAc,IAAI,GAAiBvuG,EAAON,QAC1C6yF,EAAcvyF,EAAO24C,SAAS92D,IAAK,QACnCktH,EAAgB/uG,EAAO24C,SAAS92D,IAAK,UA6B3C,OA3BA0sH,EAAY/rH,KAAM,QAAS6U,GAAIk7F,EAAa,SAC5Cgc,EAAYD,eAAe9rH,KAAM,aAAc6U,GAAIk7F,GACnDgc,EAAYF,iBAAiB7rH,KAAM,aAAc6U,GAAI03G,GAGrDtrH,KAAKmR,SAAU25G,EAAa,OAAQ,KACnC9qH,KAAKurH,iBAINvrH,KAAKmR,SAAU25G,EAAa,SAAU,KACrCvuG,EAAO04C,QAAS,UAChBj1D,KAAKwrH,YAINV,EAAYt2C,WAAW/qE,IAAK,MAAO,CAAE9J,EAAMu2C,KAC1Cl2C,KAAKwrH,UACLt1E,MAID40E,EAAYt2C,WAAW/qE,I5E1HK,S4E0HgB,CAAE9J,EAAMu2C,KACnDl2C,KAAKurH,eACLr1E,MAGM40E,EASR,kBACC,MAAMvuG,EAASvc,KAAKuc,OACduyF,EAAcvyF,EAAO24C,SAAS92D,IAAK,QACnC0vG,EAAkBvxF,EAAOV,OAAOzd,IAAK,wBAErC4sH,EAAW,IAAI,GAAczuG,EAAON,OAAQ6yF,GA2BlD,OAzBAkc,EAAShB,aAAa3O,UAAUt8G,KAAM,SAAU6U,GAAIk7F,EAAa,SAGjEkc,EAAShB,aAAajrH,KAAM,cAAe6U,GAAIk7F,EAAa,YAAatwG,IAAUA,GACnFwsH,EAAStO,eAAe39G,KAAM,aAAc6U,GAAIk7F,GAGhD9uG,KAAKmR,SAAU65G,EAAU,SAAU,KAClC,MAAM,MAAExsH,GAAUwsH,EAAShB,aAAa3O,UAAUz8F,QAC5C6sG,EAAY7d,GAA6BpvG,EAAOsvG,GACtDvxF,EAAO04C,QAAS,OAAQw2D,EAAWT,EAASU,6BAC5C1rH,KAAK2rH,mBAIN3rH,KAAKmR,SAAU65G,EAAU,SAAU,KAClChrH,KAAK2rH,mBAINX,EAASx2C,WAAW/qE,IAAK,MAAO,CAAE9J,EAAMu2C,KACvCl2C,KAAK2rH,iBACLz1E,MAGM80E,EASR,2BACC,MAAMzuG,EAASvc,KAAKuc,OACduyF,EAAcvyF,EAAO24C,SAAS92D,IAAK,QACnCK,EAAI8d,EAAO9d,EAGjB8d,EAAOi4D,WAAW/qE,I5EvLU,S4EuLW,CAAEsqE,EAAY79B,KAEpDA,IAEK44D,EAAYx/D,WAChBtvC,KAAK4rH,SAAS,KAIhBrvG,EAAOL,GAAG+5D,iBAAiBrnE,IAAK,OAAQqN,IACvC,MAAM4nF,EAAS,IAAI,GAAY5nF,GAgB/B,OAdA4nF,EAAOv0D,WAAY,EACnBu0D,EAAOnzE,MAAQjyB,EAAG,QAClBolG,EAAOzd,KC7NK,gnBD8NZyd,EAAOjvE,U5EtMoB,S4EuM3BivE,EAAOvd,SAAU,EACjBud,EAAO5d,cAAe,EAGtB4d,EAAO9kG,KAAM,aAAc6U,GAAIk7F,EAAa,aAC5CjL,EAAO9kG,KAAM,QAAS6U,GAAIk7F,EAAa,QAAStwG,KAAWA,GAG3DwB,KAAKmR,SAAU0yF,EAAQ,UAAW,IAAM7jG,KAAK4rH,SAAS,IAE/C/nB,IAUT,iCACC,MAAMtmC,EAAev9D,KAAKuc,OAAO83D,QAAQ3+C,KAAK10B,SAI9ChB,KAAKmR,SAAUosD,EAAc,QAAS,KAClBv9D,KAAK6rH,2BAIvB7rH,KAAK4rH,YAKP5rH,KAAKuc,OAAOi4D,WAAW/qE,IAAK,MAAO,CAAE9J,EAAMu2C,KACrCl2C,KAAK8rH,qBAAuB9rH,KAAK8qH,YAAY50C,aAAa/rD,YAC9DnqB,KAAK8qH,YAAYj7F,QACjBqmB,MAEC,CAIFzlC,SAAU,SAIXzQ,KAAKuc,OAAOi4D,WAAW/qE,IAAK,MAAO,CAAE9J,EAAMu2C,KACrCl2C,KAAK+rH,eACT/rH,KAAKwrH,UACLt1E,OAKF6wC,GAAqB,CACpBx1E,QAASvR,KAAKgrH,SACdhkC,UAAW,IAAMhnF,KAAKgsH,aACtB/kC,gBAAiB,CAAEjnF,KAAK4/G,SAASlqF,KAAK9W,SACtC1N,SAAU,IAAMlR,KAAKwrH,YASvB,kBACMxrH,KAAKisH,oBAIVjsH,KAAK4/G,SAAShxG,IAAK,CAClB8mB,KAAM11B,KAAK8qH,YACXjgG,SAAU7qB,KAAKksH,4BASjB,eACC,GAAKlsH,KAAKmsH,eACT,OAGD,MACMrd,EADS9uG,KAAKuc,OACO24C,SAAS92D,IAAK,QAEzC4B,KAAKgrH,SAAS5O,wBAEdp8G,KAAK4/G,SAAShxG,IAAK,CAClB8mB,KAAM11B,KAAKgrH,SACXngG,SAAU7qB,KAAKksH,4BAIXlsH,KAAK4/G,SAAS7B,cAAgB/9G,KAAKgrH,UACvChrH,KAAKgrH,SAAShB,aAAa3O,UAAUS,SAGtC97G,KAAKgrH,SAAS1O,uBAQdt8G,KAAKgrH,SAAShB,aAAa3O,UAAUz8F,QAAQpgB,MAAQswG,EAAYtwG,OAAS,GAY3E,iBACC,MAAMswG,EAAc9uG,KAAKuc,OAAO24C,SAAS92D,IAAK,QAI9C0wG,EAAYsd,oCAEe9lH,IAAtBwoG,EAAYtwG,MAChBwB,KAAKqsH,kBAELrsH,KAAKwrH,UASP,kBACMxrH,KAAKmsH,iBAGTnsH,KAAKgrH,SAAStO,eAAe7sF,QAE7B7vB,KAAK4/G,SAASz7G,OAAQnE,KAAKgrH,UAI3BhrH,KAAKuc,OAAO83D,QAAQ3+C,KAAK7F,QAEzB7vB,KAAKssH,4BAUP,QAASC,GAAe,GAEjBvsH,KAAK6rH,2BAiBL7rH,KAAK8rH,mBACT9rH,KAAKurH,eAILvrH,KAAKwsH,kBAIDD,GACJvsH,KAAK4/G,SAAShC,UAAW,UAxB1B59G,KAAKysH,2BAELzsH,KAAKwsH,kBAGAD,GACJvsH,KAAK4/G,SAAShC,UAAW,QAG1B59G,KAAKurH,gBAoBNvrH,KAAK0sH,mBAUN,UACC,IAAM1sH,KAAKgsH,aACV,OAGD,MAAMzvG,EAASvc,KAAKuc,OAEpBvc,KAAKsR,cAAeiL,EAAOL,GAAI,UAC/Blc,KAAKsR,cAAetR,KAAK4/G,SAAU,sBAInCrjG,EAAO83D,QAAQ3+C,KAAK7F,QAGpB7vB,KAAKqsH,kBAGLrsH,KAAK4/G,SAASz7G,OAAQnE,KAAK8qH,aAE3B9qH,KAAKssH,2BAWN,mBACC,MAAM/vG,EAASvc,KAAKuc,OACdghD,EAAehhD,EAAO83D,QAAQ3+C,KAAK10B,SAEzC,IAAI2rH,EAAmB3sH,KAAK6rH,0BACxBe,EAAsBC,IAE1B,MAAM1nH,EAAS,KACd,MAAM2nH,EAAe9sH,KAAK6rH,0BACpBnoF,EAAkBmpF,IAYjBF,IAAqBG,IACxBH,GAAoBjpF,IAAoBkpF,EAC3C5sH,KAAKwrH,UAMIxrH,KAAK+rH,cAId/rH,KAAK4/G,SAASvB,eAAgBr+G,KAAKksH,2BAGpCS,EAAmBG,EACnBF,EAAsBlpF,GAGvB,SAASmpF,IACR,OAAOtvD,EAAanzC,UAAUyF,MAAMrS,eAClCsiB,UACA1pB,KAAM7D,GAAQA,EAAKpS,GAAI,YAG1BH,KAAKmR,SAAUoL,EAAOL,GAAI,SAAU/W,GACpCnF,KAAKmR,SAAUnR,KAAK4/G,SAAU,qBAAsBz6G,GAUrD,qBACC,OAAOnF,KAAK4/G,SAASrC,QAASv9G,KAAKgrH,UAUpC,yBACC,OAAOhrH,KAAK4/G,SAASrC,QAASv9G,KAAK8qH,aAWpC,yBACC,OAAO9qH,KAAK4/G,SAAS7B,cAAgB/9G,KAAK8qH,YAU3C,mBACC,OAAO9qH,KAAKmsH,gBAAkBnsH,KAAKisH,mBAWpC,mBAGC,OAFoBjsH,KAAK4/G,SAAS7B,aAEZ/9G,KAAKgrH,UAAYhrH,KAAK8rH,mBAa7C,0BACC,MAAMp2F,EAAO11B,KAAKuc,OAAO83D,QAAQ3+C,KAC3BszB,EAAQhpD,KAAKuc,OAAOysC,MACpBuU,EAAe7nC,EAAK10B,SAC1B,IAAII,EAAS,KAEb,GAAK4nD,EAAM7D,QAAQz7C,IAtjBgB,WAsjBsB,CAExD,MAAMqjH,EAAqB5jH,MAAMiK,KAAMpT,KAAKuc,OAAO83D,QAAQ1wB,OAAOiL,qBAxjBhC,YAyjB5Bj0B,EAAWjF,EAAK4Q,YACrB5Q,EAAK4mC,qBAAsBywD,EAAoB,IAC/Cr3F,EAAKinC,oBAAqBowD,EAAoBA,EAAmBhrH,OAAS,KAG3EX,EAASs0B,EAAKC,aAAa2nB,eAAgB3iB,OACrC,CACN,MAAMqyF,EAAahtH,KAAK6rH,0BAClB58F,EAAQsuC,EAAanzC,UAAUmF,gBAErCnuB,EAAS4rH,EAERt3F,EAAKC,aAAa6L,aAAcwrF,GAEhCt3F,EAAKC,aAAa2nB,eAAgBruB,GAGpC,MAAO,CAAE7tB,UAcV,0BACC,MAAMs0B,EAAO11B,KAAKuc,OAAO83D,QAAQ3+C,KAC3BtL,EAAYsL,EAAK10B,SAASopB,UAEhC,GAAKA,EAAUqD,YACd,OAAOw/F,GAAyB7iG,EAAUoH,oBACpC,CAGN,MAAMvC,EAAQ7E,EAAUmF,gBAAgBa,aAClC88F,EAAYD,GAAyBh+F,EAAMpO,OAC3CssG,EAAUF,GAAyBh+F,EAAMnO,KAE/C,OAAMosG,GAAaA,GAAaC,GAK3Bz3F,EAAKg/B,cAAew4D,GAAY98F,aAAa9D,QAAS2C,GACnDi+F,EALA,MAmBV,2BACC,MAAMlkE,EAAQhpD,KAAKuc,OAAOysC,MAE1BA,EAAM5L,OAAQprB,IACb,MAAM/C,EAAQ+5B,EAAMhoD,SAASopB,UAAUmF,gBAEvC,GAAKy5B,EAAM7D,QAAQz7C,IA/nBe,WAgoBjCsoB,EAAOowC,aAhoB0B,UAgoBkB,CAAEnzC,eAErD,GAAKA,EAAMpO,MAAM+K,QAAU,CAC1B,MACMwhG,EAkDX,SAASC,EAAmBp+F,EAAOY,EAAOmC,GACzC,MAAMs7F,EAAgB,CAAEr+F,EAAMpO,MAAMhR,KAAM,GAAM,EAAG,GAC7C09G,EAAoBv7F,EAAO+wC,uBAAwB9zC,EAAMpO,MAAMhkB,KAAMywH,EAAe,UACpFE,EAAYx7F,EAAOsU,YAAainF,EAAmBt+F,EAAMnO,KAG/D,GAAK0sG,EAAU3sG,MAAMhR,KAAM,GAAMof,EAAMnO,IAAIjR,KAAM,GAChD,OAAOmiB,EAAOsU,YAAazW,GAG5B,GAAK09F,EAAkBrhG,WAAaqhG,EAAkB3hG,QACrD,OAAOyhG,EAAmBG,EAAW39F,EAAOmC,GAG7C,OAAOw7F,EAhEoBH,CAAmBp+F,EAD5B+5B,EAAMhoD,SAASopB,UAAUyF,MACiBmC,GAExDA,EAAOqwC,UAtoByB,UAsoBgB,CAC/CF,gBAAgB,EAChBX,aAAa,EACbvyC,MAAOm+F,SAGRp7F,EAAOqwC,UA5oByB,UA4oBgB,CAC/CF,gBAAgB,EAChBX,aAAa,EACbvyC,YAYL,2BACC,MAAM+5B,EAAQhpD,KAAKuc,OAAOysC,MAErBA,EAAM7D,QAAQz7C,IA9pBgB,YA+pBlCs/C,EAAM5L,OAAQprB,IACbA,EAAOy7F,aAhqB0B,cA2qBrC,SAASR,GAAyBpiG,GACjC,OAAOA,EAASrN,eAAepH,KAAMikB,IAAYqzF,O5EnqBnBn7G,E4EmqBkC8nB,G5ElqBpDl6B,GAAI,uBAA0BoS,EAAKiY,kBAAmB,QAD5D,IAAwBjY,I8EGhB,SAASo7G,GAAiB1+F,EAAO+5B,GAC/C,IAAInoC,EAAQoO,EAAMpO,MAalB,MAAO,CAAE0xB,KAXIppC,MAAMiK,KAAM6b,EAAMq4B,YAAajwC,OAAQ,CAAEqqF,EAAWnvF,IAExDA,EAAKpS,GAAI,UAAaoS,EAAKpS,GAAI,cAMhCuhG,EAAYnvF,EAAK5S,MALvBkhB,EAAQmoC,EAAM2T,oBAAqBpqD,GAE5B,IAIN,IAEY0c,MAAO+5B,EAAM1iB,YAAazlB,EAAOoO,EAAMnO,MC1BxC,MAAM,GAOpB,YAAakoC,EAAOo4C,GAOnBphG,KAAKgpD,MAAQA,EAcbhpD,KAAKohG,aAAeA,EAQpBphG,KAAK4tH,UAAW,EAgBhB5tH,KAAKyJ,IAAK,aAAa,GAGvBzJ,KAAKkpB,GAAI,mBAAoB,KACvBlpB,KAAKsvC,UACTtvC,KAAK6tH,mBAEL7tH,KAAKsR,cAAe03C,EAAMhoD,SAASopB,WACnCpqB,KAAKsR,cAAe03C,EAAMhoD,aAI5BhB,KAAK6tH,kBAQN,kBACC,MACM7sH,EADQhB,KAAKgpD,MACIhoD,SAEvBhB,KAAKmR,SAAUnQ,EAASopB,UAAW,eAAgB,CAAEtT,GAAOoxC,mBAErDA,IAKAlnD,EAASopB,UAAUqD,YASzBztB,KAAK8tH,6BAA8B,aAR7B9tH,KAAK4tH,WACT5tH,KAAKqU,KAAM,aACXrU,KAAK4tH,UAAW,MASnB5tH,KAAKmR,SAAUnQ,EAAU,cAAe,CAAE8V,EAAKq0C,KAC3B,eAAdA,EAAMlrD,MAIXD,KAAK8tH,6BAA8B,OAAQ,CAAE3iE,YAe/C,6BAA8B4iE,EAAQpuH,EAAO,IAC5C,MAAMqpD,EAAQhpD,KAAKgpD,MAEb5+B,EADW4+B,EAAMhoD,SACIopB,UAErB4jG,EAAuBhlE,EAAM1iB,YAAa0iB,EAAMoI,iBAAkBhnC,EAAUyF,MAAM9S,OAAQ,GAAKqN,EAAUyF,QAEzG,KAAE0iB,EAAI,MAAEtjB,GAAU0+F,GAAiBK,EAAsBhlE,GAEzDilE,EAAajuH,KAAKohG,aAAc7uD,GAQtC,IANM07E,GAAcjuH,KAAK4tH,UACxB5tH,KAAKqU,KAAM,aAGZrU,KAAK4tH,WAAaK,EAEbA,EAAa,CACjB,MAAMC,EAAYjwH,OAAO4nC,OAAQlmC,EAAM,CAAE4yC,OAAMtjB,UAGrB,iBAAdg/F,GACXhwH,OAAO4nC,OAAQqoF,EAAWD,GAG3BjuH,KAAKqU,KAAM,WAAY05G,EAAWG,KAKrC15G,GAAK,GAAa,IC1JlB,MAGM25G,GAAc,IAAIlkH,OAEvB,4QA6BM,KASQ,MAAM,WAAiB,GAIrC,wBACC,MAAO,WAMR,OACC,MACMmgB,EADSpqB,KAAKuc,OACKysC,MAAMhoD,SAASopB,UAExCA,EAAUlB,GAAI,eAAgB,KAE7BlpB,KAAKsvC,WAAallB,EAAU+E,OAAOpS,OAAO5c,GAAI,UAAW,eAG1DH,KAAKouH,wBAMN,YACCpuH,KAAKquH,uBACLruH,KAAKsuH,4BAQN,wBACC,MAAM/xG,EAASvc,KAAKuc,OAEdgyG,EAAU,IAAI,GAAahyG,EAAOysC,MAAOzW,IAE9C,IAoIH,SAAgCA,GAC/B,OAAOA,EAAKxwC,OAzN6B,GAyN6C,MAA5BwwC,EAAMA,EAAKxwC,OAAS,IAA2C,MAA5BwwC,EAAMA,EAAKxwC,OAAS,GArIzGysH,CAAuBj8E,GAC5B,OAID,MAAMstD,EAAM4uB,GAAiBl8E,EAAKlgC,OAAQ,EAAGkgC,EAAKxwC,OAAS,IAE3D,OAAK89F,EACG,CAAEA,YADV,IAKK3yF,EAAQqP,EAAOtE,QAAQ7Z,IAAK,SAElCmwH,EAAQrlG,GAAI,eAAgB,CAAEpS,EAAKnX,KAClC,MAAM,MAAEwrD,EAAK,MAAEl8B,EAAK,IAAE4wE,GAAQlgG,EAE9B,IAAMuN,EAAMmkG,QAASlmD,GACpB,OAGD,MAAMujE,EAAUz/F,EAAMnO,IAAIwN,cAAe,GACnCqgG,EAAYD,EAAQpgG,cAAeuxE,EAAI99F,QAEvCysG,EAAYjyF,EAAOysC,MAAM1iB,YAAaqoF,EAAWD,GAEvD1uH,KAAK4uH,eAAgB/uB,EAAK2O,KAG3B+f,EAAQxvH,KAAM,aAAc6U,GAAI5T,MAQjC,uBACC,MAAMuc,EAASvc,KAAKuc,OACdysC,EAAQzsC,EAAOysC,MACfm7D,EAAe5nG,EAAO24C,SAAS92D,IAAK,SAEpC+lH,GAINA,EAAaj7F,GAAI,UAAW,KAC3B,MAAM2B,EAAWm+B,EAAMhoD,SAASopB,UAAUoH,mBAE1C,IAAM3G,EAAS9N,OAAOoR,gBACrB,OAGD,MAAM4gD,EAAe/lB,EAAM0L,cAAe7pC,EAAS9N,OAAOoR,iBAE1DnuB,KAAK6uH,8BAA+B9/C,KAStC,4BACC,MAAMxyD,EAASvc,KAAKuc,OACdysC,EAAQzsC,EAAOysC,MAEf8lE,EAAoBvyG,EAAO24C,SAAS92D,IAAK,cAEzC0wH,GAINA,EAAkB5lG,GAAI,UAAW,KAChC,MAAM2B,EAAWm+B,EAAMhoD,SAASopB,UAAUoH,mBAEpCu9C,EAAe/lB,EAAM1iB,YAC1B0iB,EAAMoI,iBAAkBvmC,EAAS9N,OAAQ,GACzC8N,EAASyD,cAAe,IAGzBtuB,KAAK6uH,8BAA+B9/C,KAUtC,8BAA+BA,GAC9B,MAAM/lB,EAAQhpD,KAAKuc,OAAOysC,OACpB,KAAEzW,EAAI,MAAEtjB,GAAU0+F,GAAiB5+C,EAAc/lB,GAEjD62C,EAAM4uB,GAAiBl8E,GAE7B,GAAKstD,EAAM,CACV,MAAM2O,EAAYxlD,EAAM1iB,YACvBrX,EAAMnO,IAAIwN,cAAeuxE,EAAI99F,QAC7BktB,EAAMnO,KAGP9gB,KAAK4uH,eAAgB/uB,EAAK2O,IAW5B,eAAgBX,EAAM5+E,GACrB,MAAM+5B,EAAQhpD,KAAKuc,OAAOysC,MAEpBhpD,KAAKsvC,WAwBb,SAA+BrgB,EAAO+5B,GACrC,OAAOA,EAAMC,OAAOo5C,0BAA2Br5C,EAAMsL,gBAAiBrlC,GAAS,YAzBrD8/F,CAAsB9/F,EAAO+5B,IAKtDA,EAAMqC,cAAer5B,IACpB,MAAM87E,EAAkB9tG,KAAKuc,OAAOV,OAAOzd,IAAK,wBAC1CqtH,EAAY7d,GAA6BC,EAAMC,GACrD97E,EAAOtuB,aAAc,WAAY+nH,EAAWx8F,MAU/C,SAASw/F,GAAiBl8E,GACzB,MAAM72B,EAAQyyG,GAAYtkH,KAAM0oC,GAEhC,OAAO72B,EAAQA,EA3LW,GA2LmB,KC5N/B,MAAM,WAAoB2xE,GAOxC,YAAa9wE,EAAQtc,GACpBL,MAAO2c,GAQPvc,KAAKC,KAAOA,EAcb,UACCD,KAAKxB,MAAQwB,KAAKyiG,YAClBziG,KAAKsvC,UAAYtvC,KAAK0iG,gBAQvB,UACC,MAAM15C,EAAQhpD,KAAKuc,OAAOysC,MACpBhoD,EAAWgoD,EAAMhoD,SACjB2hG,EAASx5F,MAAMiK,KAAMpS,EAASopB,UAAU4/B,qBAC5ChmD,OAAQykD,GAASumE,GAAwBvmE,EAAOO,EAAMC,SAGlDgmE,GAAyB,IAAfjvH,KAAKxB,MAGrBwqD,EAAM5L,OAAQprB,IAGb,GAAKi9F,EAAU,CAEd,IAAI1jG,EAAOo3E,EAAQA,EAAO5gG,OAAS,GAAImsB,YACnCghG,EAAgBh0G,OAAOkhB,kBACvBkpB,EAAU,GAkDd,KAAQ/5B,GAAqB,YAAbA,EAAKztB,MAA4D,IAAtCytB,EAAKnM,aAAc,eAAuB,CAGpF,MAAMwqG,EAASr+F,EAAKnM,aAAc,cAG7BwqG,EAASsF,IAEbA,EAAgBtF,GAKjB,MAAMuF,EAAYvF,EAASsF,EAK3B5pE,EAAQriD,KAAM,CAAE2b,QAAS2M,EAAM6jG,WAAYD,IAG3C5jG,EAAOA,EAAK2C,YAGbo3B,EAAUA,EAAQxlB,UAElB,IAAM,MAAMz9B,KAAQijD,EACnBtzB,EAAOtuB,aAAc,aAAcrB,EAAK+sH,WAAY/sH,EAAKuc,SAqB3D,IAAMqwG,EAAU,CAGf,IAAII,EAAen0G,OAAOkhB,kBAE1B,IAAM,MAAM/5B,KAAQsgG,EACdtgG,EAAKlC,GAAI,UAAW,aAAgBkC,EAAK+c,aAAc,cAAiBiwG,IAC5EA,EAAehtH,EAAK+c,aAAc,eAKpCiwG,EAAgC,IAAjBA,EAAqB,EAAIA,EAGxCC,GAAU3sB,GAAQ,EAAM0sB,GAGxBC,GAAU3sB,GAAQ,EAAO0sB,GAO1B,IAAM,MAAMzwG,KAAW+jF,EAAO7iE,UACxBmvF,GAA2B,YAAhBrwG,EAAQ9gB,KAGvBk0B,EAAOk8C,OAAQtvD,EAAS,aACZqwG,GAA2B,YAAhBrwG,EAAQ9gB,KAKnBmxH,GAA2B,YAAhBrwG,EAAQ9gB,MAAsB8gB,EAAQQ,aAAc,aAAgBpf,KAAKC,MAGhG+xB,EAAOtuB,aAAc,WAAY1D,KAAKC,KAAM2e,IAL5CoT,EAAOo8C,cAAe,CAAEmhD,SAAUvvH,KAAKC,KAAMmvH,WAAY,GAAKxwG,GAC9DoT,EAAOk8C,OAAQtvD,EAAS,aAiB1B5e,KAAKqU,KAAM,kBAAmBsuF,KAUhC,YAEC,MAAM6sB,EAAW,GAAOxvH,KAAKuc,OAAOysC,MAAMhoD,SAASopB,UAAU4/B,qBAE7D,QAASwlE,GAAYA,EAASrvH,GAAI,UAAW,aAAgBqvH,EAASpwG,aAAc,aAAgBpf,KAAKC,KAS1G,gBAEC,GAAKD,KAAKxB,MACT,OAAO,EAGR,MAAM4rB,EAAYpqB,KAAKuc,OAAOysC,MAAMhoD,SAASopB,UACvC6+B,EAASjpD,KAAKuc,OAAOysC,MAAMC,OAE3Bg6C,EAAa,GAAO74E,EAAU4/B,qBAEpC,QAAMi5C,GAKC+rB,GAAwB/rB,EAAYh6C,IAY7C,SAASqmE,GAAU3sB,EAAQ3yE,EAAYq/F,GAEtC,MAAMI,EAAez/F,EAAa2yE,EAAQ,GAAMA,EAAQA,EAAO5gG,OAAS,GAExE,GAAK0tH,EAAatvH,GAAI,UAAW,YAAe,CAC/C,IAAIkC,EAAOotH,EAAcz/F,EAAa,kBAAoB,eActDk/F,EAAgBO,EAAarwG,aAAc,cAI/C,KAAQ/c,GAAQA,EAAKlC,GAAI,UAAW,aAAgBkC,EAAK+c,aAAc,eAAkBiwG,GACnFH,EAAgB7sH,EAAK+c,aAAc,gBACvC8vG,EAAgB7sH,EAAK+c,aAAc,eAI/B/c,EAAK+c,aAAc,eAAkB8vG,GAEzCvsB,EAAQ3yE,EAAa,UAAY,QAAU3tB,GAG5CA,EAAOA,EAAM2tB,EAAa,kBAAoB,gBAWjD,SAASg/F,GAAwBvmE,EAAOQ,GACvC,OAAOA,EAAOiH,WAAYzH,EAAM1rC,OAAQ,cAAiBksC,EAAO6D,SAAUrE,GC/S5D,MAAM,WAAsB4kC,GAQ1C,YAAa9wE,EAAQmzG,GACpB9vH,MAAO2c,GASPvc,KAAK2vH,UAA+B,WAAnBD,EAA+B,GAAK,EAMtD,UACC1vH,KAAKsvC,UAAYtvC,KAAK0iG,gBASvB,UACC,MAAM15C,EAAQhpD,KAAKuc,OAAOysC,MACpB5hB,EAAM4hB,EAAMhoD,SAClB,IAAI4uH,EAAgBzmH,MAAMiK,KAAMg0B,EAAIhd,UAAU4/B,qBAE9ChB,EAAM5L,OAAQprB,IACb,MAAM69F,EAAWD,EAAeA,EAAc7tH,OAAS,GAGvD,IAAIwpB,EAAOskG,EAAS3hG,YAGpB,KAAQ3C,GAAqB,YAAbA,EAAKztB,MAAsBytB,EAAKnM,aAAc,cAAiBywG,EAASzwG,aAAc,eACrGwwG,EAAc3sH,KAAMsoB,GAEpBA,EAAOA,EAAK2C,YAORluB,KAAK2vH,UAAY,IACrBC,EAAgBA,EAAc9vF,WAG/B,IAAM,MAAMz9B,KAAQutH,EAAgB,CACnC,MAAMhG,EAASvnH,EAAK+c,aAAc,cAAiBpf,KAAK2vH,UAInD/F,EAAS,EAIb53F,EAAOk8C,OAAQ7rE,EAAM,aAIrB2vB,EAAOtuB,aAAc,aAAckmH,EAAQvnH,GAa7CrC,KAAKqU,KAAM,kBAAmBu7G,KAUhC,gBAEC,MAAMJ,EAAW,GAAOxvH,KAAKuc,OAAOysC,MAAMhoD,SAASopB,UAAU4/B,qBAG7D,IAAMwlE,IAAaA,EAASrvH,GAAI,UAAW,YAC1C,OAAO,EAGR,GAAKH,KAAK2vH,UAAY,EAAI,CAGzB,MAAM/F,EAAS4F,EAASpwG,aAAc,cAChCnf,EAAOuvH,EAASpwG,aAAc,YAEpC,IAAI0Z,EAAO02F,EAASrhG,gBAEpB,KAAQ2K,GAAQA,EAAK34B,GAAI,UAAW,aAAgB24B,EAAK1Z,aAAc,eAAkBwqG,GAAS,CACjG,GAAK9wF,EAAK1Z,aAAc,eAAkBwqG,EAKzC,OAAO9wF,EAAK1Z,aAAc,aAAgBnf,EAG3C64B,EAAOA,EAAK3K,gBAIb,OAAO,EAIR,OAAO,GC/GF,SAAS2hG,GAAgB5zD,EAAWnX,GAC1C,MAAMpB,EAASoB,EAAcpB,OACvBqK,EAAajJ,EAAc/yB,OAC3Bu9F,EAAmD,YAAxCrzD,EAAU98C,aAAc,YAA6B,KAAO,KACvE2zC,EArBA,SAAoC/gC,GAC1C,MAAM+gC,EAAW/gC,EAAOy+B,uBAAwB,MAIhD,OAFAsC,EAASlsC,gBAAkBkpG,GAEpBh9D,EAgBUi9D,CAA2BhiE,GAEtCiiE,EAAWjiE,EAAWyC,uBAAwB8+D,EAAU,MAM9D,OAJAvhE,EAAWrqD,OAAQqqD,EAAWoD,iBAAkB6+D,EAAU,GAAKl9D,GAE/DpP,EAAOrgB,aAAc44B,EAAWnJ,GAEzBA,EAcD,SAASm9D,GAAgBh0D,EAAWi0D,EAAcprE,EAAeiE,GACvE,MAAMonE,EAAeD,EAAapzG,OAC5B4mC,EAASoB,EAAcpB,OACvBqK,EAAajJ,EAAc/yB,OAGjC,IAAI2uB,EAAiBgD,EAAOD,eAAgBsF,EAAMsT,qBAAsBJ,IAKxE,MAAMm0D,EAAUC,GAAoBp0D,EAAU/tC,gBAAiB,CAC9DoiG,YAAY,EACZC,eAAe,EACfpB,WAAYlzD,EAAU98C,aAAc,gBAE/BqxG,EAAWv0D,EAAU/tC,gBAE3B,GAAKkiG,GAAWA,EAAQjxG,aAAc,eAAkB88C,EAAU98C,aAAc,cAAiB,CAGhG,MAAM2zC,EAAWpP,EAAOR,cAAektE,GACvC1vE,EAAiBqN,EAAW0iE,eAAgB1iE,EAAW2O,oBAAqB5J,SAG5E,GAAK09D,GAA6B,YAAjBA,EAAS3yH,KAAqB,CAG9C6iD,EAAiBgD,EAAOD,eAAgBsF,EAAMoI,iBAAkBq/D,EAAU,QAI1E,MAAME,EAAqBhtE,EAAOf,uBAAwBjC,GACpDiwE,EAsLF,SAAyB91F,GAC/B,IAAM,MAAMvoB,KAAQuoB,EAAYpU,cAC/B,GAAkB,MAAbnU,EAAKzU,MAA6B,MAAbyU,EAAKzU,KAC9B,OAAOyU,EAIT,OAAO,KA7Lcs+G,CAAgBF,GAIlChwE,EADIiwE,EACa5iE,EAAWsO,qBAAsBs0D,GAGjC5iE,EAAWoD,iBAAkBu/D,EAAoB,YAKnEhwE,EAAiBgD,EAAOD,eAAgBsF,EAAMsT,qBAAsBJ,IAUtE,GANAvb,EAAiBmwE,GAAyBnwE,GAG1CqN,EAAWrqD,OAAQg9C,EAAgByvE,GAG9BK,GAA6B,YAAjBA,EAAS3yH,KAAqB,CAC9C,MAAMizH,EAAWptE,EAAOR,cAAestE,GAGjCz2F,EADmBg0B,EAAW1nB,YAAa0nB,EAAWoD,iBAAkB2/D,EAAU,GAAKpwE,GAC7D1mB,UAAW,CAAEhP,kBAAkB,IAE/D,IAAM,MAAMzsB,KAASw7B,EACpB,GAAKx7B,EAAM6D,KAAKlC,GAAI,UAAW,MAAS,CACvC,MAAM6wH,EAAgBhjE,EAAW0iE,eAAgB1iE,EAAWsO,qBAAsB99D,EAAM6D,OAClF4tH,EAAWzxH,EAAM6D,KAAK0a,OAEtBub,EAAiB01B,EAAWoD,iBAAkB++D,EAAc,OAClEc,GAAgBjjE,EAAY11B,EAAehL,WAAYgL,EAAelL,WACtE4gC,EAAWz1B,KAAMy1B,EAAWjH,cAAekpE,GAAY33F,GAEvD0B,EAAOnP,SAAWmmG,OAGd,CACN,MAAME,EAAed,EAAaliG,YAElC,GAAKgjG,IAAkBA,EAAa/wH,GAAI,UAAW,OAAU+wH,EAAa/wH,GAAI,UAAW,OAAW,CACnG,IAAIgxH,EAAe,KAEnB,IAAM,MAAM1qG,KAASyqG,EAAaxqG,cAAgB,CACjD,MAAM0qG,EAAaztE,EAAOV,eAAgBx8B,GAE1C,KAAK2qG,GAAcA,EAAWhyG,aAAc,cAAiB88C,EAAU98C,aAAc,eAGpF,MAFA+xG,EAAe1qG,EAMZ0qG,IACJnjE,EAAW0iE,eAAgB1iE,EAAW2O,oBAAqBw0D,IAC3DnjE,EAAWz1B,KAAMy1B,EAAWjH,cAAeoqE,EAAap0G,QAAUixC,EAAWoD,iBAAkB++D,EAAc,UAMhHc,GAAgBjjE,EAAYoiE,EAAcA,EAAaliG,aACvD+iG,GAAgBjjE,EAAYoiE,EAAajiG,gBAAiBiiG,GAYpD,SAASa,GAAgBjjE,EAAYqjE,EAAWC,GAEtD,OAAMD,IAAcC,GAAkC,MAAlBD,EAAUvzH,MAAkC,MAAlBuzH,EAAUvzH,MAKnEuzH,EAAUvzH,MAAQwzH,EAAWxzH,MAAQuzH,EAAUjyG,aAAc,WAAckyG,EAAWlyG,aAAc,SAJjG,KAQD4uC,EAAWujE,gBAAiBvjE,EAAW2O,oBAAqB00D,IAc7D,SAASP,GAAyBt6F,GACxC,OAAOA,EAAaxJ,wBAAyBxuB,GAASA,EAAM6D,KAAKlC,GAAI,cAe/D,SAASmwH,GAAoBp0D,EAAWh6D,GAC9C,MAAMquH,IAAeruH,EAAQquH,WACvBC,IAAkBtuH,EAAQsuH,cAC1B5G,EAAS1nH,EAAQktH,WAEvB,IAAI/sH,EAAO65D,EAEX,KAAQ75D,GAAqB,YAAbA,EAAKvE,MAAqB,CACzC,MAAM0zH,EAAanvH,EAAK+c,aAAc,cAEtC,GAAOmxG,GAAc3G,GAAU4H,GAAkBhB,GAAiB5G,EAAS4H,EAC1E,OAAOnvH,EAIPA,EAD0B,YAAtBH,EAAQ0oB,UACLvoB,EAAK6rB,YAEL7rB,EAAK8rB,gBAId,OAAO,KAYD,SAASsjG,GAAmBl1G,EAAQw4C,EAAarkC,EAAO01D,GAC9D7pE,EAAOL,GAAG+5D,iBAAiBrnE,IAAKmmD,EAAa94C,IAC5C,MAAM+4C,EAAUz4C,EAAO24C,SAAS92D,IAAK22D,GAC/BqvB,EAAa,IAAI,GAAYnoE,GAkBnC,OAhBAmoE,EAAW36E,IAAK,CACfinB,QACA01D,OACAE,SAAS,EACTL,cAAc,IAIf7B,EAAWrlF,KAAM,OAAQ,aAAc6U,GAAIohD,EAAS,QAAS,aAG7DovB,EAAWl7D,GAAI,UAAW,KACzB3M,EAAO04C,QAASF,GAChBx4C,EAAO83D,QAAQ3+C,KAAK7F,UAGdu0D,IAwGT,SAAS2rC,KACR,MAAM2B,GAAgB1xH,KAAKyiB,UAAwC,MAA3BziB,KAAKkd,SAAU,GAAIpf,MAA2C,MAA3BkC,KAAKkd,SAAU,GAAIpf,MAE9F,OAAKkC,KAAKyiB,SAAWivG,EACb,EAGD7qG,GAAgBnpB,KAAMsC,MC9VvB,SAAS2xH,GAAoB3oE,GACnC,MAAO,CAAElyC,EAAKnX,EAAMolD,KACnB,MAAMqB,EAAarB,EAAcqB,WAEjC,IAAMA,EAAWj8C,KAAMxK,EAAK0C,KAAM,YAChC+jD,EAAWj8C,KAAMxK,EAAK0C,KAAM,wBAC5B+jD,EAAWj8C,KAAMxK,EAAK0C,KAAM,wBAE7B,OAGD+jD,EAAWkH,QAAS3tD,EAAK0C,KAAM,UAC/B+jD,EAAWkH,QAAS3tD,EAAK0C,KAAM,sBAC/B+jD,EAAWkH,QAAS3tD,EAAK0C,KAAM,wBAE/B,MAAM65D,EAAYv8D,EAAK0C,KAGvB6tH,GAAgBh0D,EAFC4zD,GAAgB5zD,EAAWnX,GAEPA,EAAeiE,IA+D/C,SAAS4oE,GAAqB96G,EAAKnX,EAAMolD,GAC/C,IAAMA,EAAcqB,WAAWkH,QAAS3tD,EAAK0C,KAAM,sBAClD,OAGD,MAAM0wD,EAAWhO,EAAcpB,OAAOR,cAAexjD,EAAK0C,MACpD2rD,EAAajJ,EAAc/yB,OAIjCg8B,EAAW0iE,eAAgB1iE,EAAWsO,qBAAsBvJ,IAC5D/E,EAAW0iE,eAAgB1iE,EAAW2O,oBAAqB5J,IAI3D,MAAMk9D,EAAWl9D,EAASh2C,OACpB80G,EAAqC,YAA1BlyH,EAAKmmD,kBAAkC,KAAO,KAE/DkI,EAAWkgB,OAAQ2jD,EAAU5B,GAWvB,SAAS6B,GAA+Bh7G,EAAKnX,EAAMolD,GACzD,MACMkrE,EADWlrE,EAAcpB,OAAOR,cAAexjD,EAAK0C,MAChC0a,OACpBixC,EAAajJ,EAAc/yB,OAGjCi/F,GAAgBjjE,EAAYiiE,EAAUA,EAAS/hG,aAC/C+iG,GAAgBjjE,EAAYiiE,EAAS9hG,gBAAiB8hG,GAGtD,IAAM,MAAMxpG,KAAS9mB,EAAK0C,KAAKqkB,cAC9Bq+B,EAAcqB,WAAWkH,QAAS7mC,EAAO,UAwEpC,SAASsrG,GAAwBj7G,EAAKnX,EAAMolD,GAClD,GAAuB,YAAlBplD,EAAK0C,KAAKvE,KAAqB,CACnC,IAAI04B,EAAeuuB,EAAcpB,OAAOD,eAAgB/jD,EAAKsvB,MAAMpO,OAEnE,MAAMmtC,EAAajJ,EAAc/yB,OAC3Bvf,EAAQ,GAgDd,MAAoC,MAA5B+jB,EAAazZ,OAAOjf,MAA4C,MAA5B04B,EAAazZ,OAAOjf,QAC/D04B,EAAew3B,EAAW0iE,eAAgBl6F,GAET,MAA5BA,EAAazZ,OAAOjf,OAHqD,CAS9E,MAAMk0H,EAAcx7F,EACdy7F,EAAYjkE,EAAWoD,iBAAkB56B,EAAazZ,OAAQ,OAGpE,IAAMi1G,EAAY1lG,QAAS2lG,GAAc,CACxC,MAAMn8G,EAAUk4C,EAAW7pD,OAAQ6pD,EAAW1nB,YAAa0rF,EAAaC,IACxEx/G,EAAMxP,KAAM6S,GAGb0gB,EAAew3B,EAAW2O,oBAAqBnmC,EAAazZ,QAI7D,GAAKtK,EAAM1Q,OAAS,EAAI,CACvB,IAAM,IAAIxE,EAAI,EAAGA,EAAIkV,EAAM1Q,OAAQxE,IAAM,CACxC,MAAM20H,EAAe17F,EAAalJ,WAKlC,GAHAkJ,EADsBw3B,EAAWrqD,OAAQ6yB,EAAc/jB,EAAOlV,IACjCujB,IAGxBvjB,EAAI,EAAI,CACZ,MAAM40H,EAAWlB,GAAgBjjE,EAAYkkE,EAAcA,EAAahkG,aAInEikG,GAAYA,EAASp1G,QAAUm1G,GACnC17F,EAAalqB,UAMhB2kH,GAAgBjjE,EAAYx3B,EAAalJ,WAAYkJ,EAAapJ,aA2B9D,SAASglG,GAAqBt7G,EAAKnX,EAAMolD,GAC/C,MAAMvuB,EAAeuuB,EAAcpB,OAAOD,eAAgB/jD,EAAKkrB,UACzDwnG,EAAe77F,EAAalJ,WAC5BglG,EAAe97F,EAAapJ,UAKlC6jG,GAAgBlsE,EAAc/yB,OAAQqgG,EAAcC,GAe9C,SAASC,GAAoBz7G,EAAKnX,EAAMolD,GAC9C,GAAKA,EAAcqB,WAAWkH,QAAS3tD,EAAKozD,SAAU,CAAEj1D,MAAM,IAAW,CACxE,MAAMk0B,EAAS+yB,EAAc/yB,OAGvBw9F,EAAWx9F,EAAO3uB,cAAe,YAGjCumH,EAmpBR,SAAoB4F,GACnB,IAAI5F,EAAS,EAET7sG,EAASyyG,EAASzyG,OAEtB,KAAQA,GAAS,CAEhB,GAAKA,EAAO5c,GAAI,UAAW,MAC1BypH,QACM,CAEN,MAAMz7F,EAAkBpR,EAAOoR,gBAQ1BA,GAAmBA,EAAgBhuB,GAAI,UAAW,OACtDypH,IAIF7sG,EAASA,EAAOA,OAGjB,OAAO6sG,EA9qBS4I,CAAW7yH,EAAKozD,UAE/B/gC,EAAOtuB,aAAc,aAAckmH,EAAQ4F,GAG3C,MAAMvvH,EAAON,EAAKozD,SAASh2C,QAAuC,MAA7Bpd,EAAKozD,SAASh2C,OAAOjf,KAAe,WAAa,WAGtF,GAFAk0B,EAAOtuB,aAAc,WAAYzD,EAAMuvH,IAEjCzqE,EAAcsO,WAAYm8D,EAAU7vH,EAAKkzD,aAC9C,OAGD,MAAMxmC,EAibR,SAA+ComG,EAAe5/E,EAAckS,GAC3E,MAAM,OAAE/yB,EAAM,OAAEi3B,GAAWlE,EAG3B,IAAI14B,EAAe2F,EAAO2qC,oBAAqB81D,GAI/C,IAAM,MAAMhsG,KAASosB,EACpB,GAAmB,MAAdpsB,EAAM3oB,MAA8B,MAAd2oB,EAAM3oB,KAOhCuuB,EAAe04B,EAAcoW,YAAa10C,EAAO4F,GAAewmC,gBAC1D,CAEN,MAAM/wD,EAASijD,EAAcoW,YAAa10C,EAAOuL,EAAOo/B,iBAAkBqhE,EAAe,QAUnFC,EAAiB5wH,EAAO2hD,WAAW5iC,MAAMuM,UAC9BslG,GAAkBA,EAAevyH,GAAI,aAAgB8oD,EAAOiH,WAAYuiE,EAAeC,EAAe50H,QAsBrH20H,EAFI3wH,EAAO+wD,YAAY91C,OAAO5c,GAAI,UAAW,YAE7B2B,EAAO+wD,YAAY91C,OAGnB41G,GAAkB7wH,EAAO+wD,aAG1CxmC,EAAe2F,EAAO2qC,oBAAqB81D,IAK9C,OAAOpmG,EAhfeumG,CAAsCpD,EAAU7vH,EAAKozD,SAASrsC,cAAeq+B,GAGlGplD,EAAK8jD,WAAazxB,EAAOsU,YAAa3mC,EAAKkzD,YAAaxmC,GAExD04B,EAAcuO,uBAAwBk8D,EAAU7vH,IAc3C,SAASkzH,GAAW/7G,EAAKnX,EAAMolD,GACrC,GAAKA,EAAcqB,WAAWj8C,KAAMxK,EAAKozD,SAAU,CAAEj1D,MAAM,IAAW,CAErE,MAAMgK,EAAWqB,MAAMiK,KAAMzT,EAAKozD,SAASrsC,eAE3C,IAAM,MAAMD,KAAS3e,EAAW,GACL2e,EAAMtmB,GAAI,UAAW,OAAU2yH,GAAQrsG,KAGhEA,EAAMvQ,YAcH,SAAS68G,GAAej8G,EAAKnX,EAAMolD,GACzC,GAAKA,EAAcqB,WAAWj8C,KAAMxK,EAAKozD,SAAU,CAAEj1D,MAAM,IAAW,CACrE,GAAkC,IAA7B6B,EAAKozD,SAASjsC,WAClB,OAGD,MAAMhf,EAAW,IAAKnI,EAAKozD,SAASrsC,eAEpC,IAAIssG,GAAY,EACZlyB,GAAY,EAEhB,IAAM,MAAMr6E,KAAS3e,EACfkrH,IAAcF,GAAQrsG,IAC1BA,EAAMvQ,UAGFuQ,EAAMtmB,GAAI,UAET2gG,IACJr6E,EAAMgX,MAAQhX,EAAM9mB,KAAKuK,QAAS,OAAQ,KAIrCuc,EAAMyH,cAAe4kG,GAAQrsG,EAAMyH,eACxCzH,EAAMgX,MAAQhX,EAAM9mB,KAAKuK,QAAS,OAAQ,MAEhC4oH,GAAQrsG,KAEnBusG,GAAY,GAGblyB,GAAY,GAcR,SAASmyB,GAAqBv9F,GACpC,MAAO,CAAE5e,EAAKnX,KACb,GAAKA,EAAKikD,UACT,OAGD,MAAMsY,EAAYv8D,EAAK8iD,cAAcn1B,WAErC,GAAK4uC,GAAaA,EAAU/7D,GAAI,UAAW,YAAe,CACzD,MAAM4yD,EAAWpzD,EAAKgkD,OAAOR,cAAe+Y,GACtCg3D,EAAkBngE,EAASv1C,eAAepH,KAAM08G,IAChD94F,EAAStE,EAAK07B,iBAAkB2B,EAAU,GAAI94B,YAEpD,IAAM,MAAMz7B,KAASw7B,EAAS,CAC7B,GAAmB,gBAAdx7B,EAAMyB,MAA0BzB,EAAM6D,KAAKlC,GAAI,UAAW,MAAS,CACvER,EAAK62B,aAAeh4B,EAAMmtB,iBAE1B,MACM,GAAmB,cAAdntB,EAAMyB,MAAwBzB,EAAM6D,MAAQ6wH,EAAkB,CACzEvzH,EAAK62B,aAAeh4B,EAAM6tB,aAE1B,UA8QE,SAAS8mG,GAAuBr8G,GAAO5P,EAASynB,IAMtD,IAEIvE,EAFA/nB,EAAO6E,EAAQ/G,GAAI,oBAAuB+G,EAAQgW,SAAU,GAAMhW,EAUtE,GAHCkjB,EAHKuE,EAGO3uB,KAAKs0D,gBAAiB3lC,GAFtB3uB,KAAKgB,SAASopB,UAKtB/nB,GAAQA,EAAKlC,GAAI,UAAW,YAAe,CAE/C,MAAM6c,EAAMoN,EAAUoH,mBACtB,IAAI6+F,EAAU,KASd,GAPKrzG,EAAID,OAAO5c,GAAI,UAAW,YAC9BkwH,EAAUrzG,EAAID,OACHC,EAAIsQ,YAActQ,EAAIsQ,WAAWntB,GAAI,UAAW,cAC3DkwH,EAAUrzG,EAAIsQ,YAIV+iG,EAAU,CAId,MAAM+C,EAAe/C,EAAQjxG,aAAc,cAG3C,GAAKg0G,EAAe,EAEnB,KAAQ/wH,GAAQA,EAAKlC,GAAI,UAAW,aACnCkC,EAAKq1B,cAAe,aAAcr1B,EAAK+c,aAAc,cAAiBg0G,GAEtE/wH,EAAOA,EAAK6rB,cAkFjB,SAASykG,GAAkBhoG,GAC1B,MAAMgC,EAAa,IAAI,GAAY,CAAEhC,kBAErC,IAAInsB,EAEJ,GACCA,EAAQmuB,EAAWpB,cACT/sB,EAAMA,MAAM6D,KAAKlC,GAAI,UAAW,aAE3C,OAAO3B,EAAMA,MAAM6D,KAKpB,SAASgxH,GAAkBC,EAAYC,EAA0BC,EAAyBC,EAAiB1uE,EAAeiE,GAKzH,MAAM0qE,EAAgBpD,GAAoBiD,EAAyBjmG,WAAY,CAC9EijG,YAAY,EACZC,eAAe,EACfpB,WAAYkE,EACZK,IAAK,MAGAhwE,EAASoB,EAAcpB,OACvBqK,EAAajJ,EAAc/yB,OAG3B4hG,EAAaF,EAAgBA,EAAct0G,aAAc,cAAiB,KAEhF,IAAIuhC,EAEJ,GAAM+yE,EAkBC,GAAKE,GAAcN,EAAa,CAkBtC,MAAMO,EAAelwE,EAAOR,cAAeuwE,GAAgB32G,OAC3D4jC,EAAiBqN,EAAW2O,oBAAqBk3D,OAC3C,CAmBN,MAAMpxE,EAAgBuG,EAAMoI,iBAAkBsiE,EAAe,OAC7D/yE,EAAiBgD,EAAOD,eAAgBjB,QAzCxC9B,EAAiB6yE,EA4ClB7yE,EAAiBmwE,GAAyBnwE,GAI1C,IAAM,MAAMl6B,IAAS,IAAKgtG,EAAgB/sG,eACpCosG,GAAQrsG,KACZk6B,EAAiBqN,EAAWz1B,KAAMy1B,EAAWjH,cAAetgC,GAASk6B,GAAiB7/B,IAEtFmwG,GAAgBjjE,EAAYvnC,EAAOA,EAAMyH,aACzC+iG,GAAgBjjE,EAAYvnC,EAAM0H,gBAAiB1H,IAStD,SAASqsG,GAAQh4F,GAChB,OAAOA,EAAY36B,GAAI,UAAW,OAAU26B,EAAY36B,GAAI,UAAW,MCh8BzD,MAAM,WAAoB,GAIxC,wBACC,MAAO,cAMR,sBACC,MAAO,CAAE,IAMV,OACC,MAAMoc,EAASvc,KAAKuc,OAMpBA,EAAOysC,MAAMC,OAAOipB,SAAU,WAAY,CACzC/X,eAAgB,SAChBnD,gBAAiB,CAAE,WAAY,gBAIhC,MAAMr3D,EAAO4c,EAAO5c,KACd00E,EAAU93D,EAAO83D,QDsblB,IAA8BrrB,ECpbnCzsC,EAAOysC,MAAMhoD,SAASkvE,kBAAmBl+C,GDkgBpC,SAA+Bg3B,EAAOh3B,GAC5C,MAAMszB,EAAU0D,EAAMhoD,SAASkkD,OAAOyC,aAChCmsE,EAAiB,IAAIhgH,IAE3B,IAAIigH,GAAU,EAEd,IAAM,MAAMvqH,KAAS87C,EACpB,GAAmB,UAAd97C,EAAMvJ,MAAkC,YAAduJ,EAAM1L,KACpCk2H,EAAexqH,EAAMqhB,eACf,GAAmB,UAAdrhB,EAAMvJ,MAAkC,YAAduJ,EAAM1L,KAAqB,CAChE,GAAmB,SAAd0L,EAAM1L,KAAkB,CAE5B,MAAMuE,EAAOmH,EAAMqhB,SAASuC,UAEvB/qB,EAAK6c,aAAc,gBACvB8S,EAAOptB,gBAAiB,aAAcvC,GAEtC0xH,GAAU,GAGN1xH,EAAK6c,aAAc,cACvB8S,EAAOptB,gBAAiB,WAAYvC,GAEpC0xH,GAAU,GAGN1xH,EAAK6c,aAAc,eACvB8S,EAAOptB,gBAAiB,YAAavC,GAErC0xH,GAAU,GAGX,IAAM,MAAME,KAAa9qH,MAAMiK,KAAM41C,EAAM0L,cAAeryD,IAAS2B,OAAQtC,GAAKA,EAAEW,KAAKlC,GAAI,UAAW,aACrG6zH,EAAeC,EAAUtoG,kBAM3BqoG,EAFiBxqH,EAAMqhB,SAASyD,aAAc9kB,EAAMzH,aAG3B,UAAdyH,EAAMvJ,MAAkC,YAAduJ,EAAM1L,KAC3Ck2H,EAAexqH,EAAMqhB,WACI,aAAdrhB,EAAMvJ,MAA6C,cAAtBuJ,EAAMo8C,cAErB,aAAdp8C,EAAMvJ,MAA6C,YAAtBuJ,EAAMo8C,eAD9CouE,EAAexqH,EAAMylB,MAAMpO,OAM7B,IAAM,MAAMqzG,KAAYJ,EAAeznH,SACtC8nH,EAAiBD,GACjBE,EAAeF,GAGhB,OAAOH,EAEP,SAASC,EAAenpG,GACvB,MAAMmwF,EAAenwF,EAASyC,WAE9B,GAAM0tF,GAAiBA,EAAa76G,GAAI,UAAW,YAM5C,CACN,IAAI+zH,EAAWlZ,EAEf,GAAK8Y,EAAepqH,IAAKwqH,GACxB,OAGD,IAEC,IAAI/lG,EAAkB+lG,EAAS/lG,gBAC/BA,GAAmBA,EAAgBhuB,GAAI,UAAW,YAClDguB,EAAkB+lG,EAAS/lG,gBAI3B,GAFA+lG,EAAW/lG,EAEN2lG,EAAepqH,IAAKwqH,GACxB,OAIFJ,EAAerqH,IAAKuxG,EAAckZ,OA1B+B,CACjE,MAAM7xH,EAAOwoB,EAASuC,UAEjB/qB,GAAQA,EAAKlC,GAAI,UAAW,aAChC2zH,EAAerqH,IAAKpH,EAAMA,IA0B7B,SAAS8xH,EAAiB9xH,GACzB,IAAIgyH,EAAY,EACZC,EAAQ,KAEZ,KAAQjyH,GAAQA,EAAKlC,GAAI,UAAW,aAAe,CAClD,MAAMqxH,EAAanvH,EAAK+c,aAAc,cAEtC,GAAKoyG,EAAa6C,EAAY,CAC7B,IAAIlF,EAEW,OAAVmF,GACJA,EAAQ9C,EAAa6C,EACrBlF,EAAYkF,IAEPC,EAAQ9C,IACZ8C,EAAQ9C,GAGTrC,EAAYqC,EAAa8C,GAG1BtiG,EAAOtuB,aAAc,aAAcyrH,EAAW9sH,GAE9C0xH,GAAU,OAEVO,EAAQ,KACRD,EAAYhyH,EAAK+c,aAAc,cAAiB,EAGjD/c,EAAOA,EAAK6rB,aAId,SAASkmG,EAAe/xH,GACvB,IAAIkyH,EAAa,GACbz7F,EAAO,KAEX,KAAQz2B,GAAQA,EAAKlC,GAAI,UAAW,aAAe,CAClD,MAAMqxH,EAAanvH,EAAK+c,aAAc,cAMtC,GAJK0Z,GAAQA,EAAK1Z,aAAc,cAAiBoyG,IAChD+C,EAAaA,EAAW9sH,MAAO,EAAG+pH,EAAa,IAG7B,GAAdA,EACJ,GAAK+C,EAAY/C,GAAe,CAC/B,MAAMvxH,EAAOs0H,EAAY/C,GAEpBnvH,EAAK+c,aAAc,aAAgBnf,IACvC+xB,EAAOtuB,aAAc,WAAYzD,EAAMoC,GAEvC0xH,GAAU,QAGXQ,EAAY/C,GAAenvH,EAAK+c,aAAc,YAIhD0Z,EAAOz2B,EACPA,EAAOA,EAAK6rB,cCtpBsCsmG,CAAsBj4G,EAAOysC,MAAOh3B,IAEvFqiD,EAAQ1wB,OAAO8wE,0BAA2B,KAAMC,IAChD/0H,EAAKgkD,OAAO8wE,0BAA2B,KAAMC,IAE7CrgD,EAAQ1wB,OAAOz6B,GAAI,sBAAuB+pG,GAAqB5+C,EAAQ3+C,OACvE2+C,EAAQ1wB,OAAOz6B,GAAI,uBD8agB8/B,EC9a4BzsC,EAAOysC,MD+ahE,CAAElyC,EAAKnX,KACb,MAAMwyF,EAAUxyF,EAAK62B,aACfoT,EAAauoD,EAAQp1E,OACrB4mC,EAAShkD,EAAKgkD,OAEpB,GAAwB,MAAnB/Z,EAAW9rC,MAAmC,MAAnB8rC,EAAW9rC,KAAe,CAEzD,GAAMq0F,EAAQvmE,QAMP,CAKN,MAAM+oG,EAAYhxE,EAAOV,eAAgBkvC,EAAQ7kE,YAC3CsnG,EAAcjxE,EAAOO,eAAgBiuC,EAAQ7kE,YAGnD3tB,EAAK8iD,cAAgBuG,EAAMsT,qBAAsBq4D,GAAYrmG,aAAcsmG,OAfpD,CAGvB,MAAMD,EAAYhxE,EAAOV,eAAgBkvC,EAAQ/kE,WAEjDztB,EAAK8iD,cAAgBuG,EAAMsT,qBAAsBq4D,GAalD79G,EAAIhH,YACE,GACa,MAAnB85B,EAAW9rC,MACXq0F,EAAQ7kE,aACqB,MAA3B6kE,EAAQ7kE,WAAWxvB,MAA2C,MAA3Bq0F,EAAQ7kE,WAAWxvB,MACvD,CAGD,MAAM62H,EAAYhxE,EAAOV,eAAgBrZ,GAIzC,IAAIgrF,EAAc,EACd3E,EAAW99B,EAAQ7kE,WAEvB,KAAQ2iG,GAAY6C,GAAQ7C,IAC3B2E,GAAejxE,EAAOO,eAAgB+rE,GAEtCA,EAAWA,EAAS9hG,gBAGrBxuB,EAAK8iD,cAAgBuG,EAAMsT,qBAAsBq4D,GAAYrmG,aAAcsmG,GAE3E99G,EAAIhH,WC9dLnQ,EAAKgkD,OAAOz6B,GAAI,sBAAuB+pG,GAAqB5+C,EAAQ3+C,OAEpEnZ,EAAO+3D,WAAWjV,IAAK,mBACrBzwD,IAAKo2C,IACLA,EAAW97B,GAAI,SAAU6oG,GAAwB,CAAEthH,SAAU,SAC7Du0C,EAAW97B,GAAI,kBAAmByoG,GAAoBp1G,EAAOysC,QAC7DhE,EAAW97B,GAAI,8BAA+B0oG,GAAqB,CAAEnhH,SAAU,SAC/Eu0C,EAAW97B,GAAI,8BAA+B4oG,GAA+B,CAAErhH,SAAU,QACzFu0C,EAAW97B,GAAI,gCDwEZ,SAAgC8/B,GACtC,MAAO,CAAElyC,EAAKnX,EAAMolD,KACnB,IAAMA,EAAcqB,WAAWkH,QAAS3tD,EAAK0C,KAAM,wBAClD,OAGD,MAAM0wD,EAAWhO,EAAcpB,OAAOR,cAAexjD,EAAK0C,MACpD2rD,EAAajJ,EAAc/yB,OAIjCg8B,EAAW0iE,eAAgB1iE,EAAWsO,qBAAsBvJ,IAC5D/E,EAAW0iE,eAAgB1iE,EAAW2O,oBAAqB5J,IAG3D,MAAMk9D,EAAWl9D,EAASh2C,OACpB83G,EAAe5E,EAAS9hG,gBACxB6hD,EAAchiB,EAAWjH,cAAekpE,GAC9CjiE,EAAW7pD,OAAQ6rE,GAEd6kD,GAAgBA,EAAa3mG,aACjC+iG,GAAgBjjE,EAAY6mE,EAAcA,EAAa3mG,aAIxDmlG,GAAkB1zH,EAAKkmD,kBAAoB,EAAGlmD,EAAKsvB,MAAMpO,MAAOmvD,EAAYnvD,MAAOkyC,EAAUhO,EAAeiE,GAG5GknE,GAAgBvwH,EAAK0C,KAAM0wD,EAAUhO,EAAeiE,GAGpD,IAAM,MAAMviC,KAAS9mB,EAAK0C,KAAKqkB,cAC9Bq+B,EAAcqB,WAAWkH,QAAS7mC,EAAO,WCxGQquG,CAAuBv4G,EAAOysC,QAC9EhE,EAAW97B,GAAI,kBDhCZ,SAA0B8/B,GAChC,MAAO,CAAElyC,EAAKnX,EAAMolD,KACnB,MAEMgO,EAFehO,EAAcpB,OAAOD,eAAgB/jD,EAAKkrB,UAChCmC,wBAAyBxuB,IAAUA,EAAM6D,KAAKlC,GAAI,UAAW,OACjEitB,UACrB4gC,EAAajJ,EAAc/yB,OAIjCg8B,EAAW0iE,eAAgB1iE,EAAWsO,qBAAsBvJ,IAC5D/E,EAAW0iE,eAAgB1iE,EAAW2O,oBAAqB5J,IAG3D,MAAMk9D,EAAWl9D,EAASh2C,OACpB83G,EAAe5E,EAAS9hG,gBACxB6hD,EAAchiB,EAAWjH,cAAekpE,GACxCn6G,EAAUk4C,EAAW7pD,OAAQ6rE,GAG9B6kD,GAAgBA,EAAa3mG,aACjC+iG,GAAgBjjE,EAAY6mE,EAAcA,EAAa3mG,aAMxDmlG,GAFkBtuE,EAAcpB,OAAOV,eAAgB8P,GAE3B3zC,aAAc,cAAiB,EAAGzf,EAAKkrB,SAAUmlD,EAAYnvD,MAAOkyC,EAAUhO,EAAeiE,GAGzH,IAAM,MAAMviC,KAASunC,EAAW0G,cAAe5+C,GAAUwxC,WACxDvC,EAAcpB,OAAOqD,kBAAmBvgC,GAGzC3P,EAAIhH,QCDgCilH,CAAiBx4G,EAAOysC,QAC1DhE,EAAW97B,GAAI,SAAUkpG,GAAqB,CAAE3hH,SAAU,UAG5D8L,EAAO+3D,WAAWjV,IAAK,gBACrBzwD,IAAKo2C,IACLA,EAAW97B,GAAI,SAAU6oG,GAAwB,CAAEthH,SAAU,SAC7Du0C,EAAW97B,GAAI,kBAAmByoG,GAAoBp1G,EAAOysC,UAG/DzsC,EAAO+3D,WAAWjV,IAAK,UACrBzwD,IAAKo2C,IACLA,EAAW97B,GAAI,aAAc2pG,GAAW,CAAEpiH,SAAU,SACpDu0C,EAAW97B,GAAI,aAAc2pG,GAAW,CAAEpiH,SAAU,SACpDu0C,EAAW97B,GAAI,aAAc6pG,GAAe,CAAEtiH,SAAU,SACxDu0C,EAAW97B,GAAI,aAAcqpG,MAI/Bh2G,EAAOysC,MAAM9/B,GAAI,gBAAiBiqG,GAAuB,CAAE1iH,SAAU,SAGrE8L,EAAO24C,SAAStmD,IAAK,eAAgB,IAAI,GAAa2N,EAAQ,aAC9DA,EAAO24C,SAAStmD,IAAK,eAAgB,IAAI,GAAa2N,EAAQ,aAG9DA,EAAO24C,SAAStmD,IAAK,aAAc,IAAI,GAAe2N,EAAQ,YAC9DA,EAAO24C,SAAStmD,IAAK,cAAe,IAAI,GAAe2N,EAAQ,aAE/D,MAAMghD,EAAe8W,EAAQ3+C,KAAK10B,SAIlChB,KAAKmR,SAAUosD,EAAc,QAAS,CAAEzmD,EAAKnX,KAC5C,MAAMynC,EAAMpnC,KAAKuc,OAAOysC,MAAMhoD,SACxBy3B,EAAiB2O,EAAIhd,UAAUqH,kBAAkB1U,OAElDqqB,EAAIhd,UAAUqD,aAAsC,YAAvBgL,EAAe36B,MAAsB26B,EAAehW,UACrFziB,KAAKuc,OAAO04C,QAAS,eAErBt1D,EAAKi0C,iBACL98B,EAAIhH,UAMN9P,KAAKmR,SAAUosD,EAAc,SAAU,CAAEzmD,EAAKnX,KAE7C,GAAwB,aAAnBA,EAAKirB,UACT,OAGD,MAAMR,EAAYpqB,KAAKuc,OAAOysC,MAAMhoD,SAASopB,UAE7C,IAAMA,EAAUqD,YACf,OAGD,MAAMojF,EAAgBzmF,EAAUoH,mBAEhC,IAAMq/E,EAAc3kF,UACnB,OAGD,MAAMuM,EAAiBo4E,EAAc9zF,OAErC,GAA6B,aAAxB0b,EAAe36B,KACnB,OAG2B26B,EAAetK,iBAA2D,aAAxCsK,EAAetK,gBAAgBrwB,OAM7FkC,KAAKuc,OAAO04C,QAAS,eAErBt1D,EAAKi0C,iBACL98B,EAAIhH,SACF,CAAEW,SAAU,SAEf,MAAMukH,EAAqBjgE,GACnB,CAAEp1D,EAAMu2C,KACEl2C,KAAKuc,OAAO24C,SAAS92D,IAAK22D,GAE7BzlB,YACZtvC,KAAKuc,OAAO04C,QAASF,GACrB7e,MAKH35B,EAAOi4D,WAAW/qE,IAAK,MAAOurH,EAAoB,eAClDz4G,EAAOi4D,WAAW/qE,IAAK,YAAaurH,EAAoB,gBAMzD,YACC,MAAM9/D,EAAWl1D,KAAKuc,OAAO24C,SAEvB00D,EAAS10D,EAAS92D,IAAK,UACvByrH,EAAU30D,EAAS92D,IAAK,WAEzBwrH,GACJA,EAAOqL,qBAAsB//D,EAAS92D,IAAK,eAGvCyrH,GACJA,EAAQoL,qBAAsB//D,EAAS92D,IAAK,iBAK/C,SAASs2H,GAAuB91G,GAC/B,IAAI7c,EAAS,EAEb,IAAM,MAAM0kB,KAAS7H,EAAQ8H,cAC5B,GAAmB,MAAdD,EAAM3oB,MAA8B,MAAd2oB,EAAM3oB,KAChC,IAAM,MAAMuE,KAAQokB,EAAMC,cACzB3kB,GAAU2yH,GAAuBryH,GAKpC,OAAON,ECnMO,MAAM,WAAe,GAInC,OACC,MAAMtD,EAAIuB,KAAKuc,OAAO9d,EAGtBgzH,GAAmBzxH,KAAKuc,OAAQ,eAAgB9d,EAAG,iBC9BtC,8ZD+BbgzH,GAAmBzxH,KAAKuc,OAAQ,eAAgB9d,EAAG,iBE/BtC,kcCmCR,SAASy2H,GAAkCC,EAAUjzH,GAC3D,OAAO8iD,IACNA,EAAW97B,GAAI,sBAAuBqoC,IAGvC,SAASA,EAAWz6C,EAAKnX,EAAMolD,GAC9B,IAAMA,EAAcqB,WAAWkH,QAAS3tD,EAAK0C,KAAMyU,EAAIhZ,MACtD,OAGD,MAAM+hG,EAAMlgG,EAAKmmD,kBACXkI,EAAajJ,EAAc/yB,OAC3B44E,EAAS7lD,EAAcpB,OAAOR,cAAexjD,EAAK0C,MAClD+yH,EAAsB,IAAKxqB,EAAOlkF,eACtCtQ,KAAMqQ,GAASA,EAAM+D,kBAAmB,kBAG1CwjC,EAAW7pD,OAAQixH,GAEnB,MAAMC,EAAmBF,EAASG,oBAAqBtnE,EAAY6xC,EAAK39F,GAExE8rD,EAAWrqD,OAAQqqD,EAAWoD,iBAAkBw5C,EAAQ,GAAKyqB,ICkBxD,SAASE,GAA0BvjG,EAAQmjG,EAAUt1B,EAAK39F,GAChE,MAAM0oG,EAAS54E,EAAOy+B,uBAAwB,SAAU,CAAEstB,MAAO,UAIjE,OAFA/rD,EAAOruB,OAAQquB,EAAOo/B,iBAAkBw5C,EAAQ,GAAKuqB,EAASG,oBAAqBtjG,EAAQ6tE,EAAK39F,IAEzF0oG,EASD,SAAS4qB,GAA6BprG,GAC5C,MAAMw+E,EAAkBx+E,EAAUsH,qBAElC,OAAKk3E,GAAmBA,EAAgBzoG,GAAI,UAAW,SAC/CyoG,EAGD,KAeD,SAAS6sB,GAAazsE,EAAO62C,EAAKl/C,GACxCqI,EAAM5L,OAAQprB,IACb,MAAM0jG,EAAe1jG,EAAO3uB,cAAe,QAAS,CAAEw8F,QAEtD72C,EAAM6pB,cAAe6iD,EAAc/0E,GAEnC3uB,EAAOyI,aAAci7F,EAAc,QC5FtB,MAAM,WAA0BroC,GAI9C,UACC,MAAMrkC,EAAQhpD,KAAKuc,OAAOysC,MACpB5+B,EAAY4+B,EAAMhoD,SAASopB,UAC3B6+B,EAASD,EAAMC,OACftI,EAAiBgoD,GAA8Bv+E,EAAW4+B,GAC1D2sE,EAAgBH,GAA6BprG,GAEnD,IAAIrN,EAAS4jC,EAAe5jC,OAGvBA,EAAO0F,UAAYumC,EAAMC,OAAOG,QAASrsC,KAC7CA,EAASA,EAAOA,QAGjB/c,KAAKxB,MAAQm3H,EAAgBA,EAAcv2G,aAAc,OAAU,KACnEpf,KAAKsvC,UAAY2Z,EAAOiH,WAAYnzC,EAAQ,SAY7C,QAAS8iF,GACR,MAAM72C,EAAQhpD,KAAKuc,OAAOysC,MACpB5+B,EAAY4+B,EAAMhoD,SAASopB,UAC3BurG,EAAgBH,GAA6BprG,GAEnD,GAAKurG,EACJ3sE,EAAM5L,OAAQprB,IACbA,EAAOtuB,aAAc,MAAOm8F,EAAK81B,SAE5B,CACN,MAAMh1E,EAAiBgoD,GAA8Bv+E,EAAW4+B,GAEhEysE,GAAazsE,EAAO62C,EAAKl/C,KC1Cb,MAAM,GAOpB,YAAa1kC,EAAQJ,GACpB,MAAM+5G,EAAY/5G,EAAO+5G,UACnBC,EAAiBh6G,EAAOg6G,gBAAkB,GAC1CC,EAAmB,IAAIz9G,IAAKwD,EAAOk6G,iBACnCC,EAAsBJ,EAC1BnzH,OAAQozH,GACR7xH,OAAQiyH,IACR,MAAMn4H,EAAOm4H,EAASn4H,KAEtB,OAAMA,GAaEg4H,EAAiBpsH,IAAK5L,IAL7B,aAAY,+BAAgC,CAAEm4H,cAEvC,KAWVj2H,KAAKic,OAASA,EAQdjc,KAAKg2H,oBAAsBA,EAS5B,SAAUn2B,GACT,QAAS7/F,KAAKk2H,UAAWr2B,GAgB1B,oBAAqB7tE,EAAQ6tE,EAAK39F,GACjC,OAAOlC,KAAKk2H,UAAWr2B,GAAMs2B,eAAgBnkG,EAAQ9vB,GAUtD,UAAW29F,GACV,IAAMA,EACL,OAAO,IAAI,GAAO7/F,KAAKic,QAGxB4jF,EAAMA,EAAIv8E,OAEV,IAAM,MAAMizC,KAAcv2D,KAAKg2H,oBAAsB,CACpD,MAAMI,EAAkB7/D,EAAW8/D,KAC7B53G,EAAUpE,GAASk8C,EAAWspC,KAEpC,IAAM,MAAMy2B,KAAc73G,EAAU,CACnC,MAAM/C,EAAQ1b,KAAKu2H,eAAgB12B,EAAKy2B,GAExC,GAAK56G,EACJ,OAAO,IAAI,GAAO1b,KAAKic,OAAQ4jF,EAAKnkF,EAAO06G,IAK9C,OAAO,KAWR,eAAgBv2B,EAAKphF,GAEpB,IAAI/C,EAAQmkF,EAAInkF,MAAO+C,GAEvB,GAAK/C,EACJ,OAAOA,EAIR,IAAI86G,EAAS32B,EAAI31F,QAAS,eAAgB,IAG1C,OAFAwR,EAAQ86G,EAAO96G,MAAO+C,GAEjB/C,IAKL86G,EAASA,EAAOtsH,QAAS,SAAU,IACnCwR,EAAQ86G,EAAO96G,MAAO+C,GAEjB/C,GAIE,OAWT,MAAM,GACL,YAAaO,EAAQ4jF,EAAKnkF,EAAO06G,GAMhCp2H,KAAK6/F,IAAM7/F,KAAKy2H,aAAc52B,GAQ9B7/F,KAAKyb,GAAKQ,EAAOxd,EAOjBuB,KAAK02H,OAASh7G,EAOd1b,KAAK22H,iBAAmBP,EAYzB,eAAgBpkG,EAAQ9vB,GACvB,MAAMoB,EAAa,GACnB,IAAIw3B,EAEJ,GAAK54B,EAAQ00H,sBAA0B10H,EAAQ20H,oBAAsB72H,KAAK6/F,KAAO7/F,KAAK22H,iBAAqB,CACrG32H,KAAK6/F,MACTv8F,EAAY,mBAAsBtD,KAAK6/F,KAGnC39F,EAAQ00H,uBACZtzH,EAAWy6E,MAAQ,qBAGpB,MAAM+4C,EAAY92H,KAAK+2H,gBAAiB70H,GAExC44B,EAAc9I,EAAOglG,iBAAkB,MAAO1zH,GAAY,SAAUiyB,GACnEA,EAAW+U,UAAYwsF,UAGnB92H,KAAK6/F,MACTv8F,EAAWu8F,IAAM7/F,KAAK6/F,KAGvB/kE,EAAc9I,EAAOw8D,mBAAoB,SAAUlrF,GAKpD,OAFA0uB,EAAOg2E,kBAAmB,iBAAiB,EAAMltE,GAE1CA,EAWR,gBAAiB54B,GAChB,OAAKlC,KAAK22H,iBACF32H,KAAK22H,iBAAkB32H,KAAK02H,QAI9B12H,KAAK6/F,KAAO39F,EAAQ00H,qBACjB52H,KAAKi3H,sBAGN,GAST,sBACC,MAAM3wC,EAAU,IAAI,GACdF,EAAO,IAAI,GAEjBE,EAAQ/zC,KAAOvyC,KAAKyb,GAAI,yBACxB2qE,EAAKl/E,QCrRQ,oyCDsRbk/E,EAAKnB,QAtQ6B,YA2SlC,OAnCoB,IAAI,GAAU,CACjC78E,IAAK,MACL9E,WAAY,CACXy6E,MAAO,yCAERj2E,SAAU,CACT,CACCM,IAAK,MACL9E,WAAY,CACXy6E,MAAO,+BAERj2E,SAAU,CAAEs+E,IAEb,CACCh+E,IAAK,IACL9E,WAAY,CACXy6E,MAAO,6BACP38E,OAAQ,SACRgvG,IAAK,sBACL5C,KAAMxtG,KAAK6/F,KAEZ/3F,SAAU,CACT,CACCM,IAAK,OACL9E,WAAY,CACXy6E,MAAO,oCAERj2E,SAAU,CAAE9H,KAAK6/F,MAElBvZ,OAIA9uD,SAEe0/F,UASpB,aAAcr3B,GACb,OAAMA,EAIDA,EAAInkF,MAAO,WACRmkF,EAGD,WAAaA,EAPZ,M,ME/SK,MAAM,WAA0B,GAI9C,wBACC,MAAO,oBAMR,YAAatjF,GACZ3c,MAAO2c,GAEPA,EAAOV,OAAO5e,OAAQ,aAAc,CACnC24H,UAAW,CACV,CACC93H,KAAM,cACN+hG,IAAK,kCACLw2B,KAAM36G,GAKH,2HAJSA,EAAO,yKAapB,CACC5d,KAAM,UACN+hG,IAAK,CACJ,qCACA,oCACA,qCAEDw2B,KAAM36G,GAKH,uIAJSA,EAAO,gKAapB,CACC5d,KAAM,UACN+hG,IAAK,CACJ,2CACA,qCACA,iCACA,wBAEDw2B,KAAM36G,GAKH,0IAJSA,EAAO,iKAapB,CACC5d,KAAM,QACN+hG,IAAK,CACJ,qBACA,0CACA,0CACA,sCACA,4CACA,sCACA,qCAEDw2B,KAAM36G,GAKH,2IAJSA,EAAO,wKAapB,CACC5d,KAAM,YACN+hG,IAAK,6BAEN,CACC/hG,KAAM,UACN+hG,IAAK,iBAEN,CACC/hG,KAAM,aACN+hG,IAAK,sBAEN,CACC/hG,KAAM,SACN+hG,IAAK,gBAEN,CACC/hG,KAAM,WACN+hG,IAAK,qBAUR7/F,KAAKm1H,SAAW,IAAI,GAAe54G,EAAON,OAAQM,EAAOV,OAAOzd,IAAK,eAMtE,OACC,MAAMme,EAASvc,KAAKuc,OACd0sC,EAAS1sC,EAAOysC,MAAMC,OACtBxqD,EAAI8d,EAAO9d,EACX61E,EAAa/3D,EAAO+3D,WACpBuiD,EAAqBt6G,EAAOV,OAAOzd,IAAK,6BACxC+2H,EAAWn1H,KAAKm1H,SAEtB54G,EAAO24C,SAAStmD,IAAK,aAAc,IAAI,GAAmB2N,IAG1D0sC,EAAOipB,SAAU,QAAS,CACzBplB,UAAU,EACV5D,SAAS,EACTyQ,WAAY,SACZ3C,gBAAiB,CAAE,SAIpBsd,EAAWjV,IAAK,gBAAiBC,iBAAkB,CAClDtW,MAAO,QACPtzB,KAAM,CAAEstB,GAAgBhxB,aACvB,MAAM6tE,EAAM78C,EAAa5jC,aAAc,OAEvC,OAAOm2G,GAA0BvjG,EAAQmjG,EAAUt1B,EAAK,CACvDg3B,mBAAoBh3B,GAAOg3B,OAM9BviD,EAAWjV,IAAK,gBAAiBzwD,IAChCsmH,GAAkCC,EAAU,CAC3C0B,wBAIFviD,EAAWjV,IAAK,mBAAoBC,iBAAkB,CACrDtW,MAAO,QACPtzB,KAAM,CAAEstB,GAAgBhxB,aACvB,MAAM6tE,EAAM78C,EAAa5jC,aAAc,OAKvC,OJtLG,SAAwB0b,EAAa9I,EAAQtB,GAGnD,OAFAsB,EAAOg2E,kBAAmB,SAAS,EAAMltE,GAElCitE,GAAUjtE,EAAa9I,EAAQ,CAAEtB,UImL9BymG,CAJQ5B,GAA0BvjG,EAAQmjG,EAAUt1B,EAAK,CAC/D+2B,sBAAsB,IAGO5kG,EAAQvzB,EAAG,oBAK3C61E,EAAWjV,IAAK,mBAAoBzwD,IACnCsmH,GAAkCC,EAAU,CAC3CyB,sBAAsB,KAIxBtiD,EAAWjV,IAAK,UAEdC,iBAAkB,CAClB5pC,KAAM,CACL53B,KAAM,SACNwF,WAAY,CACXu8F,KAAK,IAGP72C,MAAO,CAAEouE,GAAaplG,aACrB,MAAM6tE,EAAMu3B,EAAUh4G,aAAc,OAEpC,GAAK+1G,EAASkC,SAAUx3B,GACvB,OAAO7tE,EAAO3uB,cAAe,QAAS,CAAEw8F,WAK1CvgC,iBAAkB,CAClB5pC,KAAM,CACL53B,KAAM,MACNwF,WAAY,CACX,mBAAmB,IAGrB0lD,MAAO,CAAEouE,GAAaplG,aACrB,MAAM6tE,EAAMu3B,EAAUh4G,aAAc,mBAEpC,GAAK+1G,EAASkC,SAAUx3B,GACvB,OAAO7tE,EAAO3uB,cAAe,QAAS,CAAEw8F,YCjO9C,MAAMy3B,GAAa,0EAQJ,MAAM,WAAuB,GAI3C,sBACC,MAAO,CAAE,GAAW,IAMrB,wBACC,MAAO,iBAMR,YAAa/6G,GACZ3c,MAAO2c,GASPvc,KAAKu3H,WAAa,KASlBv3H,KAAKw3H,kBAAoB,KAM1B,OACC,MAAMj7G,EAASvc,KAAKuc,OACdiwE,EAAgBjwE,EAAOysC,MAAMhoD,SAKnChB,KAAKmR,SAAUoL,EAAOtE,QAAQ7Z,IAAK,IAAa,sBAAuB,KACtE,MAAMkxB,EAAak9D,EAAcpiE,UAAUmF,gBAErCkoG,EAAmB,GAAatrD,aAAc78C,EAAWzO,OAC/D42G,EAAiB54E,WAAa,aAE9B,MAAM64E,EAAoB,GAAavrD,aAAc78C,EAAWxO,KAChE42G,EAAkB74E,WAAa,SAE/B2tC,EAAcrY,KAAM,cAAe,KAClCn0E,KAAK23H,4BAA6BF,EAAkBC,GAEpDD,EAAiBvrF,SACjBwrF,EAAkBxrF,UAChB,CAAEz7B,SAAU,WAGhB8L,EAAO24C,SAAS92D,IAAK,QAAS8qB,GAAI,UAAW,KACvClpB,KAAKu3H,aACTxwH,GAAO5J,OAAO84C,aAAcj2C,KAAKu3H,YACjCv3H,KAAKw3H,kBAAkBtrF,SAEvBlsC,KAAKu3H,WAAa,KAClBv3H,KAAKw3H,kBAAoB,OAExB,CAAE/mH,SAAU,SAWhB,4BAA6BmnH,EAAcC,GAC1C,MAAMt7G,EAASvc,KAAKuc,OACdu7G,EAAgBv7G,EAAOtE,QAAQ7Z,IAAK,IAAoB+2H,SAExD4C,EAAW,IAAI,GAAWH,EAAcC,GACxC79F,EAAS+9F,EAAS99F,UAAW,CAAEhP,kBAAkB,IAEvD,IAAI40E,EAAM,GAEV,IAAM,MAAMttF,KAAQynB,EACdznB,EAAKlQ,KAAKlC,GAAI,gBAClB0/F,GAAOttF,EAAKlQ,KAAK1C,MAOnB,GAHAkgG,EAAMA,EAAIv8E,QAGJu8E,EAAInkF,MAAO47G,IAGhB,YAFAS,EAAS7rF,SAMV,IAAM4rF,EAAcT,SAAUx3B,GAG7B,YAFAk4B,EAAS7rF,SAKgB3vB,EAAO24C,SAAS92D,IAAK,cAGvBkxC,WAOxBtvC,KAAKw3H,kBAAoB,GAAarrD,aAAcyrD,GAGpD53H,KAAKu3H,WAAaxwH,GAAO5J,OAAOq4C,WAAY,KAC3Cj5B,EAAOysC,MAAM5L,OAAQprB,IAMpB,IAAIuH,EALJv5B,KAAKu3H,WAAa,KAElBvlG,EAAO7tB,OAAQ4zH,GACfA,EAAS7rF,SAMqC,eAAzClsC,KAAKw3H,kBAAkB36H,KAAK0tB,WAChCgP,EAAoBv5B,KAAKw3H,mBAG1B/B,GAAal5G,EAAOysC,MAAO62C,EAAKtmE,GAEhCv5B,KAAKw3H,kBAAkBtrF,SACvBlsC,KAAKw3H,kBAAoB,QAExB,MA7BFO,EAAS7rF,U,MChHG,MAAM,WAAsB,GAK1C,YAAa8rF,EAAY/7G,GACxBrc,MAAOqc,GAEP,MAAMxd,EAAIwd,EAAOxd,EAQjBuB,KAAKk2E,aAAe,IAAI,GAQxBl2E,KAAKw0E,WAAa,IAAI,GAQtBx0E,KAAKyJ,IAAK,qBAAsB,IAOhCzJ,KAAKgqH,aAAehqH,KAAKiqH,kBAOzBjqH,KAAK08G,eAAiB18G,KAAK28G,cAAel+G,EAAG,QAAUm+G,GAAW,kBAClE58G,KAAK08G,eAAez8G,KAAO,SAC3BD,KAAK08G,eAAe39G,KAAM,aAAc6U,GAAI5T,KAAM,qBAAsBxB,KAAWA,GAOnFwB,KAAK68G,iBAAmB78G,KAAK28G,cAAel+G,EAAG,UAAY,GAAY,mBAAoB,UAS3FuB,KAAK88G,YAAc,IAAI,GASvB98G,KAAKymF,aAAe,IAAIxG,GAAa,CACpCE,WAAYngF,KAAK88G,YACjB5mC,aAAcl2E,KAAKk2E,aACnBgK,iBAAkBlgF,KAAKw0E,WACvB5xC,QAAS,CAER8jD,cAAe,cAGfC,UAAW,SAWb3mF,KAAKi4H,YAAcD,EAEnBh4H,KAAKs+E,YAAa,CACjBl2E,IAAK,OAEL9E,WAAY,CACXy6E,MAAO,CACN,KACA,gBACA,sBAGDiI,SAAU,MAGXl+E,SAAU,CACT9H,KAAKgqH,aACLhqH,KAAK08G,eACL18G,KAAK68G,oBAIPV,GAA6Bn8G,MAqB9B,SACCJ,MAAM43B,SAEN+kF,GAAe,CACd7mF,KAAM11B,OAGY,CAClBA,KAAKgqH,aACLhqH,KAAK08G,eACL18G,KAAK68G,kBAGKp5G,QAASs5G,IAEnB/8G,KAAK88G,YAAYluG,IAAKmuG,GAGtB/8G,KAAKk2E,aAAatnE,IAAKmuG,EAAEn+F,WAI1B5e,KAAKw0E,WAAWrjE,SAAUnR,KAAK4e,SAE/B,MAAMi1B,EAAkBl0C,GAAQA,EAAKk0C,kBAKrC7zC,KAAKw0E,WAAW/qE,IAAK,aAAcoqC,GACnC7zC,KAAKw0E,WAAW/qE,IAAK,YAAaoqC,GAClC7zC,KAAKw0E,WAAW/qE,IAAK,UAAWoqC,GAChC7zC,KAAKw0E,WAAW/qE,IAAK,YAAaoqC,GAKlC7zC,KAAKmR,SAAUnR,KAAKgqH,aAAaprG,QAAS,cAAe,CAAE9H,EAAKq4B,KAC/DA,EAAO0E,mBACL,CAAEpjC,SAAU,SAMhB,QACCzQ,KAAKymF,aAAaG,aAWnB,UACC,OAAO5mF,KAAKgqH,aAAa3O,UAAUz8F,QAAQpgB,MAAM8kB,OAGlD,QAASu8E,GACR7/F,KAAKgqH,aAAa3O,UAAUz8F,QAAQpgB,MAAQqhG,EAAIv8E,OAQjD,UACCtjB,KAAKk4H,kBAEL,IAAM,MAAMC,KAAan4H,KAAKi4H,YAAc,CAC3C,MAAMzc,EAAY2c,EAAWn4H,MAG7B,GAAKw7G,EAIJ,OAFAx7G,KAAKgqH,aAAaxO,UAAYA,GAEvB,EAIT,OAAO,EASR,kBACCx7G,KAAKgqH,aAAaxO,UAAY,KAC9Bx7G,KAAKgqH,aAAavO,SAAWz7G,KAAKo4H,yBASnC,kBACC,MAAM35H,EAAIuB,KAAKic,OAAOxd,EAEhB+9G,EAAe,IAAI,GAAkBx8G,KAAKic,OAAQ8/F,IAClDsc,EAAa7b,EAAanB,UAchC,OAZAr7G,KAAKo4H,yBAA2B35H,EAAG,qCACnCuB,KAAKs4H,qBAAuB75H,EAAG,wDAE/B+9G,EAAa9rF,MAAQjyB,EAAG,aACxB+9G,EAAaf,SAAWz7G,KAAKo4H,yBAE7BC,EAAWnvG,GAAI,QAAS,KAEvBszF,EAAaf,SAAW4c,EAAWz5G,QAAQpgB,MAAQwB,KAAKs4H,qBAAuBt4H,KAAKo4H,yBACpFp4H,KAAKu4H,mBAAqBF,EAAWz5G,QAAQpgB,MAAM8kB,SAG7Ck5F,EAaR,cAAe9rF,EAAO01D,EAAMhgE,EAAWrU,GACtC,MAAM8xF,EAAS,IAAI,GAAY7jG,KAAKic,QAkBpC,OAhBA4nF,EAAOp6F,IAAK,CACXinB,QACA01D,OACAE,SAAS,IAGVud,EAAOzpB,eAAgB,CACtB92E,WAAY,CACXy6E,MAAO33D,KAIJrU,GACJ8xF,EAAOtyE,SAAU,WAAY3d,GAAI5T,KAAM+R,GAGjC8xF,GClTM,MAAM,WAAqB,GAIzC,sBACC,MAAO,CAAE,IAMV,wBACC,MAAO,eAMR,OACC,MAAMtnF,EAASvc,KAAKuc,OACdy4C,EAAUz4C,EAAO24C,SAAS92D,IAAK,cAC/B+2H,EAAW54G,EAAOtE,QAAQ7Z,IAAK,IAAoB+2H,SAEzD54G,EAAOL,GAAG+5D,iBAAiBrnE,IAAK,aAAcqN,IAC7C,MAAMguE,EAAW7C,GAAgBnrE,GAE3Bu8G,EAAY,IAAI,GA6EzB,SAA4B/5H,EAAG02H,GAC9B,MAAO,CACN3qC,IACC,IAAMA,EAAKqV,IAAI99F,OACd,OAAOtD,EAAG,+BAGZ+rF,IACC,IAAM2qC,EAASkC,SAAU7sC,EAAKqV,KAC7B,OAAOphG,EAAG,sCAtF0Bg6H,CAAmBl8G,EAAO9d,EAAG02H,GAAY54G,EAAON,QAKrF,OAHAjc,KAAK04H,eAAgBzuC,EAAUuuC,EAAWxjE,EAASz4C,GACnDvc,KAAK24H,WAAY1uC,EAAUuuC,EAAWxjE,GAE/Bi1B,IAUT,eAAgBA,EAAUO,EAAMx1B,GAC/B,MAAMz4C,EAASvc,KAAKuc,OACd9d,EAAI8d,EAAO9d,EACXolG,EAAS5Z,EAAS7F,WAsCxB,SAASw0C,IACRr8G,EAAO83D,QAAQ3+C,KAAK7F,QACpBo6D,EAAS3F,QAAS,EAtCnB2F,EAASlrF,KAAM,aAAc6U,GAAIohD,GACjCi1B,EAAS5F,UAAUv8E,SAAS8G,IAAK47E,GAEjCqZ,EAAOp6F,IAAK,CACXinB,MAAOjyB,EAAG,gBACV2nF,KCvEY,4eDwEZE,SAAS,IAMVud,EAAO36E,GAAI,OAAQ,KAClBshE,EAAK4xB,wBAOL5xB,EAAKqV,IAAM7qC,EAAQx2D,OAAS,GAC5BgsF,EAAKw/B,aAAa3O,UAAUS,SAC5BtxB,EAAK36D,QACL26D,EAAK8xB,wBACH,CAAE7rG,SAAU,QAEfw5E,EAAS/gE,GAAI,SAAU,KACjBshE,EAAKquC,YACTt8G,EAAO04C,QAAS,aAAcu1B,EAAKqV,KACnC+4B,OAIF3uC,EAAS/gE,GAAI,gBAAiB,IAAMshE,EAAK0tC,mBACzCjuC,EAAS/gE,GAAI,SAAU,IAAM0vG,KAc9B,WAAY3uC,EAAUO,EAAMx1B,GAC3Bw1B,EAAKj5D,SAAU,SAAU,UAAW3d,GAAIq2E,GACxCO,EAAKw/B,aAAajrH,KAAM,SAAU6U,GAAIohD,EAAS,SAG/Cw1B,EAAKw/B,aAAajrH,KAAM,cAAe6U,GAAIohD,EAAS,YAAax2D,IAAUA,I,MEhGtE,SAASs6H,GAAwC98D,EAAkBn5C,GACzE,IAAMm5C,EAAiBl1C,WACtB,OAGD,MAAMkL,EAAS,IAAI,GAAcgqC,EAAiBh7D,UAC5C+3H,EAkFP,SAAkC/8D,EAAkBhqC,GACnD,MAAM/C,EAAQ+C,EAAO0iC,cAAesH,GAG9Bg9D,EAA0B,IAAIx6G,GAAS,CAC5C1gB,KAAM,WACN2hB,OAAQ,CACP,WAAY,QAIRs5G,EAAmB,GAEzB,IAAM,MAAMv6H,KAASywB,EACpB,GAAoB,iBAAfzwB,EAAMyB,MAA2B+4H,EAAwBt9G,MAAOld,EAAM6D,MAAS,CACnF,MAAM42H,EAAWC,GAAiB16H,EAAM6D,MAExC02H,EAAiB91H,KAAM,CACtB2b,QAASpgB,EAAM6D,KACfC,GAAI22H,EAAS32H,GACb62H,MAAOF,EAASE,MAChBvP,OAAQqP,EAASrP,SAKpB,OAAOmP,EA5GkBK,CAAyBp9D,EAAkBhqC,GAEpE,IAAM+mG,EAAiBh3H,OACtB,OAGD,IAAIs3H,EAAc,KACdC,EAAqB,EAEzBP,EAAiBt1H,QAAS,CAAE81H,EAAiBh8H,KAC5C,MAAMi8H,EA4UR,SAA0BC,EAAcC,GACvC,IAAMD,EACL,OAAO,EAGR,GAAKA,EAAan3H,KAAOo3H,EAAYp3H,GAKpC,OAAKo3H,EAAY9P,OAAS6P,EAAa7P,QAAW,EAOnD,MAAMz7F,EAAkBurG,EAAY96G,QAAQuP,gBAE5C,IAAMA,EACL,OAAO,EAIR,OAGgBvP,EAHAuP,IAITvP,EAAQze,GAAI,UAAW,OAAUye,EAAQze,GAAI,UAAW,OADhE,IAAiBye,EAvWS+6G,CAAiBZ,EAAkBx7H,EAAI,GAAKg8H,GAC9DK,EAA0BJ,EAAkB,KAAOT,EAAkBx7H,EAAI,GACzEs8H,GA+WyCH,EA/WkCH,GA+WhDE,EA/WuBG,GAgXnCF,EAAY9P,OAAS6P,EAAa7P,OAAS8P,EAAY9P,OAAS,GADvF,IAAmC6P,EAAcC,EAxW/C,GALKF,IACJH,EAAc,KACdC,EAAqB,IAGhBD,GAAyC,IAA1BQ,EAA8B,CAClD,MAAMC,EAgHT,SAA0BC,EAAcl3G,GACvC,MAAMm3G,EAAkB,IAAI/vH,OAAQ,UAAW8vH,EAAaz3H,WAAay3H,EAAanQ,qBAAuB,MACvGqQ,EAAqB,qCAErBC,EAAiBF,EAAgBnwH,KAAMgZ,GAE7C,IAAIs3G,EAAgB,UAChBl6H,EAAO,KAEX,GAAKi6H,GAAkBA,EAAgB,GAAM,CAC5C,MAAME,EAAqBH,EAAmBpwH,KAAMqwH,EAAgB,IAWpE,GATKE,GAAsBA,EAAoB,KAC9CD,EAAgBC,EAAoB,GAAI92G,OACxCrjB,EAAyB,WAAlBk6H,GAAgD,UAAlBA,EAA4B,KAAO,MAOlD,WAAlBA,EAA6B,CACjC,MAAME,EAkBT,SAAgCz7G,GAC/B,MAAM07G,EAyBP,SAA6B17G,GAE5B,GAAKA,EAAQ1B,SAAU,GAAI/c,GAAI,SAC9B,OAAO,KAGR,MAAMo6H,EAAoB37G,EAAQ1B,SAAU,GAAIA,SAAU,GAE1D,GAAKq9G,EAAkBp6H,GAAI,SAC1B,OAAOo6H,EAGR,OAAOA,EAAkBr9G,SAAU,GArCTs9G,CAAoB57G,GAE9C,IAAM07G,EACL,OAAO,KAGR,MAAMG,EAAaH,EAAkB78F,MAErC,GAAoB,MAAfg9F,EACJ,MAAO,SACD,GAAoB,MAAfA,EACX,MAAO,OAGH,GAAoB,MAAfA,EACT,MAAO,SAGR,OAAO,KArCiBC,CAAuBX,EAAan7G,SAErDy7G,IACJF,EAAgBE,IAKnB,MAAO,CACNp6H,OACAmD,MAAOu3H,GAAwBR,IAhJZS,CAAiBrB,EAAiB12G,GAEpD,GAAMw2G,GAEC,GAAKE,EAAgB3P,OAAS0P,EAAqB,CACzD,MAAMuB,EAAexB,EAAYn8G,SAAUm8G,EAAYvyG,WAAa,GAC9Dg0G,EAAoBD,EAAa39G,SAAU29G,EAAa/zG,WAAa,GAE3EuyG,EAAc0B,GAAoBjB,EAAWgB,EAAmB9oG,GAChEsnG,GAAsB,OAChB,GAAKC,EAAgB3P,OAAS0P,EAAqB,CACzD,MAAM0B,EAAuB1B,EAAqBC,EAAgB3P,OAElEyP,EAmWJ,SAAgC4B,EAAapB,GAC5C,MAAMv8G,EAAY29G,EAAYz9G,aAAc,CAAEH,aAAa,IAE3D,IAAI69G,EAAa,KACbC,EAAc,EAElB,IAAM,MAAM9gG,KAAY/c,EAKvB,GAJuB,OAAlB+c,EAASv8B,MAAmC,OAAlBu8B,EAASv8B,MACvCq9H,IAGIA,IAAgBtB,EAAwB,CAC5CqB,EAAa7gG,EACb,MAIF,OAAO6gG,EApXUE,CAAuB/B,EAAa2B,GAClD1B,EAAqB9kF,SAAU+kF,EAAgB3P,cAX/CyP,EAAc0B,GAAoBjB,EAAWP,EAAgB36G,QAASoT,GAclEunG,EAAgB3P,QAAU0P,IACxBD,EAAYl5H,GAAI,UAAW25H,EAAU75H,QAC1Co5H,EAAcrnG,EAAOk8C,OAAQ4rD,EAAU75H,KAAMo5H,KAKhD,MAAM7J,EAiOR,SAAuC5wG,EAASoT,GAG/C,OAyCD,SAA8BpT,EAASoT,GAEtC,MAAMqpG,EAAgB,IAAI78G,GAAS,CAClC1gB,KAAM,OACN2hB,OAAQ,CACP,WAAY,YAIRwP,EAAQ+C,EAAO0iC,cAAe91C,GAEpC,IAAM,MAAMpgB,KAASywB,EACA,iBAAfzwB,EAAMyB,MAA2Bo7H,EAAc3/G,MAAOld,EAAM6D,OAChE2vB,EAAO7tB,OAAQ3F,EAAM6D,MAxDvBi5H,CAAqB18G,EAASoT,GAEvBA,EAAOk8C,OAAQ,KAAMtvD,GApOV28G,CAA8BhC,EAAgB36G,QAASoT,GAExEA,EAAOpuB,YAAa4rH,EAAU6J,KA2KhC,SAASsB,GAAwBn8H,GAChC,OAASA,GACR,IAAK,sBACJ,MAAO,uBACR,IAAK,cACJ,MAAO,cACR,IAAK,cACJ,MAAO,cACR,IAAK,cACJ,MAAO,cACR,IAAK,cACJ,MAAO,cACR,IAAK,SACL,IAAK,OACL,IAAK,SACJ,OAAOA,EACR,QACC,OAAO,MAYV,SAASu8H,GAAoBjB,EAAWl7G,EAASoT,GAChD,MAAMjV,EAAS6B,EAAQ7B,OACjB9a,EAAO+vB,EAAO3uB,cAAey2H,EAAU75H,MACvC4qB,EAAW9N,EAAOE,cAAe2B,GAAY,EAUnD,OARAoT,EAAOmwF,YAAat3F,EAAU5oB,EAAM8a,GAI/B+8G,EAAU12H,OACd4uB,EAAO0K,SAAU,kBAAmBo9F,EAAU12H,MAAOnB,GAG/CA,EA+BR,SAASi3H,GAAiBt6G,GACzB,MAAMjf,EAAO,GACPm6H,EAAYl7G,EAAQe,SAAU,YAEpC,GAAKm6G,EAAY,CAChB,MAAM0B,EAAU1B,EAAUp+G,MAAO,kBAC3B+/G,EAAa3B,EAAUp+G,MAAO,gBAC9BggH,EAAc5B,EAAUp+G,MAAO,kBAEhC8/G,GAAWC,GAAcC,IAC7B/7H,EAAK2C,GAAKk5H,EAAS,GACnB77H,EAAKw5H,MAAQsC,EAAY,GACzB97H,EAAKiqH,OAAS8R,EAAa,IAI7B,OAAO/7H,EClUR,MAAMg8H,GAAkB,8CAOT,MAAM,GAMpB,YAAa36H,GAKZhB,KAAKgB,SAAWA,EAMjB,SAAU46H,GACT,OAAOD,GAAgBxxH,KAAMyxH,GAM9B,QAASj8H,GACR,MAAMqyB,EAAS,IAAI,GAAchyB,KAAKgB,WC9BzB,SAA4Bg7D,EAAkBhqC,GAC5D,IAAM,MAAMvL,KAASu1C,EAAiBt1C,cACrC,GAAKD,EAAMtmB,GAAI,UAAW,MAA6C,WAApCsmB,EAAM9G,SAAU,eAA+B,CACjF,MAAM46D,EAAave,EAAiB/+C,cAAewJ,GAEnDuL,EAAO7tB,OAAQsiB,GACfuL,EAAOmwF,YAAa5nC,EAAY9zD,EAAMC,cAAes1C,ID0BtD6/D,CAAmBl8H,EAAKuH,QAAS8qB,GDsC5B,SAAoCgqC,EAAkBhqC,GAC5D,IAAM,MAAMxzB,KAASwzB,EAAO0iC,cAAesH,GAAqB,CAC/D,MAAMp9C,EAAUpgB,EAAM6D,KAEtB,GAAKuc,EAAQze,GAAI,UAAW,MAAS,CAEpC,MAAM6E,EAAa4Z,EAAQ1B,SAAU,GAEhClY,GAAcA,EAAW7E,GAAI,UAAW,MAC5C6xB,EAAO4J,cAAe52B,KC9CxB82H,CAA2Bn8H,EAAKuH,QAAS8qB,IEQ3C,SAAS+pG,GAA2BH,GACnC,OAAOA,EAAW1xH,QAAS,0DAA2D,CAAEyiF,EAAWC,IACzE,IAAlBA,EAAO7qF,OAAe,IAAMoH,MAAOyjF,EAAO7qF,OAAS,GAAIkC,KAAM,MAAYoO,OAAQ,EAAGu6E,EAAO7qF,SC7B7F,SAASi6H,GAAWJ,EAAY51G,GACtC,MAAMi2G,EAAY,IAAI9mD,UAKhB+mD,EDjBA,SAA2BN,GAEjC,OAAOG,GAA2BA,GAA2BH,IAE3D1xH,QAAS,uEAAwE,QACjFA,QAAS,mDAAoD,IAC7DA,QAAS,QAAS,OAClBA,QAAS,iBAAkB,gBAE3BA,QAAS,+BAAgC,IAEzCA,QAAS,oBAAqB,MCMTiyH,CA0ExB,SAAgCP,GAC/B,MACMlgH,EAAQkgH,EAAWlgH,MADV,6BAGVA,GAASA,EAAO,KACpBkgH,EAAaA,EAAWn0H,MAAO,EAAGiU,EAAMhZ,OAAUk5H,EAAWn0H,MAAOiU,EAAMhZ,OAAQwH,QAASwR,EAAO,GAAK,KAGxG,OAAOkgH,EAlFkCQ,CAFzCR,EAAaA,EAAW1xH,QAAS,wBAAyB,MAKpDmyH,EAAeJ,EAAUxmD,gBAAiBymD,EAAgB,cDC1D,SAAiCG,GACvCA,EAAa/2C,iBAAkB,yBAA0B7hF,QAASmxE,IACjE,MAAM0nD,EAAkB1nD,EAAG2nD,UAAUx6H,QAAU,EAE/C6yE,EAAGtqC,UAAYnhC,MAAOmzH,EAAkB,GAAIr4H,KAAM,MAAYoO,OAAQ,EAAGiqH,KCH1EE,CAAwBH,GAGxB,MAAMI,EAAaJ,EAAahiF,KAAK/P,UAG/BoyF,EAkBP,SAAyBL,EAAcr2G,GACtC,MAAMu3C,EAAe,IAAI,GAAcv3C,GACjC2P,EAAe,IAAI,GAAc4nC,EAAc,CAAEp1B,gBAAiB,SAClE4sC,EAAWsnD,EAAanzF,yBACxBniB,EAAQs1G,EAAahiF,KAAK71C,WAEhC,KAAQuiB,EAAMhlB,OAAS,GACtBgzE,EAASnxE,YAAamjB,EAAO,IAG9B,OAAO4O,EAAaiP,UAAWmwC,GA5Bd4nD,CAAgBN,EAAcr2G,GAGzCX,EAmCP,SAAwBg3G,GACvB,MAAM58G,EAAS,GACToD,EAAe,GACf+5G,EAAYzzH,MAAMiK,KAAMipH,EAAaQ,qBAAsB,UAEjE,IAAM,MAAMz5H,KAASw5H,EACfx5H,EAAM05H,OAAS15H,EAAM05H,MAAMC,UAAY35H,EAAM05H,MAAMC,SAASh7H,SAChE0d,EAAOxc,KAAMG,EAAM05H,OACnBj6G,EAAa5f,KAAMG,EAAMknC,YAI3B,MAAO,CACN7qB,SACAoD,aAAcA,EAAa5e,KAAM,MAjDb+4H,CAAeX,GAEpC,MAAO,CACNhiF,KAAMqiF,EACND,aACAh9G,OAAQ4F,EAAa5F,OACrBoD,aAAcwC,EAAaxC,cClCtB,SAASo6G,GAA+BjhE,EAAkBkhE,GAChE,IAAMlhE,EAAiBl1C,WACtB,OAGD,MAAMq2G,EAAe,IAAI,IA4D1B,SAAiDC,EAAWphE,EAAkBhqC,GAC7E,MAAM/C,EAAQ+C,EAAO0iC,cAAesH,GAE9BqhE,EAAuB,IAAI,GAAa,CAC7Cv/H,KAAM,QAGDw/H,EAAO,GAEb,IAAM,MAAM9+H,KAASywB,EACpB,GAAKouG,EAAqB3hH,MAAOld,EAAM6D,MAAS,CAC/C,MAAMuyE,EAAKp2E,EAAM6D,KACXk7H,EAAS3oD,EAAGx1D,aAAc,YAAew1D,EAAGx1D,aAAc,YAAa7P,MAAO,KAAQ,GAEvFguH,EAAOx7H,QAAUw7H,EAAOrzG,MAAOszG,GAASJ,EAAUtqH,QAAS0qH,IAAW,GAC1EF,EAAKr6H,KAAM2xE,GAECA,EAAGx1D,aAAc,QAC7Bk+G,EAAKr6H,KAAM2xE,GAKd,IAAM,MAAMq1B,KAAOqzB,EAClBtrG,EAAO7tB,OAAQ8lG,GAjFhBwzB,CA8BD,SAA2BzhE,EAAkBhqC,GAC5C,MAAM/C,EAAQ+C,EAAO0iC,cAAesH,GAE9B0hE,EAAuB,IAAI,GAAa,CAC7C5/H,KAAM,WAGDs/H,EAAY,GAElB,IAAM,MAAM5+H,KAASywB,EAAQ,CAC5B,MAAM2lD,EAAKp2E,EAAM6D,KACXs7H,EAAkB/oD,EAAGzmD,iBAAmBymD,EAAGzmD,gBAAgBrwB,MAAQ,KAGpE4/H,EAAqBhiH,MAAOk5D,IAAQA,EAAGx1D,aAAc,cAAqC,gBAApBu+G,GAC1EP,EAAUn6H,KAAMzE,EAAM6D,KAAK+c,aAAc,OAI3C,OAAOg+G,EAnDWQ,CAAkB5hE,EAAkBmhE,GAEHnhE,EAAkBmhE,GAyFtE,SAAiCnhE,EAAkBhqC,GAClD,MAAM/C,EAAQ+C,EAAO0iC,cAAesH,GAE9B0hE,EAAuB,IAAI,GAAa,CAC7C5/H,KAAM,WAGDy/H,EAAS,GAEf,IAAM,MAAM/+H,KAASywB,EACfyuG,EAAqBhiH,MAAOld,EAAM6D,OACtCk7H,EAAOt6H,KAAMzE,EAAM6D,MAIrB,IAAM,MAAMm7H,KAASD,EACpBvrG,EAAO7tB,OAAQq5H,GAxGhBK,CAAwB7hE,EAAkBmhE,GAE1C,MAAMlrB,EAiHP,SAA8Cj2C,EAAkBhqC,GAC/D,MAAM/C,EAAQ+C,EAAO0iC,cAAesH,GAE9BqhE,EAAuB,IAAI,GAAa,CAC7Cv/H,KAAM,QAGDw/H,EAAO,GAEb,IAAM,MAAM9+H,KAASywB,EACfouG,EAAqB3hH,MAAOld,EAAM6D,OACjC7D,EAAM6D,KAAK+c,aAAc,OAAQqrC,WAAY,YACjD6yE,EAAKr6H,KAAMzE,EAAM6D,MAKpB,OAAOi7H,EAlIQQ,CAAqC9hE,EAAkBmhE,GAEjElrB,EAAOlwG,QAgLb,SAA0Dg8H,EAAeC,EAAkBhsG,GAE1F,GAAK+rG,EAAch8H,SAAWi8H,EAAiBj8H,OAC9C,IAAM,IAAIxE,EAAI,EAAGA,EAAIwgI,EAAch8H,OAAQxE,IAAM,CAChD,MAAM0gI,EAAS,QAASD,EAAkBzgI,GAAI0C,eAxKZi+H,EAwKkDF,EAAkBzgI,GAAI4gI,IAvKrGt5H,KAAMq5H,EAAUxiH,MAAO,UAAWrR,IAAK+Y,GACtCtX,OAAOsoB,aAAcogB,SAAUpxB,EAAM,MACzCnf,KAAM,OAsKR+tB,EAAOtuB,aAAc,MAAOu6H,EAAQF,EAAexgI,IAzK/C,IAA8B2gI,EAXnCE,CAAiDnsB,EAyInD,SAAkCirB,GACjC,IAAMA,EACL,MAAO,GAGR,MAAMmB,EAAqB,uFACrBC,EAAe,IAAIr0H,OAAQ,OAASo0H,EAAmBzzH,OAAS,yBAA0B,KAC1FqnG,EAASirB,EAAQxhH,MAAO4iH,GACxBx8H,EAAS,GAEf,GAAKmwG,EACJ,IAAM,MAAMI,KAASJ,EAAS,CAC7B,IAAIssB,GAAY,EAEXlsB,EAAMj5F,SAAU,aACpBmlH,EAAY,YACDlsB,EAAMj5F,SAAU,gBAC3BmlH,EAAY,cAGRA,GACJz8H,EAAOmB,KAAM,CACZk7H,IAAK9rB,EAAMnoG,QAASm0H,EAAoB,IAAKn0H,QAAS,eAAgB,IACtEjK,KAAMs+H,IAMV,OAAOz8H,EAtKmD08H,CAAyBtB,GAAWC,GCtB/F,MAAMsB,GAAe,uEACfC,GAAe,sCAON,MAAM,GAMpB,YAAa19H,GAKZhB,KAAKgB,SAAWA,EAMjB,SAAU46H,GACT,OAAO6C,GAAat0H,KAAMyxH,IAAgB8C,GAAav0H,KAAMyxH,GAM9D,QAASj8H,GACR,MAAM,KAAE06C,EAAI,aAAEx3B,GAAiBm5G,GAAWr8H,EAAKisF,aAAaL,QAAS,aAAevrF,KAAKgB,SAASglB,iBAElG8yG,GAAwCz+E,EAAMx3B,GAC9Co6G,GAA+B5iF,EAAM16C,EAAKisF,aAAaL,QAAS,aAEhE5rF,EAAKuH,QAAUmzC,GCjCV,SAASskF,GAAwB7/H,EAAKN,EAAO6D,EAAM2vB,EAAQjR,EAAe,GAC3EviB,EAAQuiB,EACZiR,EAAOtuB,aAAc5E,EAAKN,EAAO6D,GAEjC2vB,EAAOptB,gBAAiB9F,EAAKuD,GAYxB,SAASu8H,GAAsB5sG,EAAQ2uB,EAAgBr9C,EAAa,IAC1E,MAAMu7H,EAAY7sG,EAAO3uB,cAAe,YAAaC,GAKrD,OAHA0uB,EAAO8+B,cAAe,YAAa+tE,GACnC7sG,EAAOruB,OAAQk7H,EAAWl+E,GAEnBk+E,EAUD,SAASC,GAAqBC,EAAYF,GAChD,MAAMG,EAAQH,EAAU9hH,OAAOA,OACzBkiH,EAAiBzqF,SAAUwqF,EAAM5/G,aAAc,mBAAsB,IACrE,OAAE8/G,GAAWH,EAAWI,gBAAiBN,GAE/C,QAASI,GAAkBC,EAASD,ECrCtB,SAASG,KACvB,OAAOp6E,IACNA,EAAW97B,GAAI,gBAAiB,CAAEpS,EAAKnX,EAAMolD,KAC5C,MAAMs6E,EAAY1/H,EAAKozD,SAGvB,IAAMhO,EAAcqB,WAAWj8C,KAAMk1H,EAAW,CAAEvhI,MAAM,IACvD,OAGD,MAAM,KAAEwhI,EAAI,YAAEC,EAAW,eAAEN,GAmE9B,SAAoBI,GACnB,MAAMG,EAAY,CACjBD,YAAa,EACbN,eAAgB,GAeXQ,EAAW,GACXC,EAAW,GAIjB,IAAIC,EAEJ,IAAM,MAAMC,KAAcz2H,MAAMiK,KAAMisH,EAAU34G,eAG/C,GAAyB,UAApBk5G,EAAW9hI,MAAwC,UAApB8hI,EAAW9hI,MAAwC,UAApB8hI,EAAW9hI,KAAmB,CAEvE,UAApB8hI,EAAW9hI,MAAqB6hI,IACpCA,EAAoBC,GAKrB,MAAMC,EAAM12H,MAAMiK,KAAMwsH,EAAWl5G,eAAgB1iB,OAAQ4wE,GAAMA,EAAGz0E,GAAI,UAAW,OAEnF,IAAM,MAAM2/H,KAAMD,EAEjB,GAAwB,UAAnBC,EAAG/iH,OAAOjf,MAAoBgiI,EAAG/iH,SAAW4iH,EAChDH,EAAUD,cACVE,EAASx8H,KAAM68H,OACT,CACNJ,EAASz8H,KAAM68H,GAGf,MAAMC,EAAcC,GAA0BF,GAEzCC,EAAcP,EAAUP,iBAC5BO,EAAUP,eAAiBc,IAShC,OAFAP,EAAUF,KAAO,IAAKG,KAAaC,GAE5BF,EA9HyCS,CAAWZ,GAGnD/7H,EAAa,GAEd27H,IACJ37H,EAAW27H,eAAiBA,GAGxBM,IACJj8H,EAAWi8H,YAAcA,GAG1B,MAAMP,EAAQj6E,EAAc/yB,OAAO3uB,cAAe,QAASC,GAE3D,GAAMyhD,EAAcsO,WAAY2rE,EAAOr/H,EAAKkzD,aAA5C,CAUA,GANA9N,EAAcqB,WAAWkH,QAAS+xE,EAAW,CAAEvhI,MAAM,IAGrDwhI,EAAK77H,QAASy8H,GAAOn7E,EAAcoW,YAAa+kE,EAAKn7E,EAAc/yB,OAAOo/B,iBAAkB4tE,EAAO,SAG9FA,EAAMv8G,QAAU,CACpB,MAAMy9G,EAAMn7E,EAAc/yB,OAAO3uB,cAAe,YAChD0hD,EAAc/yB,OAAOruB,OAAQu8H,EAAKn7E,EAAc/yB,OAAOo/B,iBAAkB4tE,EAAO,QAEhFJ,GAAsB75E,EAAc/yB,OAAQ+yB,EAAc/yB,OAAOo/B,iBAAkB8uE,EAAK,QAGzFn7E,EAAcuO,uBAAwB0rE,EAAOr/H,OA0GhD,SAASqgI,GAA0BF,GAClC,IAAIb,EAAiB,EACjBv8H,EAAQ,EAGZ,MAAMoF,EAAWqB,MAAMiK,KAAM0sH,EAAGp5G,eAC9B1iB,OAAQyiB,GAAwB,OAAfA,EAAM3oB,MAAgC,OAAf2oB,EAAM3oB,MAGhD,KAAQ4E,EAAQoF,EAAS/F,QAAqC,OAA3B+F,EAAUpF,GAAQ5E,MAAgB,CACpE,MAAMqiI,EAAKr4H,EAAUpF,GAKrBu8H,GAFgBzqF,SAAU2rF,EAAG/gH,aAAc,YAAe,GAG1D1c,IAGD,OAAOu8H,EC1KO,MAAMmB,GA0EpB,YAAapB,EAAO98H,EAAU,IAQ7BlC,KAAKqgI,OAASrB,EASdh/H,KAAKsgI,eAA4Bh6H,IAAhBpE,EAAQg+H,IAAoBh+H,EAAQg+H,IAAMh+H,EAAQq+H,UAAY,EAS/EvgI,KAAKwgI,aAA0Bl6H,IAAhBpE,EAAQg+H,IAAoBh+H,EAAQg+H,IAAMh+H,EAAQu+H,OASjEzgI,KAAK0gI,kBAAkCp6H,IAAnBpE,EAAQg9H,OAAuBh9H,EAAQg9H,OAASh9H,EAAQy+H,aAAe,EAS3F3gI,KAAK4gI,gBAAgCt6H,IAAnBpE,EAAQg9H,OAAuBh9H,EAAQg9H,OAASh9H,EAAQ2+H,UAS1E7gI,KAAK8gI,mBAAqB5+H,EAAQ6+H,gBASlC/gI,KAAKghI,UAAY,IAAI3oH,IAQrBrY,KAAKihI,KAAO,EAQZjhI,KAAKkhI,QAAU,EASflhI,KAAKmhI,WAAa,EASlBnhI,KAAKohI,cAAgB,IAAIttH,IAQzB9T,KAAKqhI,mBAAqB,EAQ3B,CAAE/iI,OAAOiW,YACR,OAAOvU,KAQR,OACC,MAAMkgI,EAAMlgI,KAAKqgI,OAAOnjH,SAAUld,KAAKihI,MAGvC,IAAMf,GAAOlgI,KAAKshI,gBACjB,MAAO,CAAEj2G,MAAM,GAGhB,GAAKrrB,KAAKuhI,mBACT,OAAOvhI,KAAKwhI,oBAGb,IAAIC,EAAW,KAEf,MAAMC,EAAW1hI,KAAK2hI,cAEtB,GAAKD,EACC1hI,KAAK8gI,mBAAqB9gI,KAAK4hI,oBACnCH,EAAWzhI,KAAK6hI,gBAAiBH,EAASI,KAAMJ,EAASxB,IAAKwB,EAASxC,aAElE,CACN,MAAM4C,EAAO5B,EAAIhjH,SAAUld,KAAKmhI,YAEhC,IAAMW,EAEL,OAAO9hI,KAAKwhI,oBAGb,MAAMO,EAAUvtF,SAAUstF,EAAK1iH,aAAc,YAAe,GACtD4iH,EAAUxtF,SAAUstF,EAAK1iH,aAAc,YAAe,IAGvD2iH,EAAU,GAAKC,EAAU,IAC7BhiI,KAAKiiI,aAAcH,EAAME,EAASD,GAG7B/hI,KAAK4hI,oBACVH,EAAWzhI,KAAK6hI,gBAAiBC,IAGlC9hI,KAAKqhI,kBAAoBrhI,KAAKkhI,QAAUa,EAWzC,OAPA/hI,KAAKkhI,UAEAlhI,KAAKkhI,SAAWlhI,KAAKqhI,mBACzBrhI,KAAKmhI,aAICM,GAAYzhI,KAAKurB,OASzB,QAAS20G,GACRlgI,KAAKghI,UAAUpyH,IAAKsxH,GASrB,oBAMC,OALAlgI,KAAKihI,OACLjhI,KAAKkhI,QAAU,EACflhI,KAAKmhI,WAAa,EAClBnhI,KAAKqhI,mBAAqB,EAEnBrhI,KAAKurB,OASb,gBAEC,YAAwBjlB,IAAjBtG,KAAKwgI,SAAyBxgI,KAAKihI,KAAOjhI,KAAKwgI,QASvD,mBAEC,YAA2Bl6H,IAApBtG,KAAK4gI,YAA4B5gI,KAAKkhI,QAAUlhI,KAAK4gI,WAY7D,gBAAiBkB,EAAMI,EAAYliI,KAAKihI,KAAMkB,EAAeniI,KAAKkhI,SACjE,MAAO,CACN71G,MAAM,EACN7sB,MAAO,IAAI4jI,GAAWpiI,KAAM8hI,EAAMI,EAAWC,IAU/C,kBACC,MAAME,EAAuBriI,KAAKghI,UAAUt3H,IAAK1J,KAAKihI,MAChDqB,EAAsBtiI,KAAKihI,KAAOjhI,KAAKsgI,UAEvCiC,EAA4BviI,KAAKkhI,QAAUlhI,KAAK0gI,aAChD8B,OAA6Cl8H,IAApBtG,KAAK4gI,YAA4B5gI,KAAKkhI,QAAUlhI,KAAK4gI,WAEpF,OAAOyB,GAAwBC,GAAuBC,GAA6BC,EASpF,cACC,MAAMC,EAASziI,KAAKohI,cAAchjI,IAAK4B,KAAKihI,MAG5C,OAAMwB,GAKCA,EAAOrkI,IAAK4B,KAAKkhI,UAJhB,KAeT,aAAcY,EAAME,EAASD,GAC5B,MAAMpiI,EAAO,CACZmiI,OACA5B,IAAKlgI,KAAKihI,KACV/B,OAAQl/H,KAAKkhI,SAGd,IAAM,IAAIwB,EAAc1iI,KAAKihI,KAAMyB,EAAc1iI,KAAKihI,KAAOe,EAASU,IACrE,IAAM,IAAIC,EAAiB3iI,KAAKkhI,QAASyB,EAAiB3iI,KAAKkhI,QAAUa,EAASY,IAC5ED,GAAe1iI,KAAKihI,MAAQ0B,GAAkB3iI,KAAKkhI,SACvDlhI,KAAK4iI,iBAAkBF,EAAaC,EAAgBhjI,GAcxD,iBAAkBugI,EAAKhB,EAAQv/H,GACxBK,KAAKohI,cAAc13H,IAAKw2H,IAC7BlgI,KAAKohI,cAAc33H,IAAKy2H,EAAK,IAAIpsH,KAGjB9T,KAAKohI,cAAchjI,IAAK8hI,GAEhCz2H,IAAKy1H,EAAQv/H,IAOxB,MAAMyiI,GAUL,YAAaS,EAAaf,EAAMI,EAAWC,GAO1CniI,KAAK8hI,KAAOA,EAQZ9hI,KAAKkgI,IAAM2C,EAAY5B,KAQvBjhI,KAAKk/H,OAAS2D,EAAY3B,QAQ1BlhI,KAAK8iI,cAAgBZ,EAQrBliI,KAAK+iI,iBAAmBZ,EASxBniI,KAAKmhI,WAAa0B,EAAY1B,WAS9BnhI,KAAKqgI,OAASwC,EAAYxC,OAS3B,eACC,OAAOrgI,KAAKkgI,MAAQlgI,KAAK8iI,eAAiB9iI,KAAKk/H,SAAWl/H,KAAK+iI,iBAShE,gBACC,OAAOvuF,SAAUx0C,KAAK8hI,KAAK1iH,aAAc,YAAe,GASzD,iBACC,OAAOo1B,SAAUx0C,KAAK8hI,KAAK1iH,aAAc,YAAe,GAQzD,oBAGC,OAFcpf,KAAKqgI,OAAOxjI,KAAKmE,SAASgoD,MAE3BoI,iBAAkBpxD,KAAKqgI,OAAOnjH,SAAUld,KAAKkgI,KAAOlgI,KAAKmhI,aC7ejE,SAAS6B,GAAqB9gI,EAAU,IAC9C,OAAO8iD,GAAcA,EAAW97B,GAAI,eAAgB,CAAEpS,EAAKnX,EAAMolD,KAChE,MAAMi6E,EAAQr/H,EAAK0C,KAEnB,IAAM0iD,EAAcqB,WAAWkH,QAAS0xE,EAAO,UAC9C,OAIDj6E,EAAcqB,WAAWkH,QAAS0xE,EAAO,+BACzCj6E,EAAcqB,WAAWkH,QAAS0xE,EAAO,kCAEzC,MAAMiE,EAAW/gI,GAAWA,EAAQ+gI,SAE9BC,EAAgBn+E,EAAc/yB,OAAOy+B,uBAAwB,SAAU,CAAEstB,MAAO,UAChFolD,EAAep+E,EAAc/yB,OAAOy+B,uBAAwB,SAGlE,IAAI2yE,EA8PN,IAAwBtoG,EAAa9I,EAhQnC+yB,EAAc/yB,OAAOruB,OAAQohD,EAAc/yB,OAAOo/B,iBAAkB8xE,EAAe,GAAKC,GAInFF,IA4PiBnoG,EA3PQooG,GA2PKlxG,EA3PU+yB,EAAc/yB,QA4PrDg2E,kBAAmB,SAAS,EAAMltE,GA5PvCsoG,EA8PKr7B,GAAUjtE,EAAa9I,EAAQ,CAAEm2E,oBAAoB,KA3P3D,MAAM06B,EAAc,IAAIzC,GAAapB,GAE/BqE,EAAkB,CACvB9D,YAAaP,EAAM5/G,aAAc,gBAAmB,EACpD6/G,eAAgBD,EAAM5/G,aAAc,mBAAsB,GAIrDkkH,EAAW,IAAIxvH,IAErB,IAAM,MAAMyvH,KAAaV,EAAc,CACtC,MAAM,IAAE3C,EAAG,KAAE4B,GAASyB,EAEhBC,EAAWxE,EAAM9hH,SAAUgjH,GAC3BuD,EAAYH,EAASllI,IAAK8hI,IAASwD,GAAUP,EAAcK,EAAUtD,EAAKmD,EAAiBt+E,GACjGu+E,EAAS75H,IAAKy2H,EAAKuD,GAGnB1+E,EAAcqB,WAAWkH,QAASw0E,EAAM,UAIxC6B,GAA4BJ,EAAWF,EAFhBt+E,EAAc/yB,OAAOo/B,iBAAkBqyE,EAAW,OAED1+E,EAAe7iD,GAKxF,IAAM,MAAMshI,KAAYxE,EAAMt4G,cAAgB,CAC7C,MAAMk9G,EAAWJ,EAAS9gI,MAEpB4gI,EAAS55H,IAAKk6H,IACnBN,EAAS75H,IAAKm6H,EAAUF,GAAUP,EAAcK,EAAUI,EAAUP,EAAiBt+E,IAIvF,MAAMvuB,EAAeuuB,EAAcpB,OAAOD,eAAgB/jD,EAAKsvB,MAAMpO,OAErEkkC,EAAcpB,OAAOrgB,aAAc07F,EAAOiE,EAAWG,EAAcF,GACnEn+E,EAAc/yB,OAAOruB,OAAQ6yB,EAAcysG,EAAWG,EAAcF,KAuK/D,SAASW,GAA6B7gF,EAAc+B,GAC1D,MAAM,OAAE/yB,GAAW+yB,EAEnB,GAAM/B,EAAajmC,OAAO5c,GAAI,UAAW,aAIzC,OAAK2jI,GAAoC9gF,GAGjChxB,EAAOy+B,uBAAwB,OAAQ,CAAErtD,MAAO,yBAEhD4uB,EAAOy+B,uBAAwB,KAejC,SAASqzE,GAAoC9gF,GAKnD,OAFmD,IAFjCA,EAAajmC,OAEK+J,aAEP,GAAiBk8B,GAmD/C,SAAS+gF,GAA+BR,EAAWF,EAAiBt+E,GACnE,MAAM,KAAE+8E,GAASyB,EAGXS,EAAyBC,GAAoBV,EAAWF,GAExDa,EAAWn/E,EAAcpB,OAAOR,cAAe2+E,GAIhDoC,GAAYA,EAASpmI,OAASkmI,GArCpC,SAA8BnF,EAAWmF,EAAwBj/E,GAChE,MAAMiJ,EAAajJ,EAAc/yB,OAC3BkyG,EAAWn/E,EAAcpB,OAAOR,cAAe07E,GAG/CsF,EAAcz7B,GADH16C,EAAWy3D,sBAAuBue,EAAwBE,EAASnpG,iBACpCizB,GAEhDu6C,GACC47B,EACAn2E,EACA,CAAEpvC,EAASqwC,EAAYj9B,IAAYA,EAAO2K,SAAUtiB,GAAS40C,EAAWtwC,SAAWC,GACnF,CAAEA,EAASqwC,EAAYj9B,IAAYA,EAAO6K,YAAaxiB,GAAS40C,EAAWtwC,SAAWC,IAGvFovC,EAAWrqD,OAAQqqD,EAAW2O,oBAAqBunE,GAAYC,GAC/Dn2E,EAAWz1B,KAAMy1B,EAAW0G,cAAewvE,GAAYl2E,EAAWoD,iBAAkB+yE,EAAa,IACjGn2E,EAAW7pD,OAAQ6pD,EAAWjH,cAAem9E,IAE7Cn/E,EAAcpB,OAAOqD,kBAAmBk9E,GACxCn/E,EAAcpB,OAAOrgB,aAAcu7F,EAAWsF,GAmB7CC,CAAqBtC,EAAMkC,EAAwBj/E,GASrD,SAAS4+E,GAA4BJ,EAAWF,EAAiB1iF,EAAgBoE,EAAe7iD,GAC/F,MAAM+gI,EAAW/gI,GAAWA,EAAQ+gI,SAC9BoB,EAAkBJ,GAAoBV,EAAWF,GAEjDiB,EAAcrB,EACnBv6B,GAAkB3jD,EAAc/yB,OAAOyzF,sBAAuB4e,GAAmBt/E,EAAc/yB,QAC/F+yB,EAAc/yB,OAAOy+B,uBAAwB4zE,GAEzCpB,GACJ16B,GACC+7B,EACAv/E,EAAc/yB,OACd,CAAEpT,EAASqwC,EAAYj9B,IAAYA,EAAO2K,SAAUtiB,GAAS40C,EAAWtwC,SAAWC,GACnF,CAAEA,EAASqwC,EAAYj9B,IAAYA,EAAO6K,YAAaxiB,GAAS40C,EAAWtwC,SAAWC,IAIxF,MAAMigH,EAAY0E,EAAUzB,KAEtB98H,EAAa65H,EAAU3hH,SAAU,GACjCqnH,EAA6C,IAAzB1F,EAAU/3G,YAAwC,cAApB9hB,EAAWlH,KAOnE,GALAinD,EAAc/yB,OAAOruB,OAAQg9C,EAAgB2jF,GAE7Cv/E,EAAcpB,OAAOrgB,aAAcu7F,EAAWyF,IAGxCrB,IAAa,GAAiBj+H,IAAgBu/H,EAAoB,CACvE,MAAMC,EAAiB3F,EAAU3hH,SAAU,GAE3C6nC,EAAcqB,WAAWkH,QAASk3E,EAAgB,UAElDz/E,EAAcpB,OAAOrgB,aAAckhG,EAAgBF,IAYrD,SAASZ,GAAUP,EAAcK,EAAUI,EAAUP,EAAiBt+E,GAErEA,EAAcqB,WAAWkH,QAASk2E,EAAU,UAE5C,MAAMC,EAAYD,EAAS/gH,QAC1BsiC,EAAc/yB,OAAOw8D,mBAAoB,MACzCzpC,EAAc/yB,OAAOy+B,uBAAwB,MAE9C1L,EAAcpB,OAAOrgB,aAAckgG,EAAUC,GAE7C,MAAMlE,EAAc8D,EAAgB9D,YAC9BkF,EAiDP,SAAkCC,EAAarF,EAAWt6E,GACzD,MAAM4/E,EAAmBC,GAAgCF,EAAarF,GAEtE,OAAOsF,GAsBR,SAA6BD,EAAavB,EAAcp+E,GACvD,MAAM8/E,EAAoB9/E,EAAc/yB,OAAOy+B,uBAAwBi0E,GAEjE/jF,EAAiBoE,EAAc/yB,OAAOo/B,iBAAkB+xE,EAA6B,SAAfuB,EAAyB,MAAQ,GAI7G,OAFA3/E,EAAc/yB,OAAOruB,OAAQg9C,EAAgBkkF,GAEtCA,EA7BsCC,CAAoBJ,EAAarF,EAAWt6E,GApDpEggF,CAsCtB,SAAyB7E,EAAKmD,GAC7B,OAAOnD,EAAMmD,EAAgB9D,YAAc,QAAU,QAvCPyF,CAAgBpB,EAAUP,GAAmBF,EAAcp+E,GAEnGz4C,EAASizH,EAAc,GAAKqE,GAAYrE,EAAcqE,EAAWrE,EAAcqE,EAC/E/4G,EAAWk6B,EAAc/yB,OAAOo/B,iBAAkBqzE,EAAcn4H,GAItE,OAFAy4C,EAAc/yB,OAAOruB,OAAQknB,EAAU44G,GAEhCA,EAQR,SAASQ,GAAoBV,EAAWF,GACvC,MAAM,IAAEnD,EAAG,OAAEhB,GAAWqE,GAClB,eAAEtE,EAAc,YAAEM,GAAgB8D,EAMxC,GAHwB9D,GAAeA,EAAcW,EAIpD,MAAO,KAMR,OAFqBjB,GAAkBA,EAAiBC,EAElC,KAAO,KA8B9B,SAAS0F,GAAgCF,EAAavB,GACrD,IAAM,MAAMsB,KAAgBtB,EAAaz8G,cACxC,GAAK+9G,EAAa3mI,MAAQ4mI,EACzB,OAAOD,EA0BV,SAASQ,GAA2BP,EAAavB,EAAcp+E,GAC9D,MAAM0/E,EAAeG,GAAgCF,EAAavB,GAE7DsB,GAA4C,IAA5BA,EAAa39G,YACjCi+B,EAAc/yB,OAAO7tB,OAAQ4gD,EAAc/yB,OAAO+0B,cAAe09E,IAmBnE,SAAS,GAAiB7lH,GACzB,QAAS,IAAKA,EAAQ4W,oBAAqBzzB,OCnf7B,MAAM,WAA2BsrF,GAI/C,UACC,MAAMrkC,EAAQhpD,KAAKuc,OAAOysC,MACpB5+B,EAAY4+B,EAAMhoD,SAASopB,UAC3B6+B,EAASD,EAAMC,OAEfi8E,EAqCR,SAA+Br6G,GAC9B,MAAM9N,EAAS8N,EAAS9N,OAExB,OAAOA,IAAWA,EAAOlgB,KAAOkgB,EAASA,EAAOA,OAxC3BooH,CAAsB/6G,EAAUoH,oBAEpDxxB,KAAKsvC,UAAY2Z,EAAOiH,WAAYg1E,EAAa,SAelD,QAAShjI,EAAU,IAClB,MAAM8mD,EAAQhpD,KAAKuc,OAAOysC,MACpB5+B,EAAY4+B,EAAMhoD,SAASopB,UAC3B20G,EAAa/+H,KAAKuc,OAAOtE,QAAQ7Z,IAAK,cAEtCuiD,EAAiBgoD,GAA8Bv+E,EAAW4+B,GAEhEA,EAAM5L,OAAQprB,IACb,MAAMgtG,EAAQD,EAAWqG,YAAapzG,EAAQ9vB,GAE9C8mD,EAAM6pB,cAAemsD,EAAOr+E,GAE5B3uB,EAAOyI,aAAczI,EAAOo/B,iBAAkB4tE,EAAM9rD,cAAe,CAAE,EAAG,EAAG,IAAO,OCxC9E,SAASmyD,GAAuBj7G,GACtC,MAAMk7G,EAAQ,GAEd,IAAM,MAAMr2G,KAASs2G,GAAYn7G,EAAU8F,aAAgB,CAC1D,MAAMtR,EAAUqQ,EAAMqB,sBAEjB1R,GAAWA,EAAQze,GAAI,UAAW,cACtCmlI,EAAMriI,KAAM2b,GAId,OAAO0mH,EAaD,SAASE,GAAkCp7G,GACjD,MAAMk7G,EAAQ,GAEd,IAAM,MAAMr2G,KAAS7E,EAAU8F,YAAc,CAC5C,MAAMu1G,EAAoBx2G,EAAMpO,MAAM+iB,aAAc,aAE/C6hG,GACJH,EAAMriI,KAAMwiI,GAId,OAAOH,EAcD,SAASI,GAAgCt7G,GAC/C,MAAMu7G,EAAgBN,GAAuBj7G,GAE7C,OAAKu7G,EAAc5jI,OACX4jI,EAGDH,GAAkCp7G,GAenC,SAASw7G,GAAeC,GAG9B,OAAOC,GAFSD,EAAWx7H,IAAKy3H,GAAQA,EAAK/kH,OAAOra,QAiB9C,SAASqjI,GAAkBF,GACjC,MAAM7G,EAAQ6G,EAAY,GAAIjiG,aAAc,SAO5C,OAAOkiG,GANU,IAAK,IAAI1F,GAAapB,IAGrCh7H,OAAQwF,GAASq8H,EAAWzsH,SAAU5P,EAAMs4H,OAC5Cz3H,IAAKb,GAASA,EAAM01H,SAgChB,SAAS8G,GAAwBC,EAAoBlH,GAC3D,GAAKkH,EAAmBlkI,OAAS,IAsGlC,SAAuC8jI,GACtC,MAAM7G,EAAQ6G,EAAY,GAAIjiG,aAAc,SAEtCsiG,EAAaN,GAAeC,GAC5BtG,EAAc/qF,SAAUwqF,EAAM5/G,aAAc,gBAAmB,GAGrE,IAAM+mH,GAAyBD,EAAY3G,GAC1C,OAAO,EAGR,MAAMN,EAAiBzqF,SAAUwqF,EAAM5/G,aAAc,mBAAsB,GAI3E,OAAO+mH,GAHeJ,GAAkBF,GAGO5G,GArHRmH,CAA8BH,GACpE,OAAO,EAMR,MAAM3G,EAAO,IAAIjnH,IACXguH,EAAU,IAAIhuH,IAEpB,IAAIiuH,EAAsB,EAE1B,IAAM,MAAMzH,KAAaoH,EAAqB,CAC7C,MAAM,IAAE/F,EAAG,OAAEhB,GAAWH,EAAWI,gBAAiBN,GAC9CmD,EAAUxtF,SAAUqqF,EAAUz/G,aAAc,YAAe,GAC3D2iH,EAAUvtF,SAAUqqF,EAAUz/G,aAAc,YAAe,GAGjEkgH,EAAK1wH,IAAKsxH,GACVmG,EAAQz3H,IAAKswH,GAGR8C,EAAU,GACd1C,EAAK1wH,IAAKsxH,EAAM8B,EAAU,GAItBD,EAAU,GACdsE,EAAQz3H,IAAKswH,EAAS6C,EAAU,GAGjCuE,GAAyBtE,EAAUD,EAMpC,OAuCD,SAAkCzC,EAAM+G,GACvC,MAAME,EAAcp9H,MAAMiK,KAAMksH,EAAKjzH,UAC/Bm6H,EAAgBr9H,MAAMiK,KAAMizH,EAAQh6H,UAEpCo6H,EAAUr2H,KAAKsR,OAAQ6kH,GACvBG,EAAWt2H,KAAK0M,OAAQypH,GACxBI,EAAav2H,KAAKsR,OAAQ8kH,GAC1BI,EAAcx2H,KAAK0M,OAAQ0pH,GAEjC,OAASC,EAAUC,EAAW,IAAQC,EAAaC,EAAc,GAlDpCC,CAAyBvH,EAAM+G,IAE7BC,EASzB,SAASf,GAAY13G,GAC3B,OAAO1kB,MAAMiK,KAAMya,GAAS3J,KAAM4iH,IAInC,SAAShB,GAA2BiB,GACnC,MAAMC,EAAmBD,EAAQ7iH,KAAM,CAAE+iH,EAAQhyC,IAAYgyC,EAAShyC,GAKtE,MAAO,CAAE7lE,MAHK43G,EAAkB,GAGhB33G,KAFH23G,EAAkBA,EAAiBjlI,OAAS,IAK1D,SAAS+kI,GAAmB32G,EAAQE,GAEnC,MAAM62G,EAAO/2G,EAAOtP,MACdsmH,EAAO92G,EAAOxP,MAKpB,OAAOqmH,EAAKrpH,SAAUspH,IAAU,EAAI,EAqDrC,SAAShB,IAAyB,MAAE/2G,EAAK,KAAEC,GAAQ+3G,GAIlD,OAH6Bh4G,EAAQg4G,IACT/3G,EAAO+3G,ECpPrB,MAAM,WAAyB/5C,GAS7C,YAAa9wE,EAAQra,EAAU,IAC9BtC,MAAO2c,GAQPvc,KAAKm5H,MAAQj3H,EAAQi3H,OAAS,QAM/B,UACC,MAEMkO,EAFYrnI,KAAKuc,OAAOysC,MAAMhoD,SAASopB,UAEfoH,mBAAmBoS,aAAc,SAE/D5jC,KAAKsvC,YAAc+3F,EAUpB,UACC,MAAM9qH,EAASvc,KAAKuc,OACd6N,EAAY7N,EAAOysC,MAAMhoD,SAASopB,UAClC20G,EAAaxiH,EAAOtE,QAAQ7Z,IAAK,cACjCkpI,EAA6B,UAAftnI,KAAKm5H,MAEnBoO,EAAqB7B,GAAgCt7G,GACrD87G,EAAaN,GAAe2B,GAE5BrH,EAAMoH,EAAcpB,EAAW92G,MAAQ82G,EAAW72G,KAClD2vG,EAAQuI,EAAoB,GAAI3jG,aAAc,SAEpDm7F,EAAWyI,WAAYxI,EAAO,CAAEyI,GAAIH,EAAcpH,EAAMA,EAAM,EAAGwH,wBAAyBJ,KCnD7E,MAAM,WAA4Bj6C,GAShD,YAAa9wE,EAAQra,EAAU,IAC9BtC,MAAO2c,GAQPvc,KAAKm5H,MAAQj3H,EAAQi3H,OAAS,QAM/B,UACC,MAEMkO,EAFYrnI,KAAKuc,OAAOysC,MAAMhoD,SAASopB,UAEfoH,mBAAmBoS,aAAc,SAE/D5jC,KAAKsvC,YAAc+3F,EAWpB,UACC,MAAM9qH,EAASvc,KAAKuc,OACd6N,EAAY7N,EAAOysC,MAAMhoD,SAASopB,UAClC20G,EAAaxiH,EAAOtE,QAAQ7Z,IAAK,cACjCsG,EAA8B,SAAf1E,KAAKm5H,MAEpBoO,EAAqB7B,GAAgCt7G,GACrDo8G,EAAgBT,GAAkBwB,GAElCrI,EAASx6H,EAAe8hI,EAAcp3G,MAAQo3G,EAAcn3G,KAC5D2vG,EAAQuI,EAAoB,GAAI3jG,aAAc,SAEpDm7F,EAAW4I,cAAe3I,EAAO,CAAEqH,QAAS,EAAGoB,GAAI/iI,EAAew6H,EAASA,EAAS,KCxDvE,MAAM,WAAyB7xC,GAQ7C,YAAa9wE,EAAQra,EAAU,IAC9BtC,MAAO2c,GAQPvc,KAAK4qB,UAAY1oB,EAAQ0oB,WAAa,eAMvC,UACC,MAAM+6G,EAAgBD,GAAgC1lI,KAAKuc,OAAOysC,MAAMhoD,SAASopB,WAEjFpqB,KAAKsvC,UAAqC,IAAzBq2F,EAAc5jI,OAMhC,UACC,MAAM88H,EAAY6G,GAAgC1lI,KAAKuc,OAAOysC,MAAMhoD,SAASopB,WAAa,GACpFw9G,EAAkC,iBAAnB5nI,KAAK4qB,UACpBm0G,EAAa/+H,KAAKuc,OAAOtE,QAAQ7Z,IAAK,cAEvCwpI,EACJ7I,EAAW8I,sBAAuBhJ,EAAW,GAE7CE,EAAW+I,oBAAqBjJ,EAAW,IChBvC,SAASkJ,GAAuBC,EAAaC,EAAgBj2G,GACnE,MAAM,SAAEuuG,EAAQ,YAAEI,EAAW,OAAEF,EAAM,UAAEI,GAAcoH,EAG/CC,EAAel2G,EAAO3uB,cAAe,SACrC8kI,EAAa1H,EAASF,EAAW,EAEvC,IAAM,IAAIhjI,EAAI,EAAGA,EAAI4qI,EAAY5qI,IAChCy0B,EAAO8+B,cAAe,WAAYo3E,EAAc,OAGjD,MAAME,EAAW,IAAK,IAAIhI,GAAa4H,EAAa,CAAEzH,WAAUE,SAAQE,cAAaE,YAAWE,iBAAiB,KAGjH,IAAM,MAAQb,IAAKmI,EAAWnJ,OAAQoJ,EAAcxG,KAAMjD,EAAS,SAAE0J,EAAQ,cAAEzF,EAAa,iBAAEC,KAAsBqF,EAAW,CAE9H,MAAMI,EAAoBH,EAAY9H,EAChCL,EAAMgI,EAAahrH,SAAUsrH,GAGnC,GAAMD,EAQD,CACJ,MAAME,EAAgBz2G,EAAOqhD,aAAcwrD,GAE3C7sG,EAAO6pC,OAAQ4sE,EAAevI,GAI9BwI,GAAuBD,EAAeJ,EAAWC,EAAc7H,EAAQI,EAAW7uG,QAZ7E8wG,EAAgBvC,GAAYwC,EAAmBpC,IACnD/B,GAAsB5sG,EAAQA,EAAOo/B,iBAAkB8uE,EAAK,QAkB/D,OAkND,SAAoCgI,EAAcF,EAAazH,EAAUI,EAAa3uG,GACrF,MAAMutG,EAAc/qF,SAAUwzF,EAAY5oH,aAAc,gBAAmB,GAE3E,GAAKmgH,EAAc,EAAI,CAEtBZ,GAAwB,cADEY,EAAcgB,EACkB2H,EAAcl2G,EAAQ,GAGjF,MAAMitG,EAAiBzqF,SAAUwzF,EAAY5oH,aAAc,mBAAsB,GAEjF,GAAK6/G,EAAiB,EAAI,CAEzBN,GAAwB,iBADKM,EAAiB0B,EACkBuH,EAAcl2G,EAAQ,IAhOvF22G,CAA2BT,EAAcF,EAAazH,EAAUI,EAAa3uG,GAEtEk2G,EA2BD,SAASU,GAA+B5J,EAAO6J,EAAYtI,EAAW,GAC5E,MAAM+E,EAAQ,GAERzC,EAAc,IAAIzC,GAAapB,EAAO,CAAEuB,WAAUE,OAAQoI,EAAa,IAE7E,IAAM,MAAMC,KAAYjG,EAAc,CACrC,MAAM,IAAE3C,EAAG,WAAE6I,GAAeD,EACtBE,EAAa9I,EAAM6I,EAAa,EAEjC7I,EAAM2I,GAAcA,GAAcG,GACtC1D,EAAMriI,KAAM6lI,GAId,OAAOxD,EAWD,SAAS2D,GAAmBpK,EAAWqK,EAAUl3G,GACvD,MAAMwxG,EAAW3E,EAAU9hH,OACrBiiH,EAAQwE,EAASzmH,OACjB6mH,EAAWJ,EAAS9gI,MAGpBymI,EAAaD,EAAWtF,EAExBwF,EAAoB,GACpBC,EAJU70F,SAAUqqF,EAAUz/G,aAAc,YAIjB+pH,EAE5BE,EAAiB,IACrBD,EAAkBpH,QAAUqH,GAG7B,MAAMtH,EAAUvtF,SAAUqqF,EAAUz/G,aAAc,YAAe,GAE5D2iH,EAAU,IACdqH,EAAkBrH,QAAUA,GAG7B,MACMtB,EADWmD,EACSuF,EACpBf,EAAW,IAAK,IAAIhI,GAAapB,EAAO,CAAEuB,SAF/BqD,EAEyCnD,SAAQM,iBAAiB,KAEnF,IACIuI,EADAC,EAAU,KAGd,IAAM,MAAMhG,KAAa6E,EAAW,CACnC,MAAM,IAAElI,EAAG,OAAEhB,EAAM,KAAE4C,GAASyB,EAEzBzB,IAASjD,QAA6Bv4H,IAAhBgjI,IAC1BA,EAAcpK,QAGM54H,IAAhBgjI,GAA6BA,IAAgBpK,GAAUgB,IAAQO,IACnE8I,EAAU3K,GAAsB5sG,EAAQuxG,EAAUiG,oBAAqBJ,IAOzE,OAFAzK,GAAwB,UAAWwK,EAAYtK,EAAW7sG,GAEnDu3G,EA6BD,SAASE,GAAiCzK,EAAO0K,GACvD,MAAMC,EAAe,GAEf9G,EAAc,IAAIzC,GAAapB,GAErC,IAAM,MAAM8J,KAAYjG,EAAc,CACrC,MAAM,OAAE3D,EAAM,UAAE0K,GAAcd,EACxBe,EAAgB3K,EAAS0K,EAAY,EAEtC1K,EAASwK,GAAiBA,GAAiBG,GAC/CF,EAAa1mI,KAAM6lI,GAIrB,OAAOa,EAYD,SAASG,GAAiBjL,EAAWyK,EAAaS,EAAa/3G,GACrE,MACMg4G,EAAaD,EAAcT,EAE3BF,EAAoB,GACpBa,EAJUz1F,SAAUqqF,EAAUz/G,aAAc,YAIjB4qH,EAE5BC,EAAiB,IACrBb,EAAkBrH,QAAUkI,GAG7B,MAAMjI,EAAUxtF,SAAUqqF,EAAUz/G,aAAc,YAAe,GAE5D4iH,EAAU,IACdoH,EAAkBpH,QAAUA,GAG7B,MAAMuH,EAAU3K,GAAsB5sG,EAAQA,EAAO2qC,oBAAqBkiE,GAAauK,GAKvF,OAFAzK,GAAwB,UAAWqL,EAAYnL,EAAW7sG,GAEnDu3G,EAgBD,SAASb,GAAuB7J,EAAWqL,EAASC,EAAYC,EAAUC,EAAar4G,GAC7F,MAAM+vG,EAAUvtF,SAAUqqF,EAAUz/G,aAAc,YAAe,GAC3D4iH,EAAUxtF,SAAUqqF,EAAUz/G,aAAc,YAAe,GAIjE,GAFkB+qH,EAAapI,EAAU,EAExBsI,EAAc,CAG9B1L,GAAwB,UAFJ0L,EAAcF,EAAa,EAECtL,EAAW7sG,EAAQ,GAKpE,GAFek4G,EAAUlI,EAAU,EAErBoI,EAAW,CAGxBzL,GAAwB,UAFJyL,EAAWF,EAAU,EAEOrL,EAAW7sG,EAAQ,IA6C9D,SAASs4G,GAAoBtL,EAAOD,GAC1C,MAAM/4F,EAAQ+4F,EAAWwL,WAAYvL,GAC/BwL,EAAa,IAAIrhI,MAAO68B,GAAQ/1B,KAAM,GAE5C,IAAM,MAAM,OAAEivH,KAAY,IAAIkB,GAAapB,GAC1CwL,EAAYtL,KAGb,MAAMuL,EAAeD,EAAWnzH,OAAQ,CAAEvV,EAAQ4oI,EAAYxL,IACtDwL,EAAa5oI,EAAS,IAAKA,EAAQo9H,GACxC,IAEH,GAAKuL,EAAa1oI,OAAS,EAAI,CAE9B,MAAM4oI,EAAcF,EAAcA,EAAa1oI,OAAS,GAKxD,OAFAg9H,EAAW6L,cAAe5L,EAAO,CAAEyI,GAAIkD,KAEhC,EAGR,OAAO,EAkCD,SAASE,GAAiB7L,EAAOD,GACvC,MAAM+L,EAAY,GAElB,IAAM,IAAIlH,EAAW,EAAGA,EAAW5E,EAAMl4G,WAAY88G,IAAa,CAChD5E,EAAM9hH,SAAU0mH,GAEnBnhH,SACbqoH,EAAU7nI,KAAM2gI,GAIlB,GAAKkH,EAAU/oI,OAAS,EAAI,CAE3B,MAAMgpI,EAAWD,EAAWA,EAAU/oI,OAAS,GAK/C,OAFAg9H,EAAWiM,WAAYhM,EAAO,CAAEyI,GAAIsD,KAE7B,EAGR,OAAO,EA6BD,SAASE,GAAwBjM,EAAOD,GACvBuL,GAAoBtL,EAAOD,IAIjD8L,GAAiB7L,EAAOD,GA4BnB,SAASmM,GAAoBlM,EAAOmM,GAC1C,MAAMC,EAAajiI,MAAMiK,KAAM,IAAIgtH,GAAapB,EAAO,CACtD2B,YAAawK,EAAWvE,YACxB/F,UAAWsK,EAAWxE,WACtBzG,IAAKiL,EAAW1E,WAMjB,GAHkC2E,EAAWlhH,MAAO,EAAI6+G,gBAAiC,IAAfA,GAIzE,OAAOoC,EAAW1E,QAInB,MAAM4E,EAAoBD,EAAY,GAAIrC,WAAa,EACvD,OAAOoC,EAAW1E,QAAU4E,EA8BtB,SAASC,GAAuBtM,EAAOmM,GAC7C,MAAMI,EAAgBpiI,MAAMiK,KAAM,IAAIgtH,GAAapB,EAAO,CACzDuB,SAAU4K,EAAWzE,SACrBjG,OAAQ0K,EAAW1E,QACnBvH,OAAQiM,EAAWxE,cAMpB,GAHkC4E,EAAcrhH,MAAO,EAAI0/G,eAA+B,IAAdA,GAI3E,OAAOuB,EAAWxE,WAInB,MAAM6E,EAAoBD,EAAe,GAAI3B,UAAY,EACzD,OAAOuB,EAAWxE,WAAa6E,EC5fjB,MAAM,WAAyBn+C,GAS7C,YAAa9wE,EAAQra,GACpBtC,MAAO2c,GAQPvc,KAAK4qB,UAAY1oB,EAAQ0oB,UAQzB5qB,KAAK4nI,aAAiC,SAAlB5nI,KAAK4qB,WAA0C,QAAlB5qB,KAAK4qB,UAMvD,UACC,MAAM6gH,EAAczrI,KAAK0rI,oBAEzB1rI,KAAKxB,MAAQitI,EACbzrI,KAAKsvC,YAAcm8F,EAUpB,UACC,MAAMziF,EAAQhpD,KAAKuc,OAAOysC,MAEpB61E,EAAY2G,GADNx8E,EAAMhoD,SACsCopB,WAAa,GAE/DqhH,EAAczrI,KAAKxB,MACnBosB,EAAY5qB,KAAK4qB,UAEvBo+B,EAAM5L,OAAQprB,IACb,MAAM25G,EAA2B,SAAb/gH,GAAqC,QAAbA,EAGtCghH,EAAeD,EAAc9M,EAAY4M,EACzCI,EAAeF,EAAcF,EAAc5M,EAG3CiN,EAAsBD,EAAa9uH,QA6J5C,SAA0B8uH,EAAcD,EAAc55G,GAC/C,GAAS65G,KACT,GAASD,IACb55G,EAAO7tB,OAAQ6tB,EAAO0iC,cAAek3E,IAGtC55G,EAAOuG,KAAMvG,EAAO0iC,cAAem3E,GAAgB75G,EAAOo/B,iBAAkBw6E,EAAc,SAI3F55G,EAAO7tB,OAAQ0nI,GArKbE,CAAiBF,EAAcD,EAAc55G,GAE7C,MAAMg6G,EAAgBhsI,KAAK4nI,aAAe,UAAY,UAChDqE,EAAWz3F,SAAUqqF,EAAUz/G,aAAc4sH,IAAmB,GAChEE,EAAkB13F,SAAUi3F,EAAYrsH,aAAc4sH,IAAmB,GAG/Eh6G,EAAOtuB,aAAcsoI,EAAeC,EAAWC,EAAiBN,GAChE55G,EAAOyI,aAAczI,EAAO0iC,cAAek3E,IAE3C,MAAM7M,EAAa/+H,KAAKuc,OAAOtE,QAAQ7Z,IAAK,cAI5C6sI,GAHca,EAAoBloG,aAAc,SAGjBm7F,KAUjC,oBACC,MAEMF,EAAY2G,GAFJxlI,KAAKuc,OAAOysC,MACRhoD,SACsCopB,WAAa,GAErE,IAAMy0G,EACL,OAGD,MAAME,EAAa/+H,KAAKuc,OAAOtE,QAAQ7Z,IAAK,cAGtCqtI,EAAczrI,KAAK4nI,aAyB3B,SAA4B/I,EAAWj0G,EAAWm0G,GACjD,MACMC,EADWH,EAAU9hH,OACJA,OACjBovH,EAA8B,SAAbvhH,EAAuBi0G,EAAU3wG,YAAc2wG,EAAU1wG,gBAC1Ei+G,GAAsBpN,EAAM5/G,aAAc,mBAAsB,GAAM,EAE5E,IAAM+sH,EACL,OAID,MAAME,EAA0B,SAAbzhH,EAAuBi0G,EAAYsN,EAChDG,EAA2B,SAAb1hH,EAAuBuhH,EAAiBtN,GAGpDK,OAAQqN,GAAmBxN,EAAWI,gBAAiBkN,IACvDnN,OAAQsN,GAAoBzN,EAAWI,gBAAiBmN,GAE1DG,EAAej4F,SAAU63F,EAAWjtH,aAAc,YAAe,GAEjEstH,EAA8B5N,GAAqBC,EAAYsN,GAC/DM,EAA+B7N,GAAqBC,EAAYuN,GAGtE,GAAKF,GAAqBM,GAA+BC,EACxD,OAOD,OAHyBJ,EAAiBE,IAAiBD,EAGjCL,OAAiB7lI,EAxDzCsmI,CAAmB/N,EAAW7+H,KAAK4qB,UAAWm0G,GAgEjD,SAA0BF,EAAWj0G,GACpC,MAAM44G,EAAW3E,EAAU9hH,OACrBiiH,EAAQwE,EAASzmH,OAEjB6mH,EAAW5E,EAAM/hH,cAAeumH,GAGtC,GAAoB,QAAb54G,GAAuBg5G,IAAa5E,EAAMl4G,WAAa,GAAsB,MAAb8D,GAAkC,IAAbg5G,EAC3F,OAGD,MAAM5B,EAAUxtF,SAAUqqF,EAAUz/G,aAAc,YAAe,GAC3DmgH,EAAcP,EAAM5/G,aAAc,gBAAmB,EAErDytH,EAAmC,QAAbjiH,GAAyBg5G,EAAW5B,IAAczC,EACxEuN,EAAmC,MAAbliH,GAAqBg5G,IAAarE,EAG9D,GAAKA,IAAiBsN,GAAuBC,GAC5C,OAGD,MAAMC,EAAqBv4F,SAAUqqF,EAAUz/G,aAAc,YAAe,GACtE4tH,EAAgC,QAAbpiH,EAAsBg5G,EAAWmJ,EAAqBnJ,EAEzEwE,EAAW,IAAK,IAAIhI,GAAapB,EAAO,CAAEyB,OAAQuM,KAGlDC,EADkB7E,EAAShyH,KAAM5X,GAASA,EAAMsjI,OAASjD,GAC3BK,OAE9BgO,EAAkB9E,EAAShyH,KAAM,EAAI8pH,MAAK6I,aAAY7J,YACtDA,IAAW+N,IAIE,QAAbriH,EAEGs1G,IAAQ8M,EAGRA,IAAqB9M,EAAM6I,IAIpC,OAAOmE,GAAmBA,EAAgBpL,KA3GxCqL,CAAiBtO,EAAW7+H,KAAK4qB,WAElC,IAAM6gH,EACL,OAID,MAAMO,EAAgBhsI,KAAK4nI,aAAe,UAAY,UAChDwF,EAAO54F,SAAUqqF,EAAUz/G,aAAc4sH,IAAmB,GAIlE,OAFwBx3F,SAAUi3F,EAAYrsH,aAAc4sH,IAAmB,KAEtDoB,EACjB3B,OADR,GA0HF,SAAS,GAAS5M,GACjB,OAA+B,GAAxBA,EAAU/3G,YAAmB+3G,EAAU3hH,SAAU,GAAI/c,GAAI,UAAW,cAAiB0+H,EAAU3hH,SAAU,GAAIuF,QCtPtG,MAAM,WAAyB4qE,GAI7C,UACC,MAAMs4C,EAAgBD,GAAgC1lI,KAAKuc,OAAOysC,MAAMhoD,SAASopB,WAC3EijH,EAAY1H,EAAe,GAEjC,GAAK0H,EAAY,CAChB,MAAMrO,EAAQqO,EAAUzpG,aAAc,SAEhC0pG,EADgBttI,KAAKuc,OAAOtE,QAAQ7Z,IAAK,cAAemvI,QAASvO,GAClC,EAE/BwO,EAAqB5H,GAAeD,GAEpC8H,EAAkD,IAA7BD,EAAmBp+G,OAAeo+G,EAAmBn+G,OAASi+G,EAGzFttI,KAAKsvC,WAAam+F,OAElBztI,KAAKsvC,WAAY,EAOnB,UACC,MAAM0Z,EAAQhpD,KAAKuc,OAAOysC,MACpB0kF,EAAiBhI,GAAgC18E,EAAMhoD,SAASopB,WAChEujH,EAAoB/H,GAAe8H,GAEnCL,EAAYK,EAAgB,GAC5B1O,EAAQqO,EAAUzpG,aAAc,SAEhCgqG,EAAqB5tI,KAAKuc,OAAOtE,QAAQ7Z,IAAK,cAAe+gI,gBAAiBkO,GAAYnO,OAEhGl2E,EAAM5L,OAAQprB,IACb,MAAM67G,EAAeF,EAAkBt+G,KAAOs+G,EAAkBv+G,MAAQ,EAExEpvB,KAAKuc,OAAOtE,QAAQ7Z,IAAK,cAAe4sI,WAAYhM,EAAO,CAC1DyI,GAAIkG,EAAkBv+G,MACtBkwG,KAAMuO,IAGP,MAAMC,EAUT,SAAyB9O,EAAO+O,EAAiBC,GAChD,MAAM9N,EAAMlB,EAAM9hH,SAAU6wH,IAAqB/O,EAAM9hH,SAAU8hH,EAAMl4G,WAAa,GAGpF,IAAIgnH,EAAc5N,EAAIhjH,SAAU,GAC5BgiH,EAAS,EAEb,IAAM,MAAML,KAAaqB,EAAIx5G,cAAgB,CAC5C,GAAKw4G,EAAS8O,EACb,OAAOF,EAGRA,EAAcjP,EACdK,GAAU1qF,SAAUqqF,EAAUz/G,aAAc,YAAe,GAG5D,OAAO0uH,EA1BeG,CAAgBjP,EAAO2O,EAAkBv+G,MAAOw+G,GAEpE57G,EAAOyI,aAAczI,EAAOo/B,iBAAkB08E,EAAa,OC9C/C,MAAM,WAA4BzgD,GAIhD,UACC,MAAMs4C,EAAgBD,GAAgC1lI,KAAKuc,OAAOysC,MAAMhoD,SAASopB,WAC3EijH,EAAY1H,EAAe,GAEjC,GAAK0H,EAAY,CAChB,MAAMrO,EAAQqO,EAAUzpG,aAAc,SAChCsqG,EAAmBluI,KAAKuc,OAAOtE,QAAQ7Z,IAAK,cAAemsI,WAAYvL,IAEvE,MAAE5vG,EAAK,KAAEC,GAAS02G,GAAkBJ,GAE1C3lI,KAAKsvC,UAAYjgB,EAAOD,EAAU8+G,EAAmB,OAErDluI,KAAKsvC,WAAY,EAOnB,UACC,MAAQ+9F,EAAWc,GAgErB,SAA2B/jH,GAC1B,MAAMsjH,EAAiBhI,GAAgCt7G,GACjDijH,EAAYK,EAAgB,GAC5BS,EAAWT,EAAetkI,MAE1BglI,EAAc,CAAEf,EAAWc,GAEjC,OAAOd,EAAUxvH,SAAUswH,GAAaC,EAAcA,EAAYtuG,UAvEjCuuG,CAAkBruI,KAAKuc,OAAOysC,MAAMhoD,SAASopB,WACvE40G,EAAQqO,EAAUtwH,OAAOA,OAGzBqrH,EAAW,IAAK,IAAIhI,GAAapB,IAGjCsP,EAAuB,CAC5Bl/G,MAAOg5G,EAAShyH,KAAM5X,GAASA,EAAMsjI,OAASuL,GAAYnO,OAC1D7vG,KAAM+4G,EAAShyH,KAAM5X,GAASA,EAAMsjI,OAASqM,GAAWjP,QAGnD4O,EAiBR,SAAyB1F,EAAUiF,EAAWc,EAAUG,GAKvD,OAJgB95F,SAAU25F,EAAS/uH,aAAc,YAAe,GAIjD,EACP+uH,EAKEd,EAAUl/G,iBAAmBggH,EAASjgH,YACxCigH,EAASjgH,aAAem/G,EAAUl/G,gBAOpCmgH,EAAqBl/G,MAClBg5G,EAAStoG,UAAU1pB,KAAM,EAAI8oH,YAC5BA,EAASoP,EAAqBl/G,OAClC0yG,KAKGsG,EAAStoG,UAAU1pB,KAAM,EAAI8oH,YAC5BA,EAASoP,EAAqBj/G,MAClCyyG,KA9Ce,CAAgBsG,EAAUiF,EAAWc,EAAUG,GAEnEtuI,KAAKuc,OAAOysC,MAAM5L,OAAQprB,IACzB,MAAMu8G,EAAkBD,EAAqBj/G,KAAOi/G,EAAqBl/G,MAAQ,EAEjFpvB,KAAKuc,OAAOtE,QAAQ7Z,IAAK,cAAewsI,cAAe5L,EAAO,CAC7DyI,GAAI6G,EAAqBl/G,MACzBi3G,QAASkI,IAGVv8G,EAAOyI,aAAczI,EAAOo/B,iBAAkB08E,EAAa,OC1C/C,MAAM,WAA4BzgD,GAIhD,UACC,MACMs4C,EAAgBD,GADR1lI,KAAKuc,OAAOysC,MACkChoD,SAASopB,WAC/DokH,EAAY7I,EAAc5jI,OAAS,EAEzC/B,KAAKsvC,UAAYk/F,EAUjBxuI,KAAKxB,MAAQgwI,GAAa7I,EAAcz7G,MAAO43G,GAAQ9hI,KAAKyuI,aAAc3M,EAAMA,EAAK/kH,OAAOA,SAe7F,QAAS7a,EAAU,IAClB,GAAKA,EAAQogG,aAAetiG,KAAKxB,MAChC,OAED,MAAMwqD,EAAQhpD,KAAKuc,OAAOysC,MACpB28E,EAAgBD,GAAgC18E,EAAMhoD,SAASopB,WAC/D40G,EAAQ2G,EAAe,GAAI/hG,aAAc,UAEzC,MAAExU,EAAK,KAAEC,GAASu2G,GAAeD,GACjC+I,EAAmB1uI,KAAKxB,MAAQ4wB,EAAQC,EAAO,EAC/Cs/G,EAAqB3P,EAAM5/G,aAAc,gBAAmB,EAElE4pC,EAAM5L,OAAQprB,IACb,GAAK08G,EAAmB,CAGvB,MACME,EAAmBhG,GAA+B5J,EAAO0P,EAD9CA,EAAmBC,EAAqBA,EAAqB,GAG9E,IAAM,MAAM,KAAE7M,KAAU8M,EACvB3F,GAAmBnH,EAAM4M,EAAkB18G,GAI7C2sG,GAAwB,cAAe+P,EAAkB1P,EAAOhtG,EAAQ,KAY1E,aAAc6sG,EAAWG,GACxB,MAAMO,EAAc/qF,SAAUwqF,EAAM5/G,aAAc,gBAAmB,GAErE,QAASmgH,GAAeV,EAAU9hH,OAAOra,MAAQ68H,GCrEpC,MAAM,WAA+BlyC,GAInD,UACC,MACMs4C,EAAgBD,GADR1lI,KAAKuc,OAAOysC,MACkChoD,SAASopB,WAC/D20G,EAAa/+H,KAAKuc,OAAOtE,QAAQ7Z,IAAK,cACtCowI,EAAY7I,EAAc5jI,OAAS,EAEzC/B,KAAKsvC,UAAYk/F,EAUjBxuI,KAAKxB,MAAQgwI,GAAa7I,EAAcz7G,MAAO43G,GAAQhD,GAAqBC,EAAY+C,IAezF,QAAS5/H,EAAU,IAClB,GAAKA,EAAQogG,aAAetiG,KAAKxB,MAChC,OAGD,MAAMwqD,EAAQhpD,KAAKuc,OAAOysC,MACpB28E,EAAgBD,GAAgC18E,EAAMhoD,SAASopB,WAC/D40G,EAAQ2G,EAAe,GAAI/hG,aAAc,UAEzC,MAAExU,EAAK,KAAEC,GAAS02G,GAAkBJ,GACpCkJ,EAAsB7uI,KAAKxB,MAAQ4wB,EAAQC,EAAO,EAExD25B,EAAM5L,OAAQprB,IACb,GAAK68G,EAAsB,CAG1B,MAAMD,EAAmBnF,GAAiCzK,EAAO6P,GAEjE,IAAM,MAAM,KAAE/M,EAAI,OAAE5C,KAAY0P,EAC/B9E,GAAiBhI,EAAM5C,EAAQ2P,EAAqB78G,GAItD2sG,GAAwB,iBAAkBkQ,EAAqB7P,EAAOhtG,EAAQ,MCvElE,MAAM,WAAmB,GAIvC,wBACC,MAAO,aAMR,OACChyB,KAAKm2D,SAAU,iBACfn2D,KAAKm2D,SAAU,cA8BhB,gBAAiB0oE,GAChB,MAAM2E,EAAW3E,EAAU9hH,OACrBiiH,EAAQwE,EAASzmH,OAEjB6mH,EAAW5E,EAAM/hH,cAAeumH,GAEhCX,EAAc,IAAIzC,GAAapB,EAAO,CAAEkB,IAAK0D,IAEnD,IAAM,MAAM,KAAE9B,EAAI,IAAE5B,EAAG,OAAEhB,KAAY2D,EACpC,GAAKf,IAASjD,EACb,MAAO,CAAEqB,MAAKhB,UAyBjB,YAAaltG,EAAQ9vB,GACpB,MAAM88H,EAAQhtG,EAAO3uB,cAAe,SAepC,OAVAyrI,GAAiB98G,EAAQgtG,EAAO,EAHnBxqF,SAAUtyC,EAAQo9H,OAAU,EACzB9qF,SAAUtyC,EAAQmkI,UAAa,GAI1CnkI,EAAQq9H,aACZZ,GAAwB,cAAez8H,EAAQq9H,YAAaP,EAAOhtG,EAAQ,GAGvE9vB,EAAQ+8H,gBACZN,GAAwB,iBAAkBz8H,EAAQ+8H,eAAgBD,EAAOhtG,EAAQ,GAG3EgtG,EA8BR,WAAYA,EAAO98H,EAAU,IAC5B,MAAM8mD,EAAQhpD,KAAKuc,OAAOysC,MAEpB+lF,EAAW7sI,EAAQulI,IAAM,EACzBuH,EAAe9sI,EAAQo9H,MAAQ,EAC/B2P,OAAqD3oI,IAAnCpE,EAAQwlI,uBAC1BwH,EAAoBhtI,EAAQwlI,uBAAyBqH,EAAW,EAAIA,EAEpEzP,EAAOt/H,KAAKutI,QAASvO,GACrBqH,EAAUrmI,KAAKuqI,WAAYvL,GAEjCh2E,EAAM5L,OAAQprB,IACb,MAAMutG,EAAcP,EAAM5/G,aAAc,gBAAmB,EAQ3D,GALKmgH,EAAcwP,GAClBpQ,GAAwB,cAAeY,EAAcyP,EAAchQ,EAAOhtG,EAAQ,IAI7Ei9G,IAAkC,IAAbF,GAAkBA,IAAazP,GAGzD,YAFAwP,GAAiB98G,EAAQgtG,EAAO+P,EAAUC,EAAc3I,GAMzD,MAAM8I,EAAeF,EAAkB7+H,KAAKsR,IAAKqtH,EAAUG,GAAsBH,EAC3EK,EAAgB,IAAIhP,GAAapB,EAAO,CAAEyB,OAAQ0O,IAGlDE,EAAiB,IAAIlmI,MAAOk9H,GAAUp2H,KAAM,GAElD,IAAM,MAAM,IAAEiwH,EAAG,OAAEhB,EAAM,WAAE6J,EAAU,UAAEa,EAAS,KAAE9H,KAAUsN,EAAgB,CAC3E,MAAME,EAAcpP,EAAM6I,EAAa,EAGjCwG,EAAiBrP,GAAOgP,GAAqBA,GAAqBI,EADvCpP,EAAM6O,GAAYA,GAAYO,GAM9Dt9G,EAAOtuB,aAAc,UAAWqlI,EAAaiG,EAAclN,GAG3DuN,EAAgBnQ,IAAY0K,GAGnBqF,GAAmBM,IAC5BF,EAAgBnQ,GAAW0K,GAI7B,IAAM,IAAIhG,EAAW,EAAGA,EAAWoL,EAAcpL,IAAa,CAC7D,MAAMJ,EAAWxxG,EAAO3uB,cAAe,YAEvC2uB,EAAOruB,OAAQ6/H,EAAUxE,EAAO+P,GAEhC,IAAM,IAAIS,EAAY,EAAGA,EAAYH,EAAettI,OAAQytI,IAAc,CACzE,MAAMzN,EAAUsN,EAAgBG,GAC1B7uF,EAAiB3uB,EAAOo/B,iBAAkBoyE,EAAU,OAGrDzB,EAAU,GACdnD,GAAsB5sG,EAAQ2uB,EAAgBohF,EAAU,EAAI,CAAEA,WAAY,MAI3EyN,GAAap/H,KAAKq/H,IAAK1N,GAAY,MAgCvC,cAAe/C,EAAO98H,EAAU,IAC/B,MAAM8mD,EAAQhpD,KAAKuc,OAAOysC,MAEpB+lF,EAAW7sI,EAAQulI,IAAM,EACzBiI,EAAkBxtI,EAAQmkI,SAAW,EAE3Cr9E,EAAM5L,OAAQprB,IACb,MAAMitG,EAAiBD,EAAM5/G,aAAc,kBAGtC2vH,EAAW9P,GACfjtG,EAAOtuB,aAAc,iBAAkBu7H,EAAiByQ,EAAiB1Q,GAG1E,MAAM2Q,EAAe3vI,KAAKuqI,WAAYvL,GAGtC,GAAkB,IAAb+P,GAAkBY,IAAiBZ,EAAW,CAClD,IAAM,MAAMvL,KAAYxE,EAAMt4G,cAC7BkpH,GAAaF,EAAiB19G,EAAQA,EAAOo/B,iBAAkBoyE,EAAUuL,EAAW,MAAQ,IAG7F,OAGD,MAAMlM,EAAc,IAAIzC,GAAapB,EAAO,CAAEE,OAAQ6P,EAAUhO,iBAAiB,IAEjF,IAAM,MAAMwC,KAAaV,EAAc,CACtC,MAAM,IAAE3C,EAAG,KAAE4B,EAAI,iBAAEiB,EAAgB,cAAED,EAAa,UAAE8G,EAAS,WAAEb,GAAexF,EAO9E,GAAKR,EAAmBgM,EAAW,CAGlC/8G,EAAOtuB,aAAc,UAAWkmI,EAAY8F,EAAiB5N,GAG7D,MAAMwN,EAAcxM,EAAgBiG,EAAa,EAEjD,IAAM,IAAIxrI,EAAI2iI,EAAK3iI,GAAK+xI,EAAa/xI,IACpCslI,EAAYgN,QAAStyI,QAKtBqyI,GAAaF,EAAiB19G,EAAQuxG,EAAUiG,wBAkCpD,WAAYxK,EAAO98H,GAClB,MAAM8mD,EAAQhpD,KAAKuc,OAAOysC,MAEpB6kF,EAAe3rI,EAAQo9H,MAAQ,EAC/BlwG,EAAQltB,EAAQulI,GAChBp4G,EAAOD,EAAQy+G,EAAe,EAEpC7kF,EAAM5L,OAAQprB,IAKb,MAAM,YAAE89G,EAAW,YAAEC,GAmfxB,SAA2C/Q,EAAO5vG,EAAOC,GACxD,MAAMygH,EAAc,IAAIh8H,IAClBi8H,EAAc,GAEpB,IAAM,MAAM,IAAE7P,EAAG,OAAEhB,EAAM,WAAE6J,EAAU,KAAEjH,KAAU,IAAI1B,GAAapB,EAAO,CAAEyB,OAAQpxG,IAAW,CAC7F,MAAM2gH,EAAgB9P,EAAM6I,EAAa,EAIzC,GAFyC7I,GAAO9wG,GAAS8wG,GAAO7wG,GAAQ2gH,EAAgB3gH,EAEhD,CACvC,MACM4gH,EAAelH,GADW15G,EAAO6wG,EAAM,GAG7C4P,EAAYrmI,IAAKy1H,EAAQ,CACxB4C,OACAE,QAASiO,IAMX,GAFqC/P,EAAM9wG,GAAS4gH,GAAiB5gH,EAEjC,CACnC,IAAIi8G,EAIHA,EADI2E,GAAiB3gH,EACDA,EAAOD,EAAQ,EAIf4gH,EAAgB5gH,EAAQ,EAG7C2gH,EAAY9sI,KAAM,CACjB6+H,OACAE,QAAS+G,EAAasC,KAIzB,MAAO,CAAEyE,cAAaC,eA1hBiBG,CAAkClR,EAAO5vG,EAAOC,GAMrF,GAAKygH,EAAY9mI,KAAO,EAuhB3B,SAAyBg2H,EAAOmR,EAAgBL,EAAa99G,GAC5D,MAKMo+G,EAAc,IALA,IAAIhQ,GAAapB,EAAO,CAC3C+B,iBAAiB,EACjBb,IAAKiQ,KAIAjQ,EAAMlB,EAAM9hH,SAAUizH,GAE5B,IAAIE,EAEJ,IAAM,MAAM,OAAEnR,EAAM,KAAE4C,EAAI,SAAEyG,KAAc6H,EACzC,GAAKN,EAAYpmI,IAAKw1H,GAAW,CAChC,MAAQ4C,KAAMwO,EAAU,QAAEtO,GAAY8N,EAAY1xI,IAAK8gI,GAEjD5mG,EAAiB+3G,EACtBr+G,EAAO2qC,oBAAqB0zE,GAC5Br+G,EAAOo/B,iBAAkB8uE,EAAK,GAE/BluG,EAAOuG,KAAMvG,EAAO+0B,cAAeupF,GAAch4G,GACjDqmG,GAAwB,UAAWqD,EAASsO,EAAYt+G,GAExDq+G,EAAeC,OACJ/H,IAEX8H,EAAevO,GA9iBdyO,CAAgBvR,EADe3vG,EAAO,EACSygH,EAAa99G,GAI7D,IAAM,IAAIz0B,EAAI8xB,EAAM9xB,GAAK6xB,EAAO7xB,IAC/By0B,EAAO7tB,OAAQ66H,EAAM9hH,SAAU3f,IAIhC,IAAM,MAAM,QAAEykI,EAAO,KAAEF,KAAUiO,EAChCpR,GAAwB,UAAWqD,EAASF,EAAM9vG,IAkctD,SAA4BgtG,EAAO5vG,EAAOC,EAAM2C,GAC/C,MAAMutG,EAAcP,EAAM5/G,aAAc,gBAAmB,EAE3D,GAAKgQ,EAAQmwG,EAAc,CAG1BZ,GAAwB,cAFRtvG,EAAOkwG,EAAcA,GAAgBlwG,EAAOD,EAAQ,GAAMA,EAE1B4vG,EAAOhtG,EAAQ,IApc9Dw+G,CAAmBxR,EAAO5vG,EAAOC,EAAM2C,GAGjCs4G,GAAoBtL,EAAOh/H,OAGhC6qI,GAAiB7L,EAAOh/H,QAkC3B,cAAeg/H,EAAO98H,GACrB,MAAM8mD,EAAQhpD,KAAKuc,OAAOysC,MACpB55B,EAAQltB,EAAQulI,GAChB8G,EAAkBrsI,EAAQmkI,SAAW,EACrCh3G,EAAOntB,EAAQulI,GAAK8G,EAAkB,EAE5CvlF,EAAM5L,OAAQprB,KAoYhB,SAA+BgtG,EAAOsP,EAAsBt8G,GAC3D,MAAMitG,EAAiBD,EAAM5/G,aAAc,mBAAsB,EAEjE,GAAK6/G,GAAkBqP,EAAqBl/G,MAAQ6vG,EAAiB,CACpE,MAAMwR,EAAkBrgI,KAAK0M,IAAKmiH,EAAiB,EAAmCqP,EAAqBj/G,MAC1Gi/G,EAAqBl/G,MAAQ,EAE9B4C,EAAOtuB,aAAc,iBAAkBu7H,EAAiBwR,EAAiBzR,IA1YxE0R,CAAsB1R,EAAO,CAAE5vG,QAAOC,QAAQ2C,GAE9C,IAAM,IAAI2+G,EAAqBthH,EAAMshH,GAAsBvhH,EAAOuhH,IACjE,IAAM,MAAM,KAAE7O,EAAI,OAAE5C,EAAM,UAAE0K,IAAe,IAAK,IAAIxJ,GAAapB,IAE3DE,GAAUyR,GAAsB/G,EAAY,GAAK1K,EAAS0K,EAAY+G,EAC1EhS,GAAwB,UAAWiL,EAAY,EAAG9H,EAAM9vG,GAC7CktG,IAAWyR,GAEtB3+G,EAAO7tB,OAAQ29H,GAMZ+I,GAAiB7L,EAAOh/H,OAG7BsqI,GAAoBtL,EAAOh/H,QAiD9B,oBAAqB6+H,EAAW+R,EAAgB,GAC/C,MAAM5nF,EAAQhpD,KAAKuc,OAAOysC,MAEpBg2E,EADWH,EAAU9hH,OACJA,OAEjBilH,EAAUxtF,SAAUqqF,EAAUz/G,aAAc,YAAe,GAC3D2iH,EAAUvtF,SAAUqqF,EAAUz/G,aAAc,YAAe,GAEjE4pC,EAAM5L,OAAQprB,IAEb,GAAK+vG,EAAU,EAAI,CAElB,MAAM,aAAE8O,EAAY,YAAEC,GAAgBC,GAAiBhP,EAAS6O,GAEhEjS,GAAwB,UAAWmS,EAAajS,EAAW7sG,GAG3D,MAAMg/G,EAAqB,GAGtBH,EAAe,IACnBG,EAAmBjP,QAAU8O,GAIzB7O,EAAU,IACdgP,EAAmBhP,QAAUA,GAI9B4N,GADsB7N,EAAU6O,EAAgBA,EAAgB,EAAI7O,EAAU,EAClD/vG,EAAQA,EAAO2qC,oBAAqBkiE,GAAamS,GAI9E,GAAKjP,EAAU6O,EAAgB,CAC9B,MAAMK,EAAgBL,EAAgB7O,EAGhCqG,EAAW,IAAK,IAAIhI,GAAapB,KAG/BE,OAAQgS,GAAoB9I,EAAShyH,KAAM,EAAI0rH,UAAYA,IAASjD,GAGtEsS,EAAgB/I,EAASpkI,OAAQ,EAAI89H,OAAM8H,YAAW1K,YACpC4C,IAASjD,GAAaK,IAAWgS,GAC9BhS,EAASgS,GAAmBhS,EAAS0K,EAAYsH,GAM5E,IAAM,MAAM,KAAEpP,EAAI,UAAE8H,KAAeuH,EAClCn/G,EAAOtuB,aAAc,UAAWkmI,EAAYqH,EAAenP,GAM5D,MAAMkP,EAAqB,GAKtBhP,EAAU,IACdgP,EAAmBhP,QAAUA,GAG9B4N,GAAaqB,EAAej/G,EAAQA,EAAO2qC,oBAAqBkiE,GAAamS,GAE7E,MAAM/R,EAAiBD,EAAM5/G,aAAc,mBAAsB,EAG5D6/G,EAAiBiS,GACrBvS,GAAwB,iBAAkBM,EAAiBgS,EAAejS,EAAOhtG,MA8DrF,sBAAuB6sG,EAAW+R,EAAgB,GACjD,MAAM5nF,EAAQhpD,KAAKuc,OAAOysC,MAEpBw6E,EAAW3E,EAAU9hH,OACrBiiH,EAAQwE,EAASzmH,OACjBq0H,EAAepS,EAAM/hH,cAAeumH,GAEpCxB,EAAUxtF,SAAUqqF,EAAUz/G,aAAc,YAAe,GAC3D2iH,EAAUvtF,SAAUqqF,EAAUz/G,aAAc,YAAe,GAEjE4pC,EAAM5L,OAAQprB,IAEb,GAAKgwG,EAAU,EAAI,CAElB,MAAMoG,EAAW,IAAK,IAAIhI,GAAapB,EAAO,CAC7CuB,SAAU6Q,EACV3Q,OAAQ2Q,EAAepP,EAAU,EACjCjB,iBAAiB,MAIZ,aAAE8P,EAAY,YAAEC,GAAgBC,GAAiB/O,EAAS4O,GAEhEjS,GAAwB,UAAWmS,EAAajS,EAAW7sG,GAE3D,MAAQktG,OAAQiL,GAAe/B,EAAShyH,KAAM,EAAI0rH,UAAYA,IAASjD,GAGjEmS,EAAqB,GAGtBH,EAAe,IACnBG,EAAmBhP,QAAU6O,GAIzB9O,EAAU,IACdiP,EAAmBjP,QAAUA,GAG9B,IAAM,MAAMwB,KAAa6E,EAAW,CACnC,MAAM,OAAElJ,EAAM,IAAEgB,GAAQqD,EAQlB8N,EAAiBnS,IAAWiL,EAE5BmH,GAAuBpR,EAAMkR,EAAeN,GAAgBD,GAAiB,EAJ1D3Q,GAAOkR,EAAeN,GAMtBO,GAAkBC,GAC1C1B,GAAa,EAAG59G,EAAQuxG,EAAUiG,oBAAqBwH,IAM1D,GAAKhP,EAAU4O,EAAgB,CAE9B,MAAMK,EAAgBL,EAAgB5O,EAGhCoG,EAAW,IAAK,IAAIhI,GAAapB,EAAO,CAAEuB,SAAU,EAAGE,OAAQ2Q,KAGrE,IAAM,MAAM,KAAEtP,EAAI,WAAEiH,EAAU,IAAE7I,KAASkI,EAIxC,GAAKtG,IAASjD,GAAaqB,EAAM6I,EAAaqI,EAAe,CAC5D,MAAMG,EAAexI,EAAakI,EAElCj/G,EAAOtuB,aAAc,UAAW6tI,EAAczP,GAKhD,MAAMkP,EAAqB,GAGtBjP,EAAU,IACdiP,EAAmBjP,QAAUA,GAG9B+M,GAAiB98G,EAAQgtG,EAAOoS,EAAe,EAAGH,EAAe,EAAGD,GAGpE,MAAMzR,EAAcP,EAAM5/G,aAAc,gBAAmB,EAEtDmgH,EAAc6R,GAClBzS,GAAwB,cAAeY,EAAc0R,EAAejS,EAAOhtG,MAc/E,WAAYgtG,GAIX,MAAO,IAFKA,EAAM9hH,SAAU,GAEZwJ,eAAgBrP,OAAQ,CAAEgvH,EAASnG,IAG3CmG,EAFa7xF,SAAU0rF,EAAI9gH,aAAc,YAAe,GAG7D,GAWJ,QAAS4/G,GAER,OAAOA,EAAMl4G,YAWf,SAASgoH,GAAiB98G,EAAQgtG,EAAO+P,EAAUzP,EAAMkS,EAAmBluI,EAAa,IACxF,IAAM,IAAI/F,EAAI,EAAGA,EAAI+hI,EAAM/hI,IAAM,CAChC,MAAMimI,EAAWxxG,EAAO3uB,cAAe,YAEvC2uB,EAAOruB,OAAQ6/H,EAAUxE,EAAO+P,GAEhCa,GAAa4B,EAAmBx/G,EAAQA,EAAOo/B,iBAAkBoyE,EAAU,OAASlgI,IAStF,SAASssI,GAAatK,EAAOtzG,EAAQ2uB,EAAgBr9C,EAAa,IACjE,IAAM,IAAI/F,EAAI,EAAGA,EAAI+nI,EAAO/nI,IAC3BqhI,GAAsB5sG,EAAQ2uB,EAAgBr9C,GAgBhD,SAASytI,GAAiB3D,EAAMwD,GAC/B,GAAKxD,EAAOwD,EACX,MAAO,CAAEC,aAAc,EAAGC,YAAa,GAGxC,MAAMD,EAAezgI,KAAKklG,MAAO83B,EAAOwD,GAGxC,MAAO,CAAEC,eAAcC,YAFD1D,EAAOyD,EAAeD,EAAkBC,GC3vBhD,MAAM,WAA0BxjD,GAI9C,UACC,MAAM44C,EAAqBZ,GAAuBrlI,KAAKuc,OAAOysC,MAAMhoD,SAASopB,WAC7EpqB,KAAKsvC,UAAY02F,GAAwBC,EAAoBjmI,KAAKuc,OAAOtE,QAAQ7Z,IAAK,KAQvF,UACC,MAAM4qD,EAAQhpD,KAAKuc,OAAOysC,MACpB+1E,EAAa/+H,KAAKuc,OAAOtE,QAAQ7Z,IAAK,IAE5C4qD,EAAM5L,OAAQprB,IACb,MAAMi0G,EAAqBZ,GAAuBr8E,EAAMhoD,SAASopB,WAG3DqnH,EAAiBxL,EAAmBx5G,SAGpC,WAAEilH,EAAU,YAAEC,GA8CvB,SAA6BF,EAAgBxL,EAAoBlH,GAChE,IAAI6S,EAAiB,EACjBC,EAAkB,EAEtB,IAAM,MAAMhT,KAAaoH,EAAqB,CAC7C,MAAM,IAAE/F,EAAG,OAAEhB,GAAWH,EAAWI,gBAAiBN,GAEpD+S,EAAiBE,GAAcjT,EAAWK,EAAQ0S,EAAgB,WAClEC,EAAkBC,GAAcjT,EAAWqB,EAAK2R,EAAiB,WAIlE,MAAQ3R,IAAK6R,EAAc7S,OAAQ8S,GAAoBjT,EAAWI,gBAAiBsS,GAKnF,MAAO,CAAEC,WAHUE,EAAiBI,EAGfL,YAFDE,EAAkBE,GA7DAE,CAAoBR,EAAgBxL,EAAoBlH,GAC5FJ,GAAwB,UAAW+S,EAAYD,EAAgBz/G,GAC/D2sG,GAAwB,UAAWgT,EAAaF,EAAgBz/G,GAEhE,IAAM,MAAM6sG,KAAaoH,EACxB,GAAiBpH,EAAW4S,EAAgBz/G,GAM7Ci5G,GAHcwG,EAAe7tG,aAAc,SAGZm7F,GAE/B/sG,EAAOyI,aAAcg3G,EAAgB,SAYxC,SAAS,GAAiBS,EAAiBC,EAAYngH,GAChD,GAASkgH,KACT,GAASC,IACbngH,EAAO7tB,OAAQ6tB,EAAO0iC,cAAey9E,IAGtCngH,EAAOuG,KAAMvG,EAAO0iC,cAAew9E,GAAmBlgH,EAAOo/B,iBAAkB+gF,EAAY,SAI5FngH,EAAO7tB,OAAQ+tI,GAOhB,SAAS,GAASrT,GACjB,OAA+B,GAAxBA,EAAU/3G,YAAmB+3G,EAAU3hH,SAAU,GAAI/c,GAAI,UAAW,cAAiB0+H,EAAU3hH,SAAU,GAAIuF,QAuBrH,SAASqvH,GAAcjT,EAAWh+G,EAAOuxH,EAAkBC,GAC1D,MAAMC,EAAiB99F,SAAUqqF,EAAUz/G,aAAcizH,IAAW,GAEpE,OAAOjiI,KAAKsR,IAAK0wH,EAAkBvxH,EAAQyxH,GChG7B,MAAM,WAAyBjlD,GAI7C,UACC,MAAMs4C,EAAgBD,GAAgC1lI,KAAKuc,OAAOysC,MAAMhoD,SAASopB,WAEjFpqB,KAAKsvC,UAAYq2F,EAAc5jI,OAAS,EAMzC,UACC,MAAMinD,EAAQhpD,KAAKuc,OAAOysC,MACpB0kF,EAAiBhI,GAAgC18E,EAAMhoD,SAASopB,WAChE87G,EAAaN,GAAe8H,GAE5B1O,EAAQ0O,EAAgB,GAAI9pG,aAAc,SAC1C2uG,EAAiB,GAEvB,IAAM,IAAI3O,EAAWsC,EAAW92G,MAAOw0G,GAAYsC,EAAW72G,KAAMu0G,IACnE,IAAM,MAAM9B,KAAQ9C,EAAM9hH,SAAU0mH,GAAWl9G,cAC9C6rH,EAAetvI,KAAM+lD,EAAMjC,cAAe+6E,IAI5C94E,EAAM5L,OAAQprB,IACbA,EAAOyI,aAAc83G,MC3BT,MAAM,WAA4BllD,GAIhD,UACC,MAAMs4C,EAAgBD,GAAgC1lI,KAAKuc,OAAOysC,MAAMhoD,SAASopB,WAEjFpqB,KAAKsvC,UAAYq2F,EAAc5jI,OAAS,EAMzC,UACC,MAAMinD,EAAQhpD,KAAKuc,OAAOysC,MACpB0kF,EAAiBhI,GAAgC18E,EAAMhoD,SAASopB,WAChEijH,EAAYK,EAAgB,GAC5BS,EAAWT,EAAetkI,MAC1B41H,EAAQqO,EAAUzpG,aAAc,SAEhCm7F,EAAa/+H,KAAKuc,OAAOtE,QAAQ7Z,IAAK,cACtCo0I,EAAgBzT,EAAWI,gBAAiBkO,GAC5CoF,EAAc1T,EAAWI,gBAAiBgP,GAE1CxN,EAAcvwH,KAAK0M,IAAK01H,EAActT,OAAQuT,EAAYvT,QAC1D2B,EAAYzwH,KAAKsR,IAAK8wH,EAActT,OAAQuT,EAAYvT,QAExDqT,EAAiB,GAEvB,IAAM,MAAMG,KAAY,IAAItS,GAAapB,EAAO,CAAE2B,cAAaE,cAC9D0R,EAAetvI,KAAM+lD,EAAMjC,cAAe2rF,EAAS5Q,OAGpD94E,EAAM5L,OAAQprB,IACbA,EAAOyI,aAAc83G,MC4JT,SAASI,GAA4B3pF,GACnDA,EAAMhoD,SAASkvE,kBAAmBl+C,GAOnC,SAA+BA,EAAQg3B,GACtC,MAAM1D,EAAU0D,EAAMhoD,SAASkkD,OAAOyC,aAEtC,IAAI11B,GAAW,EAGf,MAAM2gH,EAAiB,IAAIv6H,IAE3B,IAAM,MAAM7O,KAAS87C,EAAU,CAC9B,IAAI05E,EAEe,SAAdx1H,EAAM1L,MAAiC,UAAd0L,EAAMvJ,OACnC++H,EAAQx1H,EAAMqhB,SAASuC,WAIL,YAAd5jB,EAAM1L,MAAoC,aAAd0L,EAAM1L,OACtCkhI,EAAQx1H,EAAMqhB,SAAS+Y,aAAc,UAIjCivG,GAAuBrpI,KAC3Bw1H,EAAQx1H,EAAMylB,MAAMpO,MAAM+iB,aAAc,UAGpCo7F,IAAU4T,EAAelpI,IAAKs1H,KAGlC/sG,EAAW6gH,GAAsB9T,EAAOhtG,IAAYC,EAEpDA,EAAW8gH,GAAmB/T,EAAOhtG,IAAYC,EAEjD2gH,EAAehkI,IAAKowH,IAItB,OAAO/sG,EA3CqC+gH,CAAsBhhH,EAAQg3B,IAmD3E,SAAS8pF,GAAsB9T,EAAOhtG,GACrC,IAAIC,GAAW,EAEf,MAAM89G,EA4EP,SAA0B/Q,GACzB,MAAMO,EAAc/qF,SAAUwqF,EAAM5/G,aAAc,gBAAmB,GAC/D6zH,EAAUjU,EAAMl4G,WAEhBipH,EAAc,GAEpB,IAAM,MAAM,IAAE7P,EAAG,KAAE4B,EAAI,WAAEiH,KAAgB,IAAI3I,GAAapB,GAAU,CAEnE,GAAK+J,EAAa,EACjB,SAGD,MAGMmK,EAHahT,EAAMX,EAGKA,EAAc0T,EAG5C,GAAK/S,EAAM6I,EAAamK,EAAW,CAClC,MAAM/J,EAAa+J,EAAWhT,EAE9B6P,EAAY9sI,KAAM,CAAE6+H,OAAME,QAASmH,KAIrC,OAAO4G,EArGaoD,CAAiBnU,GAErC,GAAK+Q,EAAYhuI,OAAS,CAGzBkwB,GAAW,EAEX,IAAM,MAAMtyB,KAAQowI,EACnBpR,GAAwB,UAAWh/H,EAAKqiI,QAASriI,EAAKmiI,KAAM9vG,EAAQ,GAItE,OAAOC,EAQR,SAAS8gH,GAAmB/T,EAAOhtG,GAClC,IAAIC,GAAW,EAEf,MAAMmhH,EAqFP,SAAyBpU,GAExB,MAAMqU,EAAU,IAAIlqI,MAAO61H,EAAMl4G,YAAa7W,KAAM,GAEpD,IAAM,MAAM,IAAEiwH,KAAS,IAAIE,GAAapB,EAAO,CAAE+B,iBAAiB,IACjEsS,EAASnT,KAGV,OAAOmT,EA7FaC,CAAgBtU,GAC9B6O,EAAe,GAGrB,IAAM,MAAQjK,EAAU56H,KAAUoqI,EAAY9pI,UACvCN,GACL6kI,EAAa5qI,KAAM2gI,GAKrB,GAAKiK,EAAa9rI,OAAS,CAG1BkwB,GAAW,EAEX,IAAM,MAAM2xG,KAAYiK,EAAa/tG,UACpC9N,EAAO7tB,OAAQ66H,EAAM9hH,SAAU0mH,IAC/BwP,EAAYttI,OAAQ89H,EAAU,GAKhC,MAAM2P,EAAYH,EAAa,GAG/B,IAFgBA,EAAYlpH,MAAOnoB,GAAUA,IAAWwxI,GAExC,CAIf,MAAMC,EAAaJ,EAAY/7H,OAAQ,CAAEyhB,EAAMoB,IAAaA,EAAUpB,EAAOoB,EAAUpB,EAAM,GAE7F,IAAM,MAAQ8qG,EAAU56H,KAAUoqI,EAAY9pI,UAAY,CACzD,MAAMomI,EAAkB8D,EAAaxqI,EAErC,GAAK0mI,EAAkB,CACtB,IAAM,IAAInyI,EAAI,EAAGA,EAAImyI,EAAiBnyI,IACrCqhI,GAAsB5sG,EAAQA,EAAOo/B,iBAAkB4tE,EAAM9hH,SAAU0mH,GAAY,QAGpF3xG,GAAW,IAKd,OAAOA,EAuDR,SAAS4gH,GAAuBrpI,GAC/B,MAAMiqI,EAAiC,cAAfjqI,EAAMvJ,KACxBnB,EAAM0K,EAAMo8C,aAElB,OAAO6tF,IAA6B,gBAAR30I,GAAiC,YAARA,GAA6B,YAARA,GC/W5D,SAAS40I,GAAmC1qF,GAC1DA,EAAMhoD,SAASkvE,kBAAmBl+C,GAOnC,SAAqCA,EAAQg3B,GAC5C,MAAM1D,EAAU0D,EAAMhoD,SAASkkD,OAAOyC,aAEtC,IAAI11B,GAAW,EAEf,IAAM,MAAMzoB,KAAS87C,EACD,UAAd97C,EAAMvJ,MAAkC,SAAduJ,EAAM1L,OACpCm0B,EAAW0hH,GAAUnqI,EAAMqhB,SAASuC,UAAW4E,IAAYC,GAGzC,UAAdzoB,EAAMvJ,MAAkC,YAAduJ,EAAM1L,OACpCm0B,EAAW2hH,GAAapqI,EAAMqhB,SAASuC,UAAW4E,IAAYC,GAG5C,UAAdzoB,EAAMvJ,MAAkC,aAAduJ,EAAM1L,OACpCm0B,EAAW4hH,GAAqBrqI,EAAMqhB,SAASuC,UAAW4E,IAAYC,GAGlE6hH,GAAsBtqI,KAC1ByoB,EAAW4hH,GAAqBrqI,EAAMqhB,SAAS9N,OAAQiV,IAAYC,GAIrE,OAAOA,EA9BqC8hH,CAA4B/hH,EAAQg3B,IAqCjF,SAAS2qF,GAAU3U,EAAOhtG,GACzB,IAAIC,GAAW,EAEf,IAAM,MAAMiuG,KAAOlB,EAAMt4G,cACxBuL,EAAW2hH,GAAa1T,EAAKluG,IAAYC,EAG1C,OAAOA,EAOR,SAAS2hH,GAAapQ,EAAUxxG,GAC/B,IAAIC,GAAW,EAEf,IAAM,MAAM4sG,KAAa2E,EAAS98G,cACjCuL,EAAW4hH,GAAqBhV,EAAW7sG,IAAYC,EAGxD,OAAOA,EAUR,SAAS4hH,GAAqBhV,EAAW7sG,GAExC,GAA6B,GAAxB6sG,EAAU/3G,WAKd,OAFAkL,EAAO8+B,cAAe,YAAa+tE,IAE5B,EAKR,MAAMmV,EAAY7qI,MAAMiK,KAAMyrH,EAAUn4G,eAAgB1iB,OAAQyiB,GAASA,EAAMtmB,GAAI,UAInF,IAAM,MAAMsmB,KAASutH,EACpBhiH,EAAOsK,KAAMtK,EAAO+0B,cAAetgC,GAAS,aAI7C,QAASutH,EAAUjyI,OASpB,SAAS+xI,GAAsBtqI,GAC9B,SAAMA,EAAMqhB,WAAarhB,EAAMqhB,SAAS9N,OAAO5c,GAAI,UAAW,gBAIzC,UAAdqJ,EAAMvJ,MAAkC,SAAduJ,EAAM1L,MAAiC,UAAd0L,EAAMvJ,MC/GlD,SAASg0I,GAAiCjrF,EAAOrF,GAC/DqF,EAAMhoD,SAASkvE,kBAAmB,IAGnC,SAAoChrB,EAAQvB,GAI3C,MAAMuwF,EAAe,IAAI77H,IAEzB,IAAM,MAAM+kC,KAAU8H,EAAOyC,aAAe,CAC3C,MAAM5qC,EAAwB,aAAfqgC,EAAOn9C,KAAsBm9C,EAAOnuB,MAAMpO,MAAM9D,OAASqgC,EAAOvyB,SAAS9N,OAEnFA,EAAO5c,GAAI,UAAW,cAC1B+zI,EAAatlI,IAAKmO,GAOpB,IAAM,MAAM8hH,KAAaqV,EAAa7nI,SACrC,IAAM,MAAM8kD,IAAa,IAAK0tE,EAAUn4G,eAAgB1iB,OAAQyiB,GAAS0tH,GAAe1tH,EAAOk9B,IAE9FuB,EAAOkvF,YAAajjF,GAOtB,OAAO,EA9BiCkjF,CAA2BrrF,EAAMhoD,SAASkkD,OAAQvB,IAsC3F,SAASwwF,GAAe1tH,EAAOk9B,GAC9B,IAAMl9B,EAAMtmB,GAAI,UAAW,aAC1B,OAAO,EAGR,MAAM26B,EAAc6oB,EAAOR,cAAe18B,GAE1C,QAAMqU,GAICgpG,GAAoCr9G,KAAYqU,EAAY36B,GAAI,UAAW,QCrDpE,SAASm0I,GAAwCtrF,GAC/DA,EAAMhoD,SAASkvE,kBAAmB,IAGnC,SAA2ClnB,GAC1C,MAAM9D,EAAS8D,EAAMhoD,SAASkkD,OAGxBqvF,EAAkB,IAAIl8H,IAE5B,IAAM,MAAM+kC,KAAU8H,EAAOyC,aAAe,CAC3C,GAAoB,aAAfvK,EAAOn9C,KACX,SAGD,MAAM2e,EAAUw+B,EAAOnuB,MAAMpO,MAAMuM,UAE9BxO,GAAWA,EAAQze,GAAI,UAAW,UAAoC,eAAvBi9C,EAAOwI,cAC1D2uF,EAAgB3lI,IAAKgQ,GAIvB,GAAK21H,EAAgBvrI,KAAO,CAG3B,IAAM,MAAMg2H,KAASuV,EAAgBloI,SAEpC64C,EAAOkvF,YAAapV,GAGrB,OAAO,EAGR,OAAO,EAhCiCwV,CAAkCxrF,I,MC0B5D,MAAM,WAAqB,GAIzC,wBACC,MAAO,eAMR,OACC,MAAMzsC,EAASvc,KAAKuc,OACdysC,EAAQzsC,EAAOysC,MACfC,EAASD,EAAMC,OACfqrB,EAAa/3D,EAAO+3D,WAE1BrrB,EAAOipB,SAAU,QAAS,CACzBvY,WAAY,SACZ3C,gBAAiB,CAAE,cAAe,kBAClClK,UAAU,EACV5D,SAAS,IAGVD,EAAOipB,SAAU,WAAY,CAC5BhZ,QAAS,QACT9P,SAAS,IAGVH,EAAOipB,SAAU,YAAa,CAC7BhZ,QAAS,WACTlC,gBAAiB,CAAE,UAAW,WAC9B5N,SAAS,EACTyN,cAAc,IAIf5N,EAAOlyB,OAAQ,SAAU,CAAEmiC,QAAS,cAGpCjQ,EAAOkpB,cAAe,CAAEzyE,EAAS0yE,KAChC,GAA6B,SAAxBA,EAAgBt0E,MAAmBqL,MAAMiK,KAAM1T,EAAQ45D,YAAalgD,SAAU,SAClF,OAAO,IAKTk7D,EAAWjV,IAAK,UAAWzwD,IAAKwwH,MAEhC9qD,EAAWjV,IAAK,mBAAoBzwD,IAAKo0H,GAAqB,CAAEC,UAAU,KAC1E3uD,EAAWjV,IAAK,gBAAiBzwD,IAAKo0H,MAGtC1uD,EAAWjV,IAAK,UAAWC,iBAAkB,CAAEtW,MAAO,WAAYtzB,KAAM,OACxE4+C,EAAWjV,IAAK,UAAWzwD,ItBvBrBo2C,IACNA,EAAW97B,GAAI,aAAc,CAAEpS,EAAKnX,KAC9BA,EAAKozD,SAAStwC,SAAqC,GAA1B9iB,EAAKkzD,YAAYnwD,OAC9CoU,EAAIhH,QAEH,CAAEW,SAAU,WsBoBf6jE,EAAWjV,IAAK,mBAAoBzwD,IpBP9Bo2C,GAAcA,EAAW97B,GAAI,kBAAmB,CAAEpS,EAAKnX,EAAMolD,KACnE,MAAMy+E,EAAW7jI,EAAK0C,KAEtB,IAAM0iD,EAAcqB,WAAWkH,QAASk2E,EAAU,UACjD,OAGD,MAAMxE,EAAQwE,EAASzmH,OAGjBomH,EAmZR,SAAuB/2B,GACtB,IAAM,MAAM3lF,KAAS2lF,EAAW1lF,cAC/B,GAAoB,UAAfD,EAAM3oB,KACV,OAAO2oB,EAtZaguH,CADC1vF,EAAcpB,OAAOR,cAAe67E,IAGpDkB,EAAMlB,EAAM/hH,cAAeumH,GAE3BX,EAAc,IAAIzC,GAAapB,EAAO,CAAEkB,QAExCmD,EAAkB,CACvB9D,YAAaP,EAAM5/G,aAAc,gBAAmB,EACpD6/G,eAAgBD,EAAM5/G,aAAc,mBAAsB,GAIrDkkH,EAAW,IAAIxvH,IAErB,IAAM,MAAMyvH,KAAaV,EAAc,CACtC,MAAMY,EAAYH,EAASllI,IAAK8hI,IAASwD,GAAUP,EAAcK,EAAUtD,EAAKmD,EAAiBt+E,GACjGu+E,EAAS75H,IAAKy2H,EAAKuD,GAGnB1+E,EAAcqB,WAAWkH,QAASi2E,EAAUzB,KAAM,UAIlD6B,GAA4BJ,EAAWF,EAFhBt+E,EAAc/yB,OAAOo/B,iBAAkBqyE,EAAW,OAED1+E,EAAe,CAAEk+E,UAAU,QoBzBpG3uD,EAAWjV,IAAK,mBAAoBzwD,IpB6G9Bo2C,GAAcA,EAAW97B,GAAI,kBAAmB,CAAEpS,EAAKnX,EAAMolD,KAEnEjuC,EAAIhH,OACJ,MAAMk+C,EAAajJ,EAAc/yB,OAC3B2xB,EAASoB,EAAcpB,OAGvBoP,EADYpP,EAAOD,eAAgB/jD,EAAKkrB,UAAWmC,wBAAyBxuB,IAAUA,EAAM6D,KAAKlC,GAAI,UAAW,OAC3FitB,UAErBiyG,EADetsE,EAASh2C,OACCA,OAGzBizD,EAAchiB,EAAWjH,cAAegM,GACxCj9C,EAAUk4C,EAAW7pD,OAAQ6rE,GAEnC,IAAM,MAAMvpD,KAASunC,EAAW0G,cAAe5+C,GAAUwxC,WACxD3D,EAAOqD,kBAAmBvgC,GAI3Bw+G,GAA2B,QAAS5F,EAAWt6E,GAC/CkgF,GAA2B,QAAS5F,EAAWt6E,IAC7C,CAAEt0C,SAAU,YoBhId6jE,EAAWjV,IAAK,UAAWC,iBAAkB,CAAEtW,MAAO,YAAatzB,KAAM,OACzE4+C,EAAWjV,IAAK,UAAWC,iBAAkB,CAAEtW,MAAO,YAAatzB,KAAM,OAEzE4+C,EAAWjV,IAAK,mBAAoBzwD,IpBiC9Bo2C,GAAcA,EAAW97B,GAAI,mBAAoB,CAAEpS,EAAKnX,EAAMolD,KACpE,MAAM85E,EAAYl/H,EAAK0C,KAEvB,IAAM0iD,EAAcqB,WAAWkH,QAASuxE,EAAW,UAClD,OAGD,MAAM2E,EAAW3E,EAAU9hH,OACrBiiH,EAAQwE,EAASzmH,OACjB6mH,EAAW5E,EAAM/hH,cAAeumH,GAEhCX,EAAc,IAAIzC,GAAapB,EAAO,CAAEkB,IAAK0D,IAE7CP,EAAkB,CACvB9D,YAAaP,EAAM5/G,aAAc,gBAAmB,EACpD6/G,eAAgBD,EAAM5/G,aAAc,mBAAsB,GAI3D,IAAM,MAAMmkH,KAAaV,EACxB,GAAKU,EAAUzB,OAASjD,EAAY,CACnC,MAAM4E,EAAY1+E,EAAcpB,OAAOR,cAAeqgF,GAMtD,YAHAG,GAA4BJ,EAAWF,EAFhBt+E,EAAc/yB,OAAOo/B,iBAAkBqyE,EAAWD,EAASvmH,cAAe4hH,IAEzB95E,EAAe,CAAEk+E,UAAU,QoBtDrG1mH,EAAO+3D,WAAWjV,IAAK,mBAAoBC,iBAAkB,CAC5DtW,MAAO,YACPtzB,KAAMmuG,GACNt2E,kBAAmB,SAIpB+mB,EAAW5U,qBAAsB,CAAE1W,MAAO,UAAWtzB,KAAM,YAC3D4+C,EAAW5U,qBAAsB,CAAE1W,MAAO,UAAWtzB,KAAM,YAG3D4+C,EAAWjV,IAAK,mBAAoBzwD,IpB4D9Bo2C,GAAcA,EAAW97B,GAAI,iCAAkC,CAAEpS,EAAKnX,EAAMolD,KAClF,MAAMi6E,EAAQr/H,EAAK0C,KAEnB,IAAM0iD,EAAcqB,WAAWkH,QAAS3tD,EAAK0C,KAAMyU,EAAIhZ,MACtD,OAGD,MAAMulI,EAAkB,CACvB9D,YAAaP,EAAM5/G,aAAc,gBAAmB,EACpD6/G,eAAgBD,EAAM5/G,aAAc,mBAAsB,GAGrDs1H,EAAa/0I,EAAKkmD,kBAClB8uF,EAAah1I,EAAKmmD,kBAElB8uF,GAAsBF,EAAaC,EAAaD,EAAaC,GAAe,EAElF,IAAM,MAAMpR,KAAa,IAAInD,GAAapB,EAAO,CAAE6B,UAAW+T,IAC7D7Q,GAA+BR,EAAWF,EAAiBt+E,MoB3E5DxoC,EAAO24C,SAAStmD,IAAK,cAAe,IAAI,GAAoB2N,IAC5DA,EAAO24C,SAAStmD,IAAK,sBAAuB,IAAI,GAAkB2N,EAAQ,CAAE48G,MAAO,WACnF58G,EAAO24C,SAAStmD,IAAK,sBAAuB,IAAI,GAAkB2N,EAAQ,CAAE48G,MAAO,WACnF58G,EAAO24C,SAAStmD,IAAK,wBAAyB,IAAI,GAAqB2N,EAAQ,CAAE48G,MAAO,UACxF58G,EAAO24C,SAAStmD,IAAK,yBAA0B,IAAI,GAAqB2N,EAAQ,CAAE48G,MAAO,WAEzF58G,EAAO24C,SAAStmD,IAAK,iBAAkB,IAAI,GAAkB2N,IAC7DA,EAAO24C,SAAStmD,IAAK,oBAAqB,IAAI,GAAqB2N,IAEnEA,EAAO24C,SAAStmD,IAAK,2BAA4B,IAAI,GAAkB2N,EAAQ,CAAEqO,UAAW,gBAC5FrO,EAAO24C,SAAStmD,IAAK,6BAA8B,IAAI,GAAkB2N,EAAQ,CAAEqO,UAAW,kBAE9FrO,EAAO24C,SAAStmD,IAAK,kBAAmB,IAAI,GAAmB2N,IAE/DA,EAAO24C,SAAStmD,IAAK,sBAAuB,IAAI,GAAkB2N,EAAQ,CAAEqO,UAAW,WACvFrO,EAAO24C,SAAStmD,IAAK,qBAAsB,IAAI,GAAkB2N,EAAQ,CAAEqO,UAAW,UACtFrO,EAAO24C,SAAStmD,IAAK,qBAAsB,IAAI,GAAkB2N,EAAQ,CAAEqO,UAAW,UACtFrO,EAAO24C,SAAStmD,IAAK,mBAAoB,IAAI,GAAkB2N,EAAQ,CAAEqO,UAAW,QAEpFrO,EAAO24C,SAAStmD,IAAK,uBAAwB,IAAI,GAAwB2N,IACzEA,EAAO24C,SAAStmD,IAAK,oBAAqB,IAAI,GAAqB2N,IAEnEA,EAAO24C,SAAStmD,IAAK,iBAAkB,IAAI,GAAkB2N,IAC7DA,EAAO24C,SAAStmD,IAAK,oBAAqB,IAAI,GAAqB2N,IAEnE+3H,GAAwCtrF,GACxC2pF,GAA4B3pF,GAC5BirF,GAAiCjrF,EAAOzsC,EAAO83D,QAAQ1wB,QACvD+vF,GAAmC1qF,GAMpC,sBACC,MAAO,CAAE,K,MC3HI,MAAM,WAAwB,GAI5C,YAAa/sC,GACZrc,MAAOqc,GAEP,MAAMld,EAAOiB,KAAKq+E,aAGlBr+E,KAAKyJ,IAAK,QACVzJ,KAAKyJ,IAAK,aAAa,GACvBzJ,KAAKyJ,IAAK,QAAQ,GAClBzJ,KAAKyJ,IAAK,gBAAgB,GAC1BzJ,KAAKyJ,IAAK,aAAa,GACvBzJ,KAAKyJ,IAAK,aACVzJ,KAAKyJ,IAAK,SACVzJ,KAAKyJ,IAAK,YAAa,GACvBzJ,KAAKyJ,IAAK,WACVzJ,KAAKyJ,IAAK,kBAAmB,KAC7BzJ,KAAKyJ,IAAK,OAAQ,UAClBzJ,KAAKyJ,IAAK,YAAY,GAQtBzJ,KAAK8H,SAAW9H,KAAKw9E,mBAQrBx9E,KAAK60I,WAAa70I,KAAK80I,oBAQvB90I,KAAKumF,UAAYvmF,KAAKwmF,mBAYtBxmF,KAAKw0E,WAAa,IAAI,GAQtBx0E,KAAKk2E,aAAe,IAAI,GAExBl2E,KAAKs+E,YAAa,CACjBl2E,IAAK,MAEL9E,WAAY,CACXy6E,MAAO,CACN,KACA,iBACAh/E,EAAKi7E,GAAI,YAAa,YAAax7E,IAAUA,GAC7CwB,KAAKumF,UAAUlI,aAAarE,GAAI,OAAQ,yBAI1ClyE,SAAU9H,KAAK8H,WAOjB,SACClI,MAAM43B,SAENx3B,KAAK8H,SAAS8G,IAAK5O,KAAK60I,YACxB70I,KAAK8H,SAAS8G,IAAK5O,KAAKumF,WAExBvmF,KAAKk2E,aAAatnE,IAAK5O,KAAK60I,WAAWj2H,SACvC5e,KAAKk2E,aAAatnE,IAAK5O,KAAKumF,UAAU3nE,SAEtC5e,KAAKw0E,WAAWrjE,SAAUnR,KAAK4e,SAG/B5e,KAAKw0E,WAAW/qE,IAAK,aAAc,CAAEqN,EAAKo/B,KACpCl2C,KAAKk2E,aAAaF,iBAAmBh2E,KAAK60I,WAAWj2H,UACzD5e,KAAKumF,UAAU12D,QAEfqmB,OAKFl2C,KAAKw0E,WAAW/qE,IAAK,YAAa,CAAEqN,EAAKo/B,KACnCl2C,KAAKk2E,aAAaF,iBAAmBh2E,KAAKumF,UAAU3nE,UACxD5e,KAAK60I,WAAWhlH,QAEhBqmB,OAQH,QACCl2C,KAAK60I,WAAWhlH,QAUjB,oBACC,MAAMglH,EAAa,IAAI,GAwBvB,OAtBAA,EAAW91I,KACV,OACA,YACA,OACA,eACA,YACA,QACA,WACA,UACA,kBACA,OACA,YACC6U,GAAI5T,MAEN60I,EAAWz6D,eAAgB,CAC1B92E,WAAY,CACXy6E,MAAO,4BAIT82D,EAAWtjH,SAAU,WAAY3d,GAAI5T,MAE9B60I,EAUR,mBACC,MAAMtuD,EAAY,IAAI,GAChBxnF,EAAOwnF,EAAUlI,aAgBvB,OAdAkI,EAAUH,KAAO,GAEjBG,EAAUnM,eAAgB,CACzB92E,WAAY,CACXy6E,MAAO,wBACP,iBAAiB,EACjB,gBAAiBh/E,EAAK6U,GAAI,OAAQpV,GAASsN,OAAQtN,OAIrD+nF,EAAUxnF,KAAM,aAAc6U,GAAI5T,MAElCumF,EAAUh1D,SAAU,WAAY3d,GAAI5T,KAAM,QAEnCumF,G,MCzMM,MAAM,WAAwB,GAI5C,YAAatqE,GACZrc,MAAOqc,GAEP,MAAMld,EAAOiB,KAAKq+E,aAQlBr+E,KAAK2V,MAAQ3V,KAAK+0I,wBAQlB/0I,KAAKyJ,IAAK,OAAQ,GAQlBzJ,KAAKyJ,IAAK,UAAW,GAQrBzJ,KAAKjB,KAAM,SACT6U,GAAI5T,KAAM,UAAWA,KAAM,OAAQ,CAAEqmI,EAAS/G,IAAU,GAAIA,OAAY+G,KAE1ErmI,KAAKs+E,YAAa,CACjBl2E,IAAK,MACL9E,WAAY,CACXy6E,MAAO,CAAE,OAGVj2E,SAAU,CACT,CACCM,IAAK,MACL9E,WAAY,CACXy6E,MAAO,CAAE,mCAEV70D,GAAI,CACH,+CAAgDnqB,EAAK6U,GAAI,YAE1D9L,SAAU9H,KAAK2V,OAEhB,CACCvN,IAAK,MACL9E,WAAY,CACXy6E,MAAO,CAAE,oCAEVj2E,SAAU,CACT,CACCyqC,KAAMxzC,EAAK6U,GAAI,aAMnBsV,GAAI,CACHg9D,UAAWnnF,EAAK6U,GAAIkD,IACnBA,EAAI88B,mBAGLuyC,MAAOpnF,EAAK6U,GAAI,KACf5T,KAAKqU,KAAM,gBAKdrU,KAAKkpB,GAAI,UAAW,CAAEpS,EAAKq4B,KAC1B,MAAM,IAAE+wF,EAAG,OAAEhB,GAAW/vF,EAAO/tC,OAAO88B,QAGtCl+B,KAAKyJ,IAAK,CACT61H,KAAM9qF,SAAU0rF,GAChBmG,QAAS7xF,SAAU0qF,OAIrBl/H,KAAKkpB,GAAI,iBAAkB,KAC1BlpB,KAAKg1I,wBAGNh1I,KAAKkpB,GAAI,cAAe,KACvBlpB,KAAKg1I,wBAOP,SAQA,aAUA,sBACC,MAAM1V,EAAOt/H,KAAKs/H,KACZ+G,EAAUrmI,KAAKqmI,QAErBrmI,KAAK2V,MAAMtL,IAAK,CAAE4qI,EAASvyI,KAE1B,MAIMqiH,EAJU30G,KAAKklG,MAAO5yG,EAAQ,IAIb48H,GAHJ58H,EAAQ,GAGiB2jI,EAE5C4O,EAAQxrI,IAAK,OAAQs7G,KAQvB,wBACC,MAAMmwB,EAAQ,GAGd,IAAM,IAAIxyI,EAAQ,EAAGA,EAAQ,IAAKA,IAAU,CAC3C,MAAMw9H,EAAM9vH,KAAKklG,MAAO5yG,EAAQ,IAC1Bw8H,EAASx8H,EAAQ,GAEvBwyI,EAAMjyI,KAAM,IAAI,GAAsBjD,KAAKic,OAAQikH,EAAM,EAAGhB,EAAS,IAGtE,OAAOl/H,KAAKw9E,iBAAkB03D,IAiBhC,MAAM,WAA6B,GAIlC,YAAaj5H,EAAQikH,EAAKhB,GACzBt/H,MAAOqc,GAEP,MAAMld,EAAOiB,KAAKq+E,aAQlBr+E,KAAKyJ,IAAK,QAAQ,GAElBzJ,KAAKs+E,YAAa,CACjBl2E,IAAK,MACL9E,WAAY,CACXy6E,MAAO,CACN,oCACAh/E,EAAKi7E,GAAI,OAAQ,UAElB,WAAYkmD,EACZ,cAAehB,MCvLJ,MAAM,WAAgB,GAIpC,OACC,MAAM3iH,EAASvc,KAAKuc,OACd9d,EAAIuB,KAAKuc,OAAO9d,EAEhB02I,EAA4C,QADjB54H,EAAON,OAAOT,yBAG/Ce,EAAOL,GAAG+5D,iBAAiBrnE,IAAK,cAAeqN,IAC9C,MAAM+4C,EAAUz4C,EAAO24C,SAAS92D,IAAK,eAC/BkpF,EAAeF,GAAgBnrE,GAWrC,IAAIm5H,EAyBJ,OAlCA9tD,EAAavoF,KAAM,aAAc6U,GAAIohD,GAGrCsyB,EAAalD,WAAW36E,IAAK,CAC5B28E,KCpDW,8TDqDX11D,MAAOjyB,EAAG,gBACV6nF,SAAS,IAKVgB,EAAap+D,GAAI,gBAAiB,KAC5BksH,IAKLA,EAAkB,IAAI,GAAiBn5H,GACvCqrE,EAAajD,UAAUv8E,SAAS8G,IAAKwmI,GAErCA,EAAgB7jH,SAAU,WAAY3d,GAAI0zE,GAE1CA,EAAalD,WAAWl7D,GAAI,OAAQ,KAEnCksH,EAAgB9V,KAAO,EACvB8V,EAAgB/O,QAAU,IAG3B/+C,EAAap+D,GAAI,UAAW,KAC3B3M,EAAO04C,QAAS,cAAe,CAAEqqE,KAAM8V,EAAgB9V,KAAM+G,QAAS+O,EAAgB/O,UACtF9pH,EAAO83D,QAAQ3+C,KAAK7F,aAIfy3D,IAGR/qE,EAAOL,GAAG+5D,iBAAiBrnE,IAAK,cAAeqN,IAC9C,MAAM/Z,EAAU,CACf,CACCjC,KAAM,eACN+oD,MAAO,CACN+L,YAAa,uBACbrkC,MAAOjyB,EAAG,iBACV42I,UAAU,IAGZ,CAAEp1I,KAAM,aACR,CACCA,KAAM,SACN+oD,MAAO,CACN+L,YAAaogF,EAAe,wBAA0B,yBACtDzkH,MAAOjyB,EAAG,wBAGZ,CACCwB,KAAM,SACN+oD,MAAO,CACN+L,YAAaogF,EAAe,yBAA2B,wBACvDzkH,MAAOjyB,EAAG,yBAGZ,CACCwB,KAAM,SACN+oD,MAAO,CACN+L,YAAa,oBACbrkC,MAAOjyB,EAAG,mBAGZ,CACCwB,KAAM,SACN+oD,MAAO,CACN+L,YAAa,oBACbrkC,MAAOjyB,EAAG,oBAKb,OAAOuB,KAAKs1I,iBAAkB72I,EAAG,UE9HrB,yYF8HkDyD,EAAS+Z,KAGxEM,EAAOL,GAAG+5D,iBAAiBrnE,IAAK,WAAYqN,IAC3C,MAAM/Z,EAAU,CACf,CACCjC,KAAM,eACN+oD,MAAO,CACN+L,YAAa,oBACbrkC,MAAOjyB,EAAG,cACV42I,UAAU,IAGZ,CAAEp1I,KAAM,aACR,CACCA,KAAM,SACN+oD,MAAO,CACN+L,YAAa,sBACbrkC,MAAOjyB,EAAG,sBAGZ,CACCwB,KAAM,SACN+oD,MAAO,CACN+L,YAAa,sBACbrkC,MAAOjyB,EAAG,sBAGZ,CACCwB,KAAM,SACN+oD,MAAO,CACN+L,YAAa,iBACbrkC,MAAOjyB,EAAG,gBAGZ,CACCwB,KAAM,SACN+oD,MAAO,CACN+L,YAAa,iBACbrkC,MAAOjyB,EAAG,iBAKb,OAAOuB,KAAKs1I,iBAAkB72I,EAAG,OG1KrB,sYH0K4CyD,EAAS+Z,KAGlEM,EAAOL,GAAG+5D,iBAAiBrnE,IAAK,kBAAmBqN,IAClD,MAAM/Z,EAAU,CACf,CACCjC,KAAM,SACN+oD,MAAO,CACN+L,YAAa,mBACbrkC,MAAOjyB,EAAG,mBAGZ,CACCwB,KAAM,SACN+oD,MAAO,CACN+L,YAAaogF,EAAe,sBAAwB,qBACpDzkH,MAAOjyB,EAAG,sBAGZ,CACCwB,KAAM,SACN+oD,MAAO,CACN+L,YAAa,qBACbrkC,MAAOjyB,EAAG,qBAGZ,CACCwB,KAAM,SACN+oD,MAAO,CACN+L,YAAaogF,EAAe,qBAAuB,sBACnDzkH,MAAOjyB,EAAG,qBAGZ,CAAEwB,KAAM,aACR,CACCA,KAAM,SACN+oD,MAAO,CACN+L,YAAa,2BACbrkC,MAAOjyB,EAAG,2BAGZ,CACCwB,KAAM,SACN+oD,MAAO,CACN+L,YAAa,6BACbrkC,MAAOjyB,EAAG,8BAKb,OAAOuB,KAAKu1I,iCAAkC92I,EAAG,eI5NrC,yYJ4N0EyD,EAAS+Z,KAcjG,iBAAkByU,EAAO01D,EAAMlkF,EAAS+Z,GACvC,MAAMM,EAASvc,KAAKuc,OACd+qE,EAAeF,GAAgBnrE,GAC/Bi5C,EAAWl1D,KAAKw1I,6BAA8BluD,EAAcplF,GAmBlE,OAhBAolF,EAAalD,WAAW36E,IAAK,CAC5BinB,QACA01D,OACAE,SAAS,IAIVgB,EAAavoF,KAAM,aAAcopB,OAAQ+sC,EAAU,YAAa,IAAK8vD,IAC7DA,EAAW7rF,KAAMmW,GAAaA,IAGtCtvC,KAAKmR,SAAUm2E,EAAc,UAAWxwE,IACvCyF,EAAO04C,QAASn+C,EAAIlM,OAAOmqD,aAC3Bx4C,EAAO83D,QAAQ3+C,KAAK7F,UAGdy3D,EAcR,iCAAkC52D,EAAO01D,EAAMlkF,EAAS+Z,GACvD,MAAMM,EAASvc,KAAKuc,OACd+qE,EAAeF,GAAgBnrE,EAAQ,IAwB7C,OArBAjc,KAAKw1I,6BAA8BluD,EAAcplF,GAEjDolF,EAAalD,WAAW36E,IAAK,CAC5BinB,QACA01D,OACAE,SAAS,EACTh3C,WAAW,IAIZtvC,KAAKmR,SAAUm2E,EAAalD,WAAY,UAAW,KAClD7nE,EAAO04C,QAbiB,mBAcxB14C,EAAO83D,QAAQ3+C,KAAK7F,UAIrB7vB,KAAKmR,SAAUm2E,EAAc,UAAWxwE,IACvCyF,EAAO04C,QAASn+C,EAAIlM,OAAOmqD,aAC3Bx4C,EAAO83D,QAAQ3+C,KAAK7F,UAGdy3D,EAYR,6BAA8BA,EAAcplF,GAC3C,MAAMqa,EAASvc,KAAKuc,OACd24C,EAAW,GACXwvD,EAAkB,IAAI,GAE5B,IAAM,MAAMT,KAAU/hH,EACrBuzI,GAAexxB,EAAQ1nG,EAAQ24C,EAAUwvD,GAK1C,OAFA/8B,GAAmBL,EAAco9B,EAAiBnoG,EAAOL,GAAG+5D,kBAErD/gB,GAWT,SAASugF,GAAexxB,EAAQ1nG,EAAQ24C,EAAUwvD,GACjD,MAAM17D,EAAQi7D,EAAOj7D,MAAQ,IAAI,GAAOi7D,EAAOj7D,QACzC,YAAE+L,EAAW,SAAEsgF,GAAapxB,EAAOj7D,MAEzC,GAAqB,WAAhBi7D,EAAOhkH,MAAqC,iBAAhBgkH,EAAOhkH,KAA0B,CACjE,MAAM+0D,EAAUz4C,EAAO24C,SAAS92D,IAAK22D,GAErCG,EAASjyD,KAAM+xD,GAEfhM,EAAMv/C,IAAK,CAAEsrD,gBAEb/L,EAAMjqD,KAAM,aAAc6U,GAAIohD,GAEzBqgF,GACJrsF,EAAMjqD,KAAM,QAAS6U,GAAIohD,EAAS,SAIpChM,EAAMv/C,IAAK,CACVo7G,UAAU,IAGXH,EAAgB91G,IAAKq1G,G,MKtUP,MAAM,WAAuB,GAI3C,wBACC,MAAO,iBAMR,sBACC,MAAO,CAAE,IAMV,OACC,MACMj7D,EADShpD,KAAKuc,OACCysC,MAErBhpD,KAAKmR,SAAU63C,EAAO,gBAAiB,CAAElyC,EAAKzF,IAAUrR,KAAK01I,qBAAsB5+H,EAAKzF,GAAQ,CAAEZ,SAAU,SAE5GzQ,KAAK21I,4BACL31I,KAAK41I,yBAQN,wBACC,MAEMjQ,EAAgBN,GAFJrlI,KAAKuc,OAAOysC,MAAMhoD,SAASopB,WAI7C,OAA6B,GAAxBu7G,EAAc5jI,OACX,KASD4jI,EAQR,yBACC,MAAMA,EAAgB3lI,KAAKqlI,wBAE3B,OAAMM,EAIC3lI,KAAKuc,OAAOysC,MAAM5L,OAAQprB,IAChC,MAAMgqC,EAAmBhqC,EAAOkX,yBAC1B61F,EAAa/+H,KAAKuc,OAAOtE,QAAQ7Z,IAAK,eAEpCgxB,MAAOw3G,EAAav3G,KAAMs3G,GAAeZ,GAAkBJ,IAC3Dv2G,MAAOs3G,EAAUr3G,KAAMo3G,GAAYb,GAAeD,GAEpDqC,EAAcrC,EAAe,GAAI/hG,aAAc,SAErD,IAAIiyG,EAAkBpP,EAClBqP,EAAqBnP,EAIzB,GAAKX,GAAwBL,EAAe5G,GAAe,CAC1D,MAAMoM,EAAa,CAClBvE,cACAD,aACAD,WACAD,WAGDoP,EAAkB3K,GAAoBlD,EAAamD,GACnD2K,EAAqBxK,GAAuBtD,EAAamD,GAG1D,MAOMnM,EAAQ+I,GAAuBC,EAPd,CACtBzH,SAAUmG,EACV/F,YAAaiG,EACbnG,OAAQoV,EACRhV,UAAWiV,GAGsD9jH,GAIlE,OAFAA,EAAOruB,OAAQq7H,EAAOhjE,EAAkB,GAEjCA,IAxCA,KA0DT,iBAAkB+5E,EAAY5D,GAC7B,MAAM6D,EAAgBh2I,KAAKi2I,kBAAmBF,EAAY5D,GAE1DnyI,KAAKuc,OAAOysC,MAAM5L,OAAQprB,IACzBA,EAAOyI,aACNu7G,EAAc1Q,MAAMj7H,IAAKy3H,GAAQ9vG,EAAO+0B,cAAe+6E,IACvD,CAAEnxG,SAAUqlH,EAAcrlH,aAU7B,eACC,MAEM/R,EADiB,IADL5e,KAAKuc,OAAOysC,MAAMhoD,SAASopB,UACP8F,aAAc9mB,MACrBknB,sBAE/B,OAAK1R,GAAWA,EAAQze,GAAI,UAAW,aAC/Bye,EAGD,KAQR,gBACC,MAEMA,EADkB,GADN5e,KAAKuc,OAAOysC,MAAMhoD,SAASopB,UACJ8F,aACTI,sBAEhC,OAAK1R,GAAWA,EAAQze,GAAI,UAAW,aAC/Bye,EAGD,KAcR,4BACC,MAAMrC,EAASvc,KAAKuc,OACd25H,EAAc,IAAI79H,IAExBkE,EAAO+3D,WAAWjV,IAAK,mBAAoBzwD,IAAKo2C,GAAcA,EAAW97B,GAAI,YAAa,CAAEpS,EAAKnX,EAAMolD,KACtG,MAAMiJ,EAAajJ,EAAc/yB,QAqBlC,SAAqCA,GACpC,IAAM,MAAMmkH,KAAyBD,EACpClkH,EAAO6K,YAAa,+BAAgCs5G,GAGrDD,EAAY3sI,QAxBZ6sI,CAA4BpoF,GAE5B,MAAM23E,EAAgB3lI,KAAKqlI,wBAE3B,IAAMM,EACL,OAGD,IAAM,MAAM9G,KAAa8G,EAAgB,CACxC,MAAM7qG,EAAciqB,EAAcpB,OAAOR,cAAe07E,GAExD7wE,EAAWrxB,SAAU,+BAAgC7B,GACrDo7G,EAAYtnI,IAAKksB,GAGlB,MAAMu7G,EAAetxF,EAAcpB,OAAOR,cAAewiF,EAAeA,EAAc5jI,OAAS,IAC/FisD,EAAWvzB,aAAc47G,EAAc,IACrC,CAAE5lI,SAAU,YAkBhB,yBACC,MAAM8L,EAASvc,KAAKuc,OAEpBvc,KAAKkpB,GAAI,mBAAoB,KAC5B,IAAMlpB,KAAKsvC,UAAY,CACtB,MAAMq2F,EAAgB3lI,KAAKqlI,wBAE3B,IAAMM,EACL,OAGDppH,EAAOysC,MAAM5L,OAAQprB,IACpB,MAAMnH,EAAWmH,EAAOo/B,iBAAkBu0E,EAAe,GAAK,GACxD12G,EAAQ1S,EAAOysC,MAAMC,OAAO8D,yBAA0BliC,GAE5DmH,EAAOyI,aAAcxL,QAazB,qBAAsBhe,EAAOI,GAC5B,MAAQ+Y,EAAWloB,GAAYmP,EACzB23C,EAAQhpD,KAAKuc,OAAOysC,MACpBh5B,GAAc9tB,GAAgC,YAArBA,EAAQ0oB,UACjCq7G,EAAqBZ,GAAuBj7G,GAE5C67G,EAAmBlkI,SAIzBkP,EAAMnB,OAENk5C,EAAM5L,OAAQprB,IACb,MAAMskH,EAAoBrQ,EAAoBj2G,EAAai2G,EAAmBlkI,OAAS,EAAI,GAE3FinD,EAAM5L,OAAQprB,IACb,IAAM,MAAM6sG,KAAaoH,EACxBj9E,EAAM8jB,cAAe96C,EAAOsiC,gBAAiBuqE,EAAW,SAI1D,MAAM0X,EAAgBvtF,EAAMC,OAAO8D,yBAA0B/6B,EAAOo/B,iBAAkBklF,EAAmB,IAKpGlsH,EAAUjqB,GAAI,qBAClB6xB,EAAOyI,aAAc87G,GAErBnsH,EAAUnE,MAAOswH,MAgBpB,kBAAmBR,EAAY5D,GAC9B,MAAMpT,EAAa/+H,KAAKuc,OAAOtE,QAAQ7Z,IAAK,cACtCo0I,EAAgBzT,EAAWI,gBAAiB4W,GAC5CtD,EAAc1T,EAAWI,gBAAiBgT,GAE1C5R,EAAWnwH,KAAK0M,IAAK01H,EAActS,IAAKuS,EAAYvS,KACpDO,EAASrwH,KAAKsR,IAAK8wH,EAActS,IAAKuS,EAAYvS,KAElDS,EAAcvwH,KAAK0M,IAAK01H,EAActT,OAAQuT,EAAYvT,QAC1D2B,EAAYzwH,KAAKsR,IAAK8wH,EAActT,OAAQuT,EAAYvT,QAGxDsX,EAAe,IAAIrtI,MAAOs3H,EAASF,EAAW,GAAItwH,KAAM,MAAO5F,IAAK,IAAM,IAE1EosI,EAAgB,CACrBlW,WACAE,SACAE,cACAE,aAGD,IAAM,MAAM,IAAEX,EAAG,KAAE4B,KAAU,IAAI1B,GAAa2V,EAAWnyG,aAAc,SAAW6yG,GACjFD,EAActW,EAAMK,GAAWt9H,KAAM6+H,GAGtC,MAAM4U,EAAiBjE,EAAYvS,IAAMsS,EAActS,IACjDyW,EAAmBlE,EAAYvT,OAASsT,EAActT,OAU5D,OARKwX,GACJF,EAAa12G,UAGT62G,GACJH,EAAa/yI,QAASy8H,GAAOA,EAAIpgG,WAG3B,CACNwlG,MAAOkR,EAAa7zE,OACpBhyC,SAAU+lH,GAAkBC,IChUhB,MAAM,WAAuB,GAI3C,wBACC,MAAO,iBAMR,sBACC,MAAO,CAAE,GAAgB,IAM1B,OACC,MAAMp6H,EAASvc,KAAKuc,OACdghD,EAAehhD,EAAO83D,QAAQ3+C,KAAK10B,SAEzChB,KAAKmR,SAAUosD,EAAc,OAAQ,CAAEzmD,EAAKnX,IAAUK,KAAK42I,WAAY9/H,EAAKnX,IAC5EK,KAAKmR,SAAUosD,EAAc,MAAO,CAAEzmD,EAAKnX,IAAUK,KAAK42I,WAAY9/H,EAAKnX,IAC3EK,KAAKmR,SAAUoL,EAAOysC,MAAO,gBAAiB,CAAElyC,EAAKzF,IAAUrR,KAAK62I,iBAAkB//H,KAAQzF,GAAQ,CAAEZ,SAAU,SAElHzQ,KAAKm2D,SAAU,yBAUhB,WAAYr/C,EAAKnX,GAChB,MAAMm3I,EAAiB92I,KAAKuc,OAAOtE,QAAQ7Z,IAAK,IAEhD,IAAM04I,EAAezR,wBACpB,OAGD,GAAiB,OAAZvuH,EAAIhZ,MAAiBkC,KAAKuc,OAAO4gC,WACrC,OAGDx9C,EAAKi0C,iBACL98B,EAAIhH,OAEJ,MAAMg9E,EAAiB9sF,KAAKuc,OAAO5c,KAC7B49D,EAAev9D,KAAKuc,OAAO83D,QAAQ3+C,KAAK10B,SAExCkG,EAAU4lF,EAAehvB,OAAQg5E,EAAeC,0BAEtDx5E,EAAalpD,KAAM,kBAAmB,CACrCu3E,aAAcjsF,EAAKisF,aACnB1kF,UACA4S,OAAQhD,EAAIhZ,OAkBd,iBAAkBgZ,EAAK5P,EAASynB,GAC/B,GAAKA,IAAeA,EAAWxuB,GAAI,qBAClC,OAGD,MAAM6oD,EAAQhpD,KAAKuc,OAAOysC,MACpB+1E,EAAa/+H,KAAKuc,OAAOtE,QAAQ7Z,IAAK,IAG5C,IAAI44I,EA6MC,SAAuC9vI,EAAS8hD,GACtD,IAAM9hD,EAAQ/G,GAAI,sBAAyB+G,EAAQ/G,GAAI,WACtD,OAAO,KAIR,GAAK+G,EAAQ/G,GAAI,UAAW,SAC3B,OAAO+G,EAKR,GAA2B,GAAtBA,EAAQ4f,YAAmB5f,EAAQgW,SAAU,GAAI/c,GAAI,UAAW,SACpE,OAAO+G,EAAQgW,SAAU,GAK1B,MAAM+5H,EAAejuF,EAAM0L,cAAextD,GAE1C,IAAM,MAAM0X,KAAWq4H,EAAa3vF,WACnC,GAAK1oC,EAAQze,GAAI,UAAW,SAAY,CAEvC,MAAM+2I,EAAcluF,EAAM1iB,YAAa2wG,EAAap2H,MAAOmoC,EAAMsT,qBAAsB19C,IAEvF,GAAKoqC,EAAM0U,WAAYw5E,EAAa,CAAEv5E,mBAAmB,IACxD,OAAO,KAIR,MAAMw5E,EAAanuF,EAAM1iB,YAAa0iB,EAAM2T,oBAAqB/9C,GAAWq4H,EAAan2H,KAEzF,OAAKkoC,EAAM0U,WAAYy5E,EAAY,CAAEx5E,mBAAmB,IAChD,KAID/+C,EAIT,OAAO,KAtPYw4H,CAA8BlwI,EAAS8hD,GAEzD,IAAMguF,EACL,OAGD,MAAM/Q,EAAqBP,GAAgC18E,EAAMhoD,SAASopB,WAEpE67G,EAAmBlkI,QAOzB+U,EAAIhH,OAEJk5C,EAAM5L,OAAQprB,IACb,MAAMqlH,EAAmB,CACxBrxG,MAAO+4F,EAAWwL,WAAYyM,GAC9Bt+F,OAAQqmF,EAAWwO,QAASyJ,IAIvB5sH,EA8OT,SAAiC67G,EAAoBoR,EAAkBrlH,EAAQ+sG,GAC9E,MAAMuY,EAAgBrR,EAAoB,GAAIriG,aAAc,SAEtD4iG,EAAgBT,GAAkBE,GAClCC,EAAaN,GAAeK,GAE5B77G,EAAY,CACjBw8G,YAAaJ,EAAcp3G,MAC3Bu3G,WAAYH,EAAcn3G,KAC1Bq3G,SAAUR,EAAW92G,MACrBq3G,QAASP,EAAW72G,MAIfkoH,EAAsD,IAA9BtR,EAAmBlkI,OAE5Cw1I,IACJntH,EAAUq8G,SAAW4Q,EAAiB3+F,OAAS,EAC/CtuB,EAAUu8G,YAAc0Q,EAAiBrxG,MAAQ,EAoCnD,SAA0Bg5F,EAAOwY,EAAgBC,EAAe1Y,GAC/D,MAAM2Y,EAAa3Y,EAAWwL,WAAYvL,GACpC2Y,EAAc5Y,EAAWwO,QAASvO,GAEnCyY,EAAgBC,GACpB3Y,EAAW4I,cAAe3I,EAAO,CAChCyI,GAAIiQ,EACJrR,QAASoR,EAAgBC,IAItBF,EAAiBG,GACrB5Y,EAAWyI,WAAYxI,EAAO,CAC7ByI,GAAIkQ,EACJrY,KAAMkY,EAAiBG,IAhDxBC,CAAiBN,EAAeltH,EAAUq8G,QAAU,EAAGr8G,EAAUu8G,WAAa,EAAG5H,IAK7EwY,IAA0BvR,GAAwBC,EAAoBlH,GA8H5E,SAA2CC,EAAOmM,EAAYn5G,GAC7D,MAAM,SAAE00G,EAAQ,QAAED,EAAO,YAAEG,EAAW,WAAED,GAAewE,EAEjDjF,EAAa,CAAE92G,MAAOs3G,EAAUr3G,KAAMo3G,GACtCD,EAAgB,CAAEp3G,MAAOw3G,EAAav3G,KAAMs3G,GAGlDkR,GAAiB7Y,EAAO4H,EAAaV,EAAYl0G,GACjD6lH,GAAiB7Y,EAAO2H,EAAa,EAAGT,EAAYl0G,GAGpD8lH,GAAmB9Y,EAAO0H,EAAUF,EAAex0G,GACnD8lH,GAAmB9Y,EAAOyH,EAAU,EAAGD,EAAex0G,EAAQ00G,GAtI7DqR,CAAkCT,EAAeltH,EAAW4H,IAiB5D5H,EAAUq8G,QAAUyE,GAAoBoM,EAAeltH,GACvDA,EAAUu8G,WAAa2E,GAAuBgM,EAAeltH,IAG9D,OAAOA,EAhSa4tH,CAAwB/R,EAAoBoR,EAAkBrlH,EAAQ+sG,GAIlFkZ,EAAkB7tH,EAAUq8G,QAAUr8G,EAAUs8G,SAAW,EAC3DwR,EAAiB9tH,EAAUu8G,WAAav8G,EAAUw8G,YAAc,EAShEqB,EAAiB,CACtB1H,SAAU,EACVI,YAAa,EACbF,OAAQrwH,KAAK0M,IAAKm7H,EAAiBZ,EAAiB3+F,QAAW,EAC/DmoF,UAAWzwH,KAAK0M,IAAKo7H,EAAgBb,EAAiBrxG,OAAU,GAGjEgxG,EAAcjP,GAAuBiP,EAAa/O,EAAgBj2G,GAGlE,MAAMslH,EAAgBrR,EAAoB,GAAIriG,aAAc,SAEtDoyG,EAAgBh2I,KAAKm4I,gCAAiCnB,EAAaK,EAAkBC,EAAeltH,EAAW4H,GAErH,GAAKhyB,KAAKuc,OAAOtE,QAAQ7Z,IAAK,kBAAmBkxC,UAAY,CAG5D,MAAM8qD,EAAkBmrC,GAAYyQ,EAAc3rI,IAAKy3H,GAAQ9vG,EAAO+0B,cAAe+6E,KAErF9vG,EAAOyI,aAAc2/D,QAGrBpoE,EAAOyI,aAAcu7G,EAAe,GAAK,MAnD1C/K,GAAwB+L,EAAajY,GAyEvC,gCAAiCiY,EAAaK,EAAkBC,EAAeltH,EAAW4H,GACzF,MAAQgU,MAAOoyG,EAAa1/F,OAAQ2/F,GAAiBhB,EAG/CiB,EAsRR,SAA4BtZ,EAAOh5F,EAAO0S,GAEzC,MAAMruC,EAAM,IAAIlB,MAAOuvC,GAASzoC,KAAM,MACpC5F,IAAK,IAAM,IAAIlB,MAAO68B,GAAQ/1B,KAAM,OAEtC,IAAM,MAAM,OAAEivH,EAAM,IAAEgB,EAAG,KAAE4B,KAAU,IAAI1B,GAAapB,GACrD30H,EAAK61H,GAAOhB,GAAW4C,EAGxB,OAAOz3H,EA/RyBkuI,CAAmBvB,EAAaoB,EAAaC,GAEtEG,EAAmB,IAAK,IAAIpY,GAAakX,EAAe,CAC7D/W,SAAUn2G,EAAUs8G,SACpBjG,OAAQr2G,EAAUq8G,QAClB9F,YAAav2G,EAAUw8G,YACvB/F,UAAWz2G,EAAUu8G,WACrB5F,iBAAiB,KAIZiV,EAAgB,GAGtB,IAAIr1F,EAQJ,IAAM,MAAM4iF,KAAaiV,EAAmB,CAC3C,MAAM,IAAEtY,EAAG,OAAEhB,GAAWqE,EAGnBrE,IAAW90G,EAAUw8G,cACzBjmF,EAAiB4iF,EAAUiG,qBAI5B,MAAMiP,EAAYvY,EAAM91G,EAAUs8G,SAC5BgS,EAAexZ,EAAS90G,EAAUw8G,YAClC+R,EAAaL,EAAwBG,EAAYJ,GAAgBK,EAAeN,GAIhFQ,EAAeD,EAAa3mH,EAAOqhD,aAAcslE,GAAe,KAGhEE,EAAe74I,KAAK84I,sBAAuBvV,EAAWqV,EAAcj4F,EAAgB3uB,GAGpF6mH,IAKNnQ,GAAuBmQ,EAAc3Y,EAAKhB,EAAQ90G,EAAUq8G,QAASr8G,EAAUu8G,WAAY30G,GAE3FgkH,EAAc/yI,KAAM41I,GAEpBl4F,EAAiB3uB,EAAO2qC,oBAAqBk8E,IAI9C,MAAMtZ,EAAc/qF,SAAU8iG,EAAcl4H,aAAc,gBAAmB,GACvE6/G,EAAiBzqF,SAAU8iG,EAAcl4H,aAAc,mBAAsB,GAE7E25H,EAAsC3uH,EAAUs8G,SAAWnH,GAAeA,GAAen1G,EAAUq8G,QACnGuS,EAAyC5uH,EAAUw8G,YAAc3H,GAAkBA,GAAkB70G,EAAUu8G,WAErH,GAAKoS,EAAsC,CAC1C,MACME,EAAWnB,GAAmBR,EAAe/X,EAD9B,CAAEnwG,MAAOhF,EAAUw8G,YAAav3G,KAAMjF,EAAUu8G,YACS30G,EAAQ5H,EAAUs8G,UAEhGsP,EAAc/yI,QAASg2I,GAGxB,GAAKD,EAAyC,CAC7C,MACMC,EAAWpB,GAAiBP,EAAerY,EAD/B,CAAE7vG,MAAOhF,EAAUs8G,SAAUr3G,KAAMjF,EAAUq8G,SACaz0G,GAE5EgkH,EAAc/yI,QAASg2I,GAGxB,OAAOjD,EAaR,sBAAuBzS,EAAWqV,EAAcj4F,EAAgB3uB,GAC/D,MAAM,KAAE8vG,EAAI,SAAEyG,GAAahF,EAW3B,OALKgF,GACJv2G,EAAO7tB,OAAQ29H,GAIV8W,GAIN5mH,EAAOruB,OAAQi1I,EAAcj4F,GAEtBi4F,GALC,MAgPV,SAASd,GAAmB9Y,EAAOkK,EAAUgQ,EAAclnH,EAAQuuG,EAAW,GAE7E,GAAK2I,EAAW,EACf,OAQD,OALyBN,GAA+B5J,EAAOkK,EAAU3I,GAGnCv8H,OAAQ,EAAIk7H,SAAQ0K,eAAiBuP,GAAuBja,EAAQ0K,EAAWsP,IAEjG7uI,IAAK,EAAIy3H,UAAYmH,GAAmBnH,EAAMoH,EAAUl3G,IAG7E,SAAS6lH,GAAiB7Y,EAAO+K,EAAaqP,EAAWpnH,GAExD,GAAK+3G,EAAc,EAClB,OAQD,OALyBN,GAAiCzK,EAAO+K,GAG3B/lI,OAAQ,EAAIk8H,MAAK6I,gBAAkBoQ,GAAuBjZ,EAAK6I,EAAYqQ,IAE7F/uI,IAAK,EAAIy3H,OAAM5C,YAAc4K,GAAiBhI,EAAM5C,EAAQ6K,EAAa/3G,IAM9F,SAASmnH,GAAuBz2I,EAAO0qI,EAAMt+C,GAC5C,MAAMuqD,EAAW32I,EAAQ0qI,EAAO,GAC1B,MAAEh+G,EAAK,KAAEC,GAASy/D,EAKxB,OAH0BpsF,GAAS0sB,GAAS1sB,GAAS2sB,GAChB3sB,EAAQ0sB,GAASiqH,GAAYjqH,EC5iBpD,MAAM,WAAsB,GAI1C,wBACC,MAAO,gBAMR,sBACC,MAAO,CAAE,IAMV,OACC,MACMmuC,EADOv9D,KAAKuc,OAAO83D,QAAQ3+C,KACP10B,SAG1BhB,KAAKuc,OAAOi4D,WAAW/qE,IAAK,MAAO,IAAK4H,IAAUrR,KAAKs5I,6BAA8BjoI,GAAQ,CAAEZ,SAAU,QACzGzQ,KAAKuc,OAAOi4D,WAAW/qE,IAAK,MAAOzJ,KAAKu5I,gBAAgB,GAAQ,CAAE9oI,SAAU,QAC5EzQ,KAAKuc,OAAOi4D,WAAW/qE,IAAK,YAAazJ,KAAKu5I,gBAAgB,GAAS,CAAE9oI,SAAU,QAKnFzQ,KAAKmR,SAAUosD,EAAc,UAAW,IAAKlsD,IAAUrR,KAAKw5I,cAAenoI,GAAQ,CAAEZ,SAAU,GAAWrS,IAAK,QAAW,KAW3H,0BAA2BuB,EAAMu2C,GAChC,MAAM35B,EAASvc,KAAKuc,OAEdqsF,EADYrsF,EAAOysC,MAAMhoD,SAASopB,UACNsH,qBAE5Bk3E,GAAoBA,EAAgBzoG,GAAI,UAAW,WAIzD+1C,IAEA35B,EAAOysC,MAAM5L,OAAQprB,IACpBA,EAAOyI,aAAczI,EAAO0iC,cAAek0C,EAAgB1rF,SAAU,GAAIA,SAAU,QAWrF,eAAgBgyD,GACf,MAAM3yD,EAASvc,KAAKuc,OAEpB,MAAO,CAAEqyE,EAAc14C,KAEtB,IAAI2oF,EAAY2G,GADEjpH,EAAOysC,MAAMhoD,SAASopB,WACuB,GAM/D,GAJMy0G,IACLA,EAAY7+H,KAAKuc,OAAOtE,QAAQ7Z,IAAK,kBAAmBq7I,iBAGnD5a,EACL,OAGD3oF,IAEA,MAAMstF,EAAW3E,EAAU9hH,OACrBiiH,EAAQwE,EAASzmH,OAEjB28H,EAAkB1a,EAAM/hH,cAAeumH,GACvCmW,EAAmBnW,EAASvmH,cAAe4hH,GAE3C+a,EAAwC,IAArBD,EAEzB,IAAMzqE,GAAa0qE,GAAwC,IAApBF,EAMtC,YAJAn9H,EAAOysC,MAAM5L,OAAQprB,IACpBA,EAAOyI,aAAczI,EAAO+0B,cAAei4E,MAM7C,MAAM6a,EAAkBF,IAAqBnW,EAAS18G,WAAa,EAC7DgzH,EAAYJ,IAAoB1a,EAAMl4G,WAAa,EAEzD,GAAKooD,GAAa4qE,GAAaD,IAC9Bt9H,EAAO04C,QAAS,uBAIXykF,IAAoB1a,EAAMl4G,WAAa,GAK3C,YAJAvK,EAAOysC,MAAM5L,OAAQprB,IACpBA,EAAOyI,aAAczI,EAAO+0B,cAAei4E,MAO9C,IAAI8O,EAGJ,GAAK5+D,GAAa2qE,EAAkB,CACnC,MAAME,EAAU/a,EAAM9hH,SAAUw8H,EAAkB,GAElD5L,EAAciM,EAAQ78H,SAAU,QAG5B,IAAMgyD,GAAa0qE,EAAmB,CAC1C,MAAMI,EAAchb,EAAM9hH,SAAUw8H,EAAkB,GAEtD5L,EAAckM,EAAY98H,SAAU88H,EAAYlzH,WAAa,QAI7DgnH,EAActK,EAAStmH,SAAUy8H,GAAqBzqE,EAAY,GAAK,IAGxE3yD,EAAOysC,MAAM5L,OAAQprB,IACpBA,EAAOyI,aAAczI,EAAO0iC,cAAeo5E,OAY9C,WAAY96H,EAAW47E,GACtB,MAAMryE,EAASvc,KAAKuc,OACdgY,EAAUq6D,EAAar6D,QAE7B,IAAMS,GAAgBT,GACrB,OAGD,MAAM3J,EAAYqK,GAAmCV,EAAShY,EAAON,OAAOT,0BACzDxb,KAAKi6I,iBAAkBrvH,EAAWgkE,EAAal6D,YAGjEk6D,EAAah7C,iBACbg7C,EAAa/6C,kBACb7gC,EAAUlD,QAYZ,iBAAkB8a,EAAW6uF,GAC5B,MACMrvF,EADQpqB,KAAKuc,OAAOysC,MACFhoD,SAASopB,UAC3B8kD,EAAY,CAAE,QAAS,QAAS91D,SAAUwR,GAI1C+6G,EAAgBN,GAAuBj7G,GAE7C,GAAKu7G,EAAc5jI,OAAS,CAC3B,IAAIm4I,EAUJ,OAPCA,EADIzgC,EACQz5G,KAAKuc,OAAOtE,QAAQ7Z,IAAK,kBAAmBq7I,eAE5CvqE,EAAYy2D,EAAeA,EAAc5jI,OAAS,GAAM4jI,EAAe,GAGpF3lI,KAAKm6I,6BAA8BD,EAAWtvH,EAAW6uF,IAElD,EAIR,MAAMolB,EAAYz0G,EAAUyF,MAAM+T,aAAc,aAEhD,QAAMi7F,MAMDplB,IAAoBrvF,EAAUqD,aAAerD,EAAU4F,YAAck/C,OAKrElvE,KAAKo6I,uBAAwBhwH,EAAWy0G,EAAW3vD,KACvDlvE,KAAKm6I,6BAA8Btb,EAAWj0G,EAAW6uF,IAElD,KAeT,uBAAwBrvF,EAAWy0G,EAAW3vD,GAC7C,MAAMlmB,EAAQhpD,KAAKuc,OAAOysC,MACpBC,EAASjpD,KAAKuc,OAAOysC,MAAMC,OAE3Bp5B,EAAQq/C,EAAY9kD,EAAUqH,kBAAoBrH,EAAUoH,mBAIlE,IAAMy3B,EAAOgkB,gBAAiBp9C,GAAQ1vB,GAAI,UAAW,aAAgB,CAGpE,OAFyB6oD,EAAMoI,iBAAkBytE,EAAW3vD,EAAY,MAAQ,GAExDnuB,WAAYlxB,GAGrC,MAAMopF,EAAQjwD,EAAMsL,gBAAiBzkC,GAKrC,OAHAm5B,EAAMskB,gBAAiB2rC,EAAO,CAAEruF,UAAWskD,EAAY,UAAY,aAG5Dr/C,EAAMvD,QAAS2sF,EAAMppF,OAW7B,6BAA8BqqH,EAAWtvH,EAAW6uF,GAAkB,GACrE,MAAMzwD,EAAQhpD,KAAKuc,OAAOysC,MAEpBg2E,EAAQkb,EAAUt2G,aAAc,SAChCwkG,EAAW,IAAK,IAAIhI,GAAapB,EAAO,CAAE+B,iBAAiB,MACzDb,IAAKuG,EAASvH,OAAQyH,GAAeyB,EAAUA,EAASrmI,OAAS,GAEnEs4I,EAAkBjS,EAAShyH,KAAM,EAAI0rH,UAAYA,GAAQoY,GAC/D,IAAI,IAAEha,EAAG,OAAEhB,GAAWmb,EAEtB,OAASzvH,GACR,IAAK,OACJs0G,IACA,MAED,IAAK,KACJgB,IACA,MAED,IAAK,QACJhB,GAAUmb,EAAgBzQ,UAC1B,MAED,IAAK,OACJ1J,GAAOma,EAAgBtR,WAWzB,GAP4B7I,EAAM,GAAKA,EAAMuG,GACnBvH,EAAS,GAAKgB,GAAO,GACvBhB,EAASyH,GAAczG,GAAOuG,EAUrD,YAJAz9E,EAAM5L,OAAQprB,IACbA,EAAOyI,aAAczI,EAAO+0B,cAAei4E,MAMxCE,EAAS,GACbA,EAASzlB,EAAkB,EAAIktB,EAC/BzG,KACWhB,EAASyH,IACpBzH,EAASzlB,EAAkBktB,EAAa,EACxCzG,KAGD,MAAMoa,EAAelS,EAAShyH,KAAMs8H,GAAYA,EAASxS,KAAOA,GAAOwS,EAASxT,QAAUA,GAAS4C,KAC7F5yD,EAAY,CAAE,QAAS,QAAS91D,SAAUwR,GAC1CksH,EAAiB92I,KAAKuc,OAAOtE,QAAQ7Z,IAAK,kBAEhD,GAAKq7G,GAAmBq9B,EAAexnG,UAAY,CAClD,MAAMymG,EAAae,EAAeyD,iBAAmBL,EAErDpD,EAAe0D,iBAAkBzE,EAAYuE,OACvC,CACN,MAAMG,EAAmBzxF,EAAMoI,iBAAkBkpF,EAAcprE,EAAY,EAAI,OAE/ElmB,EAAM5L,OAAQprB,IACbA,EAAOyI,aAAcggH,OChUV,MAAM,WAA4B,GAIhD,YAAa/kH,GACZ91B,MAAO81B,GAEP11B,KAAK8zC,aAAe,CAAE,YAAa,UAAW,cAM/C,WAAYJ,GACX1zC,KAAKqU,KAAMq/B,EAASzzC,KAAMyzC,ICnBb,MAAM,WAAmB,GAIvC,wBACC,MAAO,aAMR,sBACC,MAAO,CAAE,IAMV,OACgB1zC,KAAKuc,OAIb83D,QAAQ3+C,KAAKknB,YAAa,IAEjC58C,KAAK06I,6BACL16I,KAAK26I,4BASN,6BACC,MAAMp+H,EAASvc,KAAKuc,OACpB,IAAIq+H,GAAuB,EAE3B,MAAM9D,EAAiBv6H,EAAOtE,QAAQ7Z,IAAK,IAE3C4B,KAAKmR,SAAUoL,EAAO83D,QAAQ3+C,KAAK10B,SAAU,YAAa,CAAE8V,EAAK83E,KAChE,IAAM5uF,KAAKsvC,YAAcwnG,EAAexnG,UACvC,OAGD,IAAMs/C,EAAal7C,SAAShf,SAC3B,OAGD,MAAMqhH,EAAae,EAAeyD,iBAAmB/U,GAAkCjpH,EAAOysC,MAAMhoD,SAASopB,WAAa,GAE1H,IAAM2rH,EACL,OAGD,MAAM5D,EAAanyI,KAAK66I,+BAAgCjsD,GAEnDujD,GAAc2I,GAAqB/E,EAAY5D,KACnDyI,GAAuB,EACvB9D,EAAe0D,iBAAkBzE,EAAY5D,GAE7CvjD,EAAah7C,oBAIf5zC,KAAKmR,SAAUoL,EAAO83D,QAAQ3+C,KAAK10B,SAAU,UAAW,KACvD45I,GAAuB,IAmBxB56I,KAAKmR,SAAUoL,EAAO83D,QAAQ3+C,KAAK10B,SAAU,kBAAmB8V,IAC1D8jI,GAGJ9jI,EAAIhH,QAEH,CAAEW,SAAU,YAahB,4BACC,MAAM8L,EAASvc,KAAKuc,OACpB,IAAIw5H,EAAY5D,EACZ4I,GAAqB,EACrBH,GAAuB,EAE3B,MAAM9D,EAAiBv6H,EAAOtE,QAAQ7Z,IAAK,IAE3C4B,KAAKmR,SAAUoL,EAAO83D,QAAQ3+C,KAAK10B,SAAU,YAAa,CAAE8V,EAAK83E,KAC1D5uF,KAAKsvC,WAAcwnG,EAAexnG,YAKnCs/C,EAAal7C,SAAShf,UAAYk6D,EAAal7C,SAASjf,SAAWm6D,EAAal7C,SAASlf,SAI9FuhH,EAAa/1I,KAAK66I,+BAAgCjsD,OAGnD5uF,KAAKmR,SAAUoL,EAAO83D,QAAQ3+C,KAAK10B,SAAU,YAAa,CAAE8V,EAAK83E,KAChE,IAAMA,EAAal7C,SAASw2C,QAC3B,OAGD,IAAM6rD,EACL,OAGD,MAAMiF,EAAgBh7I,KAAK66I,+BAAgCjsD,GAEtDosD,GAAiBF,GAAqB/E,EAAYiF,KACtD7I,EAAa6I,EAIPD,GAAsB5I,GAAc4D,IACzCgF,GAAqB,IAKjBA,IAINH,GAAuB,EACvB9D,EAAe0D,iBAAkBzE,EAAY5D,GAE7CvjD,EAAah7C,oBAGd5zC,KAAKmR,SAAUoL,EAAO83D,QAAQ3+C,KAAK10B,SAAU,UAAW,KACvD+5I,GAAqB,EACrBH,GAAuB,EACvB7E,EAAa,KACb5D,EAAa,OAIdnyI,KAAKmR,SAAUoL,EAAO83D,QAAQ3+C,KAAK10B,SAAU,kBAAmB8V,IAC1D8jI,GAGJ9jI,EAAIhH,QAEH,CAAEW,SAAU,YAUhB,+BAAgCm+E,GAE/B,MAAMqsD,EAAoBrsD,EAAaxtF,OACjCo1B,EAAex2B,KAAKuc,OAAO83D,QAAQ3+C,KAAK07B,iBAAkB6pF,EAAmB,GAInF,OAHsBj7I,KAAKuc,OAAO83D,QAAQ1wB,OAAOH,gBAAiBhtB,GAC/BzZ,OAEf6mB,aAAc,YAAa,CAAExmB,aAAa,KAIhE,SAAS09H,GAAqBI,EAAOC,GACpC,OAAOD,EAAMn+H,OAAOA,QAAUo+H,EAAMp+H,OAAOA,O,MCvMrC,SAASq+H,GAAwBhxH,GACvC,MAAM0Q,EAAc1Q,EAAUsH,qBAE9B,OAAKoJ,GAAeugH,GAAevgH,GAC3BA,EAGD,KASD,SAASwgH,GAAwBlxH,GACvC,MAAMmxH,EAiBP,SAAuB78F,EAAY88F,GAClC,IAAIz+H,EAASy+H,EAAkBz+H,OAE/B,KAAQA,GAAS,CAChB,GAAKA,EAAOjf,OAAS4gD,EACpB,OAAO3hC,EAGRA,EAASA,EAAOA,QAzBG6mB,CAAc,QAASxZ,EAAUoH,oBAErD,OAAK+pH,GAAeF,GAAeE,EAAYx+H,QACvCw+H,EAAYx+H,OAGb,KAOR,SAASs+H,GAAevgH,GACvB,QAASA,EAAYtQ,kBAAmB,UAAaq9E,GAAU/sE,GC1ChE,IAAI,GAAe,sBACf2gH,GAAkBxxI,OAAO,GAAaW,QAwB3B,OAPf,SAAsBgQ,GAEpB,OADAA,EAAS,GAASA,KACA6gI,GAAgBtxI,KAAKyQ,GACnCA,EAAO1Q,QAAQ,GAAc,QAC7B0Q,GCdN,MAAM8gI,GAAkB,CAEvBC,UAAW,CAAEvoI,KAAM,MAAOQ,GAAI,KAC9BgoI,oBAAqB,CAAExoI,KAAM,MAAOQ,GAAI,KACxCioI,UAAW,CAAEzoI,KAAM,OAAQQ,GAAI,KAG/BkoI,QAAS,CAAE1oI,KAAM,MAAOQ,GAAI,KAC5BmoI,SAAU,CAAE3oI,KAAM,MAAOQ,GAAI,KAC7BooI,UAAW,CAAE5oI,KAAM,MAAOQ,GAAI,KAC9BqoI,SAAU,CAAE7oI,KAAM,MAAOQ,GAAI,KAC7BsoI,cAAe,CAAE9oI,KAAM,MAAOQ,GAAI,KAClCuoI,gBAAiB,CAAE/oI,KAAM,KAAMQ,GAAI,KACnCwoI,mBAAoB,CAAEhpI,KAAM,KAAMQ,GAAI,KACtCyoI,SAAU,CAAEjpI,KAAM,KAAMQ,GAAI,KAC5B0oI,UAAW,CAAElpI,KAAM,KAAMQ,GAAI,KAC7B2oI,WAAY,CAAEnpI,KAAM,KAAMQ,GAAI,KAG9B4oI,mBAAoB,CAAEppI,KAAM,MAAOQ,GAAI,KACvC6oI,OAAQ,CAAErpI,KAAM,gBAAiBQ,GAAI,CAAE,KAAM,IAAK,OAClD8oI,OAAQ,CAAEtpI,KAAM,iBAAkBQ,GAAI,CAAE,KAAM,IAAK,OAGnD+oI,cAAe,CAAEvpI,KAAMwpI,GAAmB,KAAOhpI,GAAI,CAAE,KAAM,IAAK,KAAM,MACxEipI,gBAAiB,CAAEzpI,KAAMwpI,GAAmB,KAAQhpI,GAAI,CAAE,KAAM,IAAK,KAAM,MAG3EkpI,kBAAmB,CAAE1pI,KAAMwpI,GAAmB,KAAQhpI,GAAI,CAAE,KAAM,IAAK,KAAM,MAC7EmpI,oBAAqB,CAAE3pI,KAAMwpI,GAAmB,KAAOhpI,GAAI,CAAE,KAAM,IAAK,KAAM,MAG9EopI,gBAAiB,CAAE5pI,KAAMwpI,GAAmB,KAAOhpI,GAAI,CAAE,KAAM,IAAK,KAAM,MAC1EqpI,kBAAmB,CAAE7pI,KAAMwpI,GAAmB,KAAQhpI,GAAI,CAAE,KAAM,IAAK,KAAM,OAIxEspI,GAAwB,CAC7BC,QAAS,CAAE,YAAa,sBAAuB,aAC/CC,aAAc,CACb,UAAW,WAAY,YAAa,WAAY,gBAChD,kBAAmB,qBAAsB,WACzC,YAAa,cAEdC,WAAY,CAAE,qBAAsB,SAAU,UAC9CC,OAAQ,CAAE,gBAAiB,oBAItBC,GAA0B,CAC/B,UACA,eACA,aACA,UAmHD,SAASC,GAAepqI,GACvB,MAAoB,iBAARA,EACJ,IAAInJ,OAAQ,IAAK,GAAcmJ,QAIhCA,EASR,SAASqqI,GAAa7pI,GACrB,MAAkB,iBAANA,EACJ,IAAM,CAAEA,GACJA,aAAczK,MAClB,IAAMyK,EAIPA,EAQR,SAAS8pI,GAAgC7yH,GAGxC,OAFiBA,EAAS1M,SAAW0M,EAAS1M,SAAW0M,EAASuC,WAElD2N,gBAOjB,SAAS6hH,GAAmBe,GAC3B,OAAO,IAAI1zI,OAAQ,WAAY0zI,QAAuBA,QAAuBA,OChM/D,MAAM,WAAsB,IAG3C,GAAc5hI,eAAiB,CCChB,cAAyB,GAIvC,sBACC,MAAO,CAAE,GAAW,GAAO,GAAW,GAAY,GAAQ,IAM3D,wBACC,MAAO,eDXR,GpLhBc,cAAyB,GAIvC,wBACC,MAAO,aAMR,YACC/b,KAAK49I,sBACL59I,KAAK69I,6BACL79I,KAAK89I,yBACL99I,KAAK+9I,4BACL/9I,KAAKg+I,2BAYN,sBACC,MAAM9oF,EAAWl1D,KAAKuc,OAAO24C,SAExBA,EAAS92D,IAAK,iBAClBuiG,GAAwB3gG,KAAKuc,OAAQvc,KAAM,WAAY,gBAGnDk1D,EAAS92D,IAAK,iBAClBuiG,GAAwB3gG,KAAKuc,OAAQvc,KAAM,aAAc,gBAmB3D,6BACC,MAAMk1D,EAAWl1D,KAAKuc,OAAO24C,SAE7B,GAAKA,EAAS92D,IAAK,QAAW,CAC7B,MAAM6/I,EAAeh8C,GAAwCjiG,KAAKuc,OAAQ,QAE1EykF,GAAyBhhG,KAAKuc,OAAQvc,KAAM,wBAAyBi+I,GACrEj9C,GAAyBhhG,KAAKuc,OAAQvc,KAAM,oBAAqBi+I,GAGlE,GAAK/oF,EAAS92D,IAAK,UAAa,CAC/B,MAAM8/I,EAAiBj8C,GAAwCjiG,KAAKuc,OAAQ,UAI5EykF,GAAyBhhG,KAAKuc,OAAQvc,KAAM,+BAAgCk+I,GAC5El9C,GAAyBhhG,KAAKuc,OAAQvc,KAAM,4BAA6Bk+I,GAG1E,GAAKhpF,EAAS92D,IAAK,QAAW,CAC7B,MAAM+/I,EAAel8C,GAAwCjiG,KAAKuc,OAAQ,QAE1EykF,GAAyBhhG,KAAKuc,OAAQvc,KAAM,kBAAmBm+I,GAGhE,GAAKjpF,EAAS92D,IAAK,iBAAoB,CACtC,MAAMggJ,EAAwBn8C,GAAwCjiG,KAAKuc,OAAQ,iBAEnFykF,GAAyBhhG,KAAKuc,OAAQvc,KAAM,oBAAqBo+I,IAenE,yBACC,MAAMppF,EAAUh1D,KAAKuc,OAAO24C,SAAS92D,IAAK,WAErC42D,GACJA,EAAQ8uD,cACN9/G,OAAQlG,GAAQA,EAAK4d,MAAO,mBAC5BjY,QAAS8jD,IACT,MAAM82F,EAAQ92F,EAAW,GACnB9oC,EAAU,IAAIxU,OAAQ,OAAQo0I,WAEpC19C,GAAwB3gG,KAAKuc,OAAQvc,KAAMye,EAAS,KAEnD,IAAMu2C,EAAQ1lB,WAAa0lB,EAAQx2D,QAAU+oD,EAC5C,OAAO,EAGRvnD,KAAKuc,OAAO04C,QAAS,UAAW,CAAEz2D,MAAO+oD,QAc9C,4BACMvnD,KAAKuc,OAAO24C,SAAS92D,IAAK,eAC9BuiG,GAAwB3gG,KAAKuc,OAAQvc,KAAM,QAAS,cAYtD,2BACMA,KAAKuc,OAAO24C,SAAS92D,IAAK,cAC9BuiG,GAAwB3gG,KAAKuc,OAAQvc,KAAM,QAAS,esL7IxC,cAAmB,GAIjC,sBACC,MAAO,CAAE,GAAa,IAMvB,wBACC,MAAO,SCZM,cAAqB,GAInC,sBACC,MAAO,CAAE,GAAe,IAMzB,wBACC,MAAO,WCbM,cAAyB,GAIvC,sBACC,MAAO,CAAE,GAAmB,IAM7B,wBACC,MAAO,eCFM,cAAuB,GAIrC,wBACC,MAAO,WAMR,sBACC,MAAO,CAAE,GAAiB,GAAY,MCRzB,cAAwB,GAItC,sBACC,MAAO,CACN,GACA,GACA,IAOF,wBACC,MAAO,cC3BM,cAAsB,GAIpC,sBACC,MAAO,CAAE,GAAgB,IAM1B,wBACC,MAAO,YPOR,GQxBc,cAA2B,GAIzC,sBACC,MAAO,CAAE,IAMV,wBACC,MAAO,iBCVM,cAAyB,GAIvC,sBACC,MAAO,CAAE,GAAmB,IAM7B,wBACC,MAAO,eCTM,cAA2B,GAIzC,sBACC,MAAO,CAAE,IAMV,wBACC,MAAO,eAMR,YACC,MAAMuc,EAASvc,KAAKuc,OACd9d,EAAI8d,EAAO9d,EACe8d,EAAOtE,QAAQ7Z,IAAK,IAE5B8zE,SAAU,QAAS,CAC1C22C,UAAWpqH,EAAG,iBACdkX,MAAO4G,EAAOV,OAAOzd,IAAK,kBAAqB,GAC/C0qH,kBAAmB5f,OVHrB,GWbc,cAAqB,GAInC,wBACC,MAAO,SAMR,sBACC,MAAO,CAAE,GAAe,MC1BX,cAAmB,GAIjC,sBACC,MAAO,CAAE,GAAa,GAAQ,IAM/B,wBACC,MAAO,SCZM,cAAmB,GAIjC,sBACC,MAAO,CAAE,GAAa,IAMvB,wBACC,MAAO,SCJM,cAAyB,GAIvC,sBACC,MAAO,CAAE,GAAmB,GAAc,GAAgB,IAM3D,wBACC,MAAO,edYR,GexBc,cAA8B,GAI5C,wBACC,MAAO,kBAMR,sBACC,MAAO,CAAE,IAMV,OACC,MAAM3sF,EAASvc,KAAKuc,OACdghD,EAAehhD,EAAO83D,QAAQ3+C,KAAK10B,SACnCs9I,EAAc,GAEpBA,EAAYr7I,KAAM,IAAI,GAAkBs6D,IACxC+gF,EAAYr7I,KAAM,IAAI,GAAsBs6D,IAE5ChhD,EAAOtE,QAAQ7Z,IAAK,aAAc8qB,GACjC,sBACA,CAAEpS,EAAKnX,KACN,GAAKA,EAAK4+I,iCACT,OAGD,MAAM3iB,EAAaj8H,EAAKisF,aAAaL,QAAS,aACxCizD,EAAmBF,EAAYloI,KAAMwO,GAAcA,EAAWm7D,SAAU67C,IAEzE4iB,IACJA,EAAiBvpF,QAASt1D,GAE1BA,EAAK4+I,kCAAmC,IAG1C,CAAE9tI,SAAU,WCnCA,cAAoB,GAIlC,sBACC,MAAO,CAAE,GAAc,GAAS,GAAgB,GAAY,GAAe,GAAgB,IAM5F,wBACC,MAAO,UCzBM,cAA2B,GAIzC,sBACC,MAAO,CAAE,IAMV,wBACC,MAAO,eAMR,YACC,MAAM8L,EAASvc,KAAKuc,OACd9d,EAAI8d,EAAO9d,EACXggJ,EAA0BliI,EAAOtE,QAAQ7Z,IAAK,IAE9CsgJ,EAA2BniI,EAAOV,OAAOzd,IAAK,wBAE9CugJ,EAAoBpiI,EAAOV,OAAOzd,IAAK,sBAExCsgJ,GACJD,EAAwBvsE,SAAU,eAAgB,CACjD22C,UAAWpqH,EAAG,iBACdkX,MAAO+oI,EACP51B,kBAAmBwyB,KAIhBqD,GACJF,EAAwBvsE,SAAU,QAAS,CAC1C22C,UAAWpqH,EAAG,iBACdkX,MAAOgpI,EACP71B,kBAAmBsyB,OlBYR,cAAiC,GAI/C,wBACC,MAAO,qBAMR,YAAa7+H,GACZ3c,MAAO2c,GAEPA,EAAOV,OAAO5e,OAAQ,SAAU,CAC/B02F,gBAAiB,CAChBirD,QAASrB,MAQZ,OACC,MACMlpF,EADQr0D,KAAKuc,OAAOysC,MACGhoD,SAASopB,UAEtCiqC,EAAenrC,GAAI,eAAgB,KAElClpB,KAAKsvC,WAAa+kB,EAAellC,OAAOpS,OAAO5c,GAAI,UAAW,eAG/DH,KAAK6+I,gCAQN,gCACC,MAAMtiI,EAASvc,KAAKuc,OACdysC,EAAQzsC,EAAOysC,MACf97C,EAAQqP,EAAOtE,QAAQ7Z,IAAK,SAC5B0gJ,EA+GR,SAAmCjjI,GAClC,MAAMkjI,EAAQljI,EAAOkjI,OAAS,GACxB56I,EAAS0X,EAAO1X,QAAU,GAC1B66I,EAAeC,IAAmB96I,EAAOiV,SAAU6lI,GAIzD,OAcD,SAA0CC,GAEzC,MAAMC,EAAyB,IAAI9mI,IAEnC,IAAM,MAAM+mI,KAAyBF,EACpC,GAAKhC,GAAuBkC,GAC3B,IAAM,MAAMH,KAAkB/B,GAAuBkC,GACpDD,EAAuBvwI,IAAKqwI,QAG7BE,EAAuBvwI,IAAKwwI,GAI9B,OAAOj2I,MAAMiK,KAAM+rI,GA5BZE,CAFYxjI,EAAO+iI,QAAQn8I,OAAQs8I,GAAQ/6I,OAAQg7I,IAGxDh7I,OAAQg7I,GACR30I,IAAK40I,GAAkBvD,GAAiBuD,IAAoBA,GAC5D50I,IAAK40I,IAAkB,CACvB7rI,KAAMoqI,GAAeyB,EAAe7rI,MACpCQ,GAAI6pI,GAAawB,EAAerrI,OA3HC0rI,CAA0B/iI,EAAOV,OAAOzd,IAAK,2BAiDzEmwH,EAAU,IAAI,GAAahyG,EAAOysC,MA/CnBzW,IACpB,IAAM,MAAMgtG,KAA4BT,EAA4B,CAInE,GAHaS,EAAyBnsI,KACnBjJ,KAAMooC,GAGxB,MAAO,CAAEgtG,+BA2CZhxB,EAAQrlG,GAAI,eAtCY,CAAEpS,EAAKnX,KAC9B,IAAMuN,EAAMmkG,QAAS1xG,EAAKwrD,OACzB,OAGD,MAAM,KAAE/3C,EAAI,GAAEQ,GAAOjU,EAAK4/I,yBAEpB/vG,EAAUp8B,EAAKvJ,KAAMlK,EAAK4yC,MAC1BitG,EAAW5rI,EAAI47B,EAAQ/nC,MAAO,IAE9Bg4I,EAAe9/I,EAAKsvB,MAE1B,IAAIywH,EAAclwG,EAAQ9sC,MAE1BsmD,EAAMqC,cAAer5B,IACpB,IAAM,IAAIz0B,EAAI,EAAGA,EAAIiyC,EAAQztC,OAAQxE,IAAM,CAC1C,MAAMme,EAAQ8zB,EAASjyC,GACjBoiJ,EAAcH,EAAUjiJ,EAAI,GAElC,GAAoB,MAAfoiJ,EAAsB,CAC1BD,GAAehkI,EAAM3Z,OAErB,SAGD,MAAM69I,EAAkBH,EAAa5+H,MAAMyN,aAAcoxH,GACnDG,EAAe72F,EAAM1iB,YAAas5G,EAAiBA,EAAgBtxH,aAAc5S,EAAM3Z,SACvFuB,EAAao6I,GAAgCkC,GAEnD52F,EAAM6pB,cAAe7gD,EAAOwiC,WAAYmrF,EAAar8I,GAAcu8I,GAEnEH,GAAeC,EAAY59I,YAQ9BwsH,EAAQxvH,KAAM,aAAc6U,GAAI5T,SC9GlC,GAAc8b,cAAgB,CAC7Bs8D,QAAS,CACRziE,MAAO,CACN,UACA,IACA,OACA,SACA,OACA,eACA,eACA,IACA,SACA,UACA,IACA,cACA,aACA,cACA,aACA,OACA,SAGF08F,MAAO,CACNj6B,QAAS,CACR,kBACA,kBACA,IACA,yBAGF4mD,MAAO,CACN8gB,eAAgB,CACf,cACA,WACA,oBAIFvlI,SAAU,S","file":"ckeditor.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ClassicEditor\"] = factory();\n\telse\n\t\troot[\"ClassicEditor\"] = factory();\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(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, __webpack_require__);\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__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.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__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 98);\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/ckeditorerror\n */\n\n/* globals console */\n\n/**\n * URL to the documentation with error codes.\n */\nexport const DOCUMENTATION_URL =\n\t'https://ckeditor.com/docs/ckeditor5/latest/framework/guides/support/error-codes.html';\n\n/**\n * The CKEditor error class.\n *\n * You should throw `CKEditorError` when:\n *\n * * An unexpected situation occurred and the editor (most probably) will not work properly. Such exception will be handled\n * by the {@link module:watchdog/watchdog~Watchdog watchdog} (if it is integrated),\n * * If the editor is incorrectly integrated or the editor API is used in the wrong way. This way you will give\n * feedback to the developer as soon as possible. Keep in mind that for common integration issues which should not\n * stop editor initialization (like missing upload adapter, wrong name of a toolbar component) we use\n * {@link module:utils/ckeditorerror~logWarning `logWarning()`} and\n * {@link module:utils/ckeditorerror~logError `logError()`}\n * to improve developers experience and let them see the a working editor as soon as possible.\n *\n *\t\t/**\n *\t\t * Error thrown when a plugin cannot be loaded due to JavaScript errors, lack of plugins with a given name, etc.\n *\t\t *\n *\t\t * @error plugin-load\n *\t\t * @param pluginName The name of the plugin that could not be loaded.\n *\t\t * @param moduleName The name of the module which tried to load this plugin.\n *\t\t * /\n *\t\tthrow new CKEditorError( 'plugin-load', {\n *\t\t\tpluginName: 'foo',\n *\t\t\tmoduleName: 'bar'\n *\t\t} );\n *\n * @extends Error\n */\nexport default class CKEditorError extends Error {\n\t/**\n\t * Creates an instance of the CKEditorError class.\n\t *\n\t * @param {String} errorName The error id in an `error-name` format. A link to this error documentation page will be added\n\t * to the thrown error's `message`.\n\t * @param {Object|null} context A context of the error by which the {@link module:watchdog/watchdog~Watchdog watchdog}\n\t * is able to determine which editor crashed. It should be an editor instance or a property connected to it. It can be also\n\t * a `null` value if the editor should not be restarted in case of the error (e.g. during the editor initialization).\n\t * The error context should be checked using the `areConnectedThroughProperties( editor, context )` utility\n\t * to check if the object works as the context.\n\t * @param {Object} [data] Additional data describing the error. A stringified version of this object\n\t * will be appended to the error message, so the data are quickly visible in the console. The original\n\t * data object will also be later available under the {@link #data} property.\n\t */\n\tconstructor( errorName, context, data ) {\n\t\tconst message = `${ errorName }${ ( data ? ` ${ JSON.stringify( data ) }` : '' ) }${ getLinkToDocumentationMessage( errorName ) }`;\n\n\t\tsuper( message );\n\n\t\t/**\n\t\t * @type {String}\n\t\t */\n\t\tthis.name = 'CKEditorError';\n\n\t\t/**\n\t\t * A context of the error by which the Watchdog is able to determine which editor crashed.\n\t\t *\n\t\t * @type {Object|null}\n\t\t */\n\t\tthis.context = context;\n\n\t\t/**\n\t\t * The additional error data passed to the constructor. Undefined if none was passed.\n\t\t *\n\t\t * @type {Object|undefined}\n\t\t */\n\t\tthis.data = data;\n\t}\n\n\t/**\n\t * Checks if the error is of the `CKEditorError` type.\n\t */\n\tis( type ) {\n\t\treturn type === 'CKEditorError';\n\t}\n\n\t/**\n\t * A utility that ensures that the thrown error is a {@link module:utils/ckeditorerror~CKEditorError} one.\n\t * It is useful when combined with the {@link module:watchdog/watchdog~Watchdog} feature, which can restart the editor in case\n\t * of a {@link module:utils/ckeditorerror~CKEditorError} error.\n\t *\n\t * @static\n\t * @param {Error} err The error to rethrow.\n\t * @param {Object} context An object connected through properties with the editor instance. This context will be used\n\t * by the watchdog to verify which editor should be restarted.\n\t */\n\tstatic rethrowUnexpectedError( err, context ) {\n\t\tif ( err.is && err.is( 'CKEditorError' ) ) {\n\t\t\tthrow err;\n\t\t}\n\n\t\t/**\n\t\t * An unexpected error occurred inside the CKEditor 5 codebase. This error will look like the original one\n\t\t * to make the debugging easier.\n\t\t *\n\t\t * This error is only useful when the editor is initialized using the {@link module:watchdog/watchdog~Watchdog} feature.\n\t\t * In case of such error (or any {@link module:utils/ckeditorerror~CKEditorError} error) the watchdog should restart the editor.\n\t\t *\n\t\t * @error unexpected-error\n\t\t */\n\t\tconst error = new CKEditorError( err.message, context );\n\n\t\t// Restore the original stack trace to make the error look like the original one.\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/5595 for more details.\n\t\terror.stack = err.stack;\n\n\t\tthrow error;\n\t}\n}\n\n/**\n * Logs a warning to the console with a properly formatted message and adds a link to the documentation.\n * Use whenever you want to log a warning to the console.\n *\n *\t\t/**\n *\t\t * There was a problem processing the configuration of the toolbar. The item with the given\n *\t\t * name does not exist, so it was omitted when rendering the toolbar.\n *\t\t *\n *\t\t * @error toolbarview-item-unavailable\n *\t\t * @param {String} name The name of the component.\n *\t\t * /\n *\t\tlogWarning( 'toolbarview-item-unavailable', { name } );\n *\n * See also {@link module:utils/ckeditorerror~CKEditorError} for an explanation when to throw an error and when to log\n * a warning or an error to the console.\n *\n * @param {String} errorName The error name to be logged.\n * @param {Object} [data] Additional data to be logged.\n * @returns {String}\n */\nexport function logWarning( errorName, data ) {\n\tconsole.warn( ...formatConsoleArguments( errorName, data ) );\n}\n\n/**\n * Logs an error to the console with a properly formatted message and adds a link to the documentation.\n * Use whenever you want to log an error to the console.\n *\n *\t\t/**\n *\t\t * There was a problem processing the configuration of the toolbar. The item with the given\n *\t\t * name does not exist, so it was omitted when rendering the toolbar.\n *\t\t *\n *\t\t * @error toolbarview-item-unavailable\n *\t\t * @param {String} name The name of the component.\n *\t\t * /\n *\t\t logError( 'toolbarview-item-unavailable', { name } );\n *\n * **Note**: In most cases logging a warning using {@link module:utils/ckeditorerror~logWarning} is enough.\n *\n * See also {@link module:utils/ckeditorerror~CKEditorError} for an explanation when to use each method.\n *\n * @param {String} errorName The error name to be logged.\n * @param {Object} [data] Additional data to be logged.\n * @returns {String}\n */\nexport function logError( errorName, data ) {\n\tconsole.error( ...formatConsoleArguments( errorName, data ) );\n}\n\nfunction getLinkToDocumentationMessage( errorName ) {\n\treturn `\\nRead more: ${ DOCUMENTATION_URL }#error-${ errorName }`;\n}\n\nfunction formatConsoleArguments( errorName, data ) {\n\tconst documentationMessage = getLinkToDocumentationMessage( errorName );\n\n\treturn data ? [ errorName, data, documentationMessage ] : [ errorName, documentationMessage ];\n}\n","\"use strict\";\n\nvar isOldIE = function isOldIE() {\n  var memo;\n  return function memorize() {\n    if (typeof memo === 'undefined') {\n      // Test for IE <= 9 as proposed by Browserhacks\n      // @see http://browserhacks.com/#hack-e71d8692f65334173fee715c222cb805\n      // Tests for existence of standard globals is to allow style-loader\n      // to operate correctly into non-standard environments\n      // @see https://github.com/webpack-contrib/style-loader/issues/177\n      memo = Boolean(window && document && document.all && !window.atob);\n    }\n\n    return memo;\n  };\n}();\n\nvar getTarget = function getTarget() {\n  var memo = {};\n  return function memorize(target) {\n    if (typeof memo[target] === 'undefined') {\n      var styleTarget = document.querySelector(target); // Special case to return head of iframe instead of iframe itself\n\n      if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {\n        try {\n          // This will throw an exception if access to iframe is blocked\n          // due to cross-origin restrictions\n          styleTarget = styleTarget.contentDocument.head;\n        } catch (e) {\n          // istanbul ignore next\n          styleTarget = null;\n        }\n      }\n\n      memo[target] = styleTarget;\n    }\n\n    return memo[target];\n  };\n}();\n\nvar stylesInDom = [];\n\nfunction getIndexByIdentifier(identifier) {\n  var result = -1;\n\n  for (var i = 0; i < stylesInDom.length; i++) {\n    if (stylesInDom[i].identifier === identifier) {\n      result = i;\n      break;\n    }\n  }\n\n  return result;\n}\n\nfunction modulesToDom(list, options) {\n  var idCountMap = {};\n  var identifiers = [];\n\n  for (var i = 0; i < list.length; i++) {\n    var item = list[i];\n    var id = options.base ? item[0] + options.base : item[0];\n    var count = idCountMap[id] || 0;\n    var identifier = \"\".concat(id, \" \").concat(count);\n    idCountMap[id] = count + 1;\n    var index = getIndexByIdentifier(identifier);\n    var obj = {\n      css: item[1],\n      media: item[2],\n      sourceMap: item[3]\n    };\n\n    if (index !== -1) {\n      stylesInDom[index].references++;\n      stylesInDom[index].updater(obj);\n    } else {\n      stylesInDom.push({\n        identifier: identifier,\n        updater: addStyle(obj, options),\n        references: 1\n      });\n    }\n\n    identifiers.push(identifier);\n  }\n\n  return identifiers;\n}\n\nfunction insertStyleElement(options) {\n  var style = document.createElement('style');\n  var attributes = options.attributes || {};\n\n  if (typeof attributes.nonce === 'undefined') {\n    var nonce = typeof __webpack_nonce__ !== 'undefined' ? __webpack_nonce__ : null;\n\n    if (nonce) {\n      attributes.nonce = nonce;\n    }\n  }\n\n  Object.keys(attributes).forEach(function (key) {\n    style.setAttribute(key, attributes[key]);\n  });\n\n  if (typeof options.insert === 'function') {\n    options.insert(style);\n  } else {\n    var target = getTarget(options.insert || 'head');\n\n    if (!target) {\n      throw new Error(\"Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.\");\n    }\n\n    target.appendChild(style);\n  }\n\n  return style;\n}\n\nfunction removeStyleElement(style) {\n  // istanbul ignore if\n  if (style.parentNode === null) {\n    return false;\n  }\n\n  style.parentNode.removeChild(style);\n}\n/* istanbul ignore next  */\n\n\nvar replaceText = function replaceText() {\n  var textStore = [];\n  return function replace(index, replacement) {\n    textStore[index] = replacement;\n    return textStore.filter(Boolean).join('\\n');\n  };\n}();\n\nfunction applyToSingletonTag(style, index, remove, obj) {\n  var css = remove ? '' : obj.media ? \"@media \".concat(obj.media, \" {\").concat(obj.css, \"}\") : obj.css; // For old IE\n\n  /* istanbul ignore if  */\n\n  if (style.styleSheet) {\n    style.styleSheet.cssText = replaceText(index, css);\n  } else {\n    var cssNode = document.createTextNode(css);\n    var childNodes = style.childNodes;\n\n    if (childNodes[index]) {\n      style.removeChild(childNodes[index]);\n    }\n\n    if (childNodes.length) {\n      style.insertBefore(cssNode, childNodes[index]);\n    } else {\n      style.appendChild(cssNode);\n    }\n  }\n}\n\nfunction applyToTag(style, options, obj) {\n  var css = obj.css;\n  var media = obj.media;\n  var sourceMap = obj.sourceMap;\n\n  if (media) {\n    style.setAttribute('media', media);\n  } else {\n    style.removeAttribute('media');\n  }\n\n  if (sourceMap && typeof btoa !== 'undefined') {\n    css += \"\\n/*# sourceMappingURL=data:application/json;base64,\".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), \" */\");\n  } // For old IE\n\n  /* istanbul ignore if  */\n\n\n  if (style.styleSheet) {\n    style.styleSheet.cssText = css;\n  } else {\n    while (style.firstChild) {\n      style.removeChild(style.firstChild);\n    }\n\n    style.appendChild(document.createTextNode(css));\n  }\n}\n\nvar singleton = null;\nvar singletonCounter = 0;\n\nfunction addStyle(obj, options) {\n  var style;\n  var update;\n  var remove;\n\n  if (options.singleton) {\n    var styleIndex = singletonCounter++;\n    style = singleton || (singleton = insertStyleElement(options));\n    update = applyToSingletonTag.bind(null, style, styleIndex, false);\n    remove = applyToSingletonTag.bind(null, style, styleIndex, true);\n  } else {\n    style = insertStyleElement(options);\n    update = applyToTag.bind(null, style, options);\n\n    remove = function remove() {\n      removeStyleElement(style);\n    };\n  }\n\n  update(obj);\n  return function updateStyle(newObj) {\n    if (newObj) {\n      if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap) {\n        return;\n      }\n\n      update(obj = newObj);\n    } else {\n      remove();\n    }\n  };\n}\n\nmodule.exports = function (list, options) {\n  options = options || {}; // Force single-tag solution on IE6-9, which has a hard limit on the # of <style>\n  // tags it will allow on a page\n\n  if (!options.singleton && typeof options.singleton !== 'boolean') {\n    options.singleton = isOldIE();\n  }\n\n  list = list || [];\n  var lastIdentifiers = modulesToDom(list, options);\n  return function update(newList) {\n    newList = newList || [];\n\n    if (Object.prototype.toString.call(newList) !== '[object Array]') {\n      return;\n    }\n\n    for (var i = 0; i < lastIdentifiers.length; i++) {\n      var identifier = lastIdentifiers[i];\n      var index = getIndexByIdentifier(identifier);\n      stylesInDom[index].references--;\n    }\n\n    var newLastIdentifiers = modulesToDom(newList, options);\n\n    for (var _i = 0; _i < lastIdentifiers.length; _i++) {\n      var _identifier = lastIdentifiers[_i];\n\n      var _index = getIndexByIdentifier(_identifier);\n\n      if (stylesInDom[_index].references === 0) {\n        stylesInDom[_index].updater();\n\n        stylesInDom.splice(_index, 1);\n      }\n    }\n\n    lastIdentifiers = newLastIdentifiers;\n  };\n};","import freeGlobal from './_freeGlobal.js';\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\nexport default root;\n","import root from './_root.js';\nimport stubFalse from './stubFalse.js';\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Built-in value references. */\nvar Buffer = moduleExports ? root.Buffer : undefined;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined;\n\n/**\n * Checks if `value` is a buffer.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.\n * @example\n *\n * _.isBuffer(new Buffer(2));\n * // => true\n *\n * _.isBuffer(new Uint8Array(2));\n * // => false\n */\nvar isBuffer = nativeIsBuffer || stubFalse;\n\nexport default isBuffer;\n","import freeGlobal from './_freeGlobal.js';\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Detect free variable `process` from Node.js. */\nvar freeProcess = moduleExports && freeGlobal.process;\n\n/** Used to access faster Node.js helpers. */\nvar nodeUtil = (function() {\n  try {\n    // Use `util.types` for Node.js 10+.\n    var types = freeModule && freeModule.require && freeModule.require('util').types;\n\n    if (types) {\n      return types;\n    }\n\n    // Legacy `process.binding('util')` for Node.js < 10.\n    return freeProcess && freeProcess.binding && freeProcess.binding('util');\n  } catch (e) {}\n}());\n\nexport default nodeUtil;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/version\n */\n\n/* globals window, global */\n\nimport CKEditorError from './ckeditorerror';\n\nconst version = '24.0.0';\n\n/* istanbul ignore next */\nconst windowOrGlobal = typeof window === 'object' ? window : global;\n\n/* istanbul ignore next */\nif ( windowOrGlobal.CKEDITOR_VERSION ) {\n\t/**\n\t * This error is thrown when due to a mistake in how CKEditor 5 was installed or initialized, some\n\t * of its modules were duplicated (evaluated and executed twice). Module duplication leads to inevitable runtime\n\t * errors.\n\t *\n\t * There are many situations in which some modules can be loaded twice. In the worst case scenario,\n\t * you may need to check your project for each of these issues and fix them all.\n\t *\n\t * # Trying to add a plugin to an existing build\n\t *\n\t * If you import an existing CKEditor 5 build and a plugin like this:\n\t *\n\t *\t\timport ClassicEditor from '@ckeditor/ckeditor5-build-classic';\n\t *\t\timport Highlight from '@ckeditor/ckeditor5-highlight/src/highlight';\n\t *\n\t * Then your project loads some CKEditor 5 packages twice. How does it happen?\n\t *\n\t * The build package contains a file which is already compiled with webpack. This means\n\t * that it contains all the necessary code from e.g. `@ckeditor/ckeditor5-engine` and `@ckeditor/ckeditor5-utils`.\n\t *\n\t * However, the `Highlight` plugin imports some of the modules from these packages, too. If you ask webpack to\n\t * build such a project, you will end up with the modules being included (and run) twice &mdash; first, because they are\n\t * included inside the build package, and second, because they are required by the `Highlight` plugin.\n\t *\n\t * Therefore, **you must never add plugins to an existing build** unless your plugin has no dependencies.\n\t *\n\t * Adding plugins to a build is done by taking the source version of this build (so, before it was built with webpack)\n\t * and adding plugins there. In this situation, webpack will know that it only needs to load each plugin once.\n\t *\n\t * Read more in the {@glink builds/guides/integration/installing-plugins \"Installing plugins\"} guide.\n\t *\n\t * # Confused an editor build with an editor implementation\n\t *\n\t * This scenario is very similar to the previous one, but has a different origin.\n\t *\n\t * Let's assume that you wanted to use CKEditor 5 from source, as explained in the\n\t * {@glink builds/guides/integration/advanced-setup#scenario-2-building-from-source \"Building from source\"} section\n\t * or in the {@glink framework/guides/quick-start \"Quick start\"} guide of CKEditor 5 Framework.\n\t *\n\t * The correct way to do so is to import an editor and plugins and run them together like this:\n\t *\n\t *\t\timport ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';\n\t *\t\timport Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';\n\t *\t\timport Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';\n\t *\t\timport Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';\n\t *\t\timport Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';\n\t *\n\t *\t\tClassicEditor\n\t *\t\t\t.create( document.querySelector( '#editor' ), {\n\t *\t\t\t\tplugins: [ Essentials, Paragraph, Bold, Italic ],\n\t *\t\t\t\ttoolbar: [ 'bold', 'italic' ]\n\t *\t\t\t} )\n\t *\t\t\t.then( editor => {\n\t *\t\t\t\tconsole.log( 'Editor was initialized', editor );\n\t *\t\t\t} )\n\t *\t\t\t.catch( error => {\n\t *\t\t\t\tconsole.error( error.stack );\n\t *\t\t\t} );\n\t *\n\t * However, you might have mistakenly imported a build instead of the source `ClassicEditor`. In this case\n\t * your imports will look like this:\n\t *\n\t *\t\timport ClassicEditor from '@ckeditor/ckeditor5-build-classic';\n\t *\t\timport Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';\n\t *\t\timport Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';\n\t *\t\timport Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';\n\t *\t\timport Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';\n\t *\n\t * This creates the same situation as in the previous section because you use a build together with source plugins.\n\t *\n\t * Remember: `@ckeditor/ckeditor5-build-*` packages contain editor builds and `@ckeditor/ckeditor5-editor-*` contain source editors.\n\t *\n\t * # Loading two or more builds on one page\n\t *\n\t * If you use CKEditor 5 builds, you might have loaded two (or more) `ckeditor.js` files on one web page.\n\t * Check your web page for duplicated `<script>` elements or make sure your page builder/bundler includes CKEditor only once.\n\t *\n\t * If you want to use two different types of editors at once, see the\n\t * {@glink builds/guides/integration/advanced-setup#scenario-3-using-two-different-editors \"Using two different editors\"}\n\t * section.\n\t *\n\t * # Using outdated packages\n\t *\n\t * Building CKEditor 5 from source requires using multiple npm packages. These packages have their dependencies\n\t * to other packages. If you use the latest version of, for example, `@ckeditor/ckeditor5-editor-classic` with\n\t * an outdated version of `@ckeditor/ckeditor5-image`, npm or yarn will need to install two different versions of\n\t * `@ckeditor/ckeditor5-core` because `@ckeditor/ckeditor5-editor-classic` and `@ckeditor/ckeditor5-image` may require\n\t * different versions of the core package.\n\t *\n\t * The solution to this issue is to update all packages to their latest version. We recommend\n\t * using tools like [`npm-check-updates`](https://www.npmjs.com/package/npm-check-updates) which simplify this process.\n\t *\n\t * # Conflicting version of dependencies\n\t *\n\t * This is a special case of the previous scenario. If you use CKEditor 5 with some third-party plugins,\n\t * it may happen that even if you use the latest versions of the official packages and the latest version of\n\t * these third-party packages, there will be a conflict between some of their dependencies.\n\t *\n\t * Such a problem can be resolved by either downgrading CKEditor 5 packages (which we do not recommend) or\n\t * asking the author of the third-party package to upgrade its depdendencies (or forking their project and doing this yourself).\n\t *\n\t * **Note:** All official CKEditor 5 packages (excluding integrations and `ckeditor5-dev-*` packages) are released in the\n\t * same major version. This is &mdash; in the `x.y.z`, the `x` is the same for all packages. This is the simplest way to check\n\t * whether you use packages coming from the same CKEditor 5 version. You can read more about versioning in the\n\t * {@glink framework/guides/support/versioning-policy Versioning policy} guide.\n\t *\n\t * # Packages were duplicated in `node_modules`\n\t *\n\t * In some situations, especially when calling `npm install` multiple times, it may happen\n\t * that npm will not correctly \"deduplicate\" packages.\n\t *\n\t * Normally, npm deduplicates all packages so, for example, `@ckeditor/ckeditor5-core` is installed only once in `node_modules/`.\n\t * However, it is known to fail to do so from time to time.\n\t *\n\t * We recommend checking if any of the steps listed below help:\n\t *\n\t * * `rm -rf node_modules && npm install` to make sure you have a clean `node_modules/` directory. This step\n\t * is known to help in most cases.\n\t * * If you use `yarn.lock` or `package-lock.json`, remove it before `npm install`.\n\t * * Check whether all CKEditor 5 packages are up to date and reinstall them\n\t * if you changed anything (`rm -rf node_modules && npm install`).\n\t *\n\t * If all packages are correct and compatible with each other, the steps above are known to help. If not, you may\n\t * try to check with `npm ls` how many times packages like `@ckeditor/ckeditor5-core`, `@ckeditor/ckeditor5-engine` and\n\t *`@ckeditor/ckeditor5-utils` are installed. If more than once, verify which package causes that.\n\t *\n\t * @error ckeditor-duplicated-modules\n\t */\n\tthrow new CKEditorError(\n\t\t'ckeditor-duplicated-modules',\n\t\tnull\n\t);\n} else {\n\twindowOrGlobal.CKEDITOR_VERSION = version;\n}\n","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./responsiveform.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\nexport default freeGlobal;\n","import root from './_root.js';\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Built-in value references. */\nvar Buffer = moduleExports ? root.Buffer : undefined,\n    allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined;\n\n/**\n * Creates a clone of  `buffer`.\n *\n * @private\n * @param {Buffer} buffer The buffer to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Buffer} Returns the cloned buffer.\n */\nfunction cloneBuffer(buffer, isDeep) {\n  if (isDeep) {\n    return buffer.slice();\n  }\n  var length = buffer.length,\n      result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length);\n\n  buffer.copy(result);\n  return result;\n}\n\nexport default cloneBuffer;\n","module.exports = function(originalModule) {\n\tif (!originalModule.webpackPolyfill) {\n\t\tvar module = Object.create(originalModule);\n\t\t// module.parent = undefined by default\n\t\tif (!module.children) module.children = [];\n\t\tObject.defineProperty(module, \"loaded\", {\n\t\t\tenumerable: true,\n\t\t\tget: function() {\n\t\t\t\treturn module.l;\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(module, \"id\", {\n\t\t\tenumerable: true,\n\t\t\tget: function() {\n\t\t\t\treturn module.i;\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(module, \"exports\", {\n\t\t\tenumerable: true\n\t\t});\n\t\tmodule.webpackPolyfill = 1;\n\t}\n\treturn module;\n};\n","var g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || new Function(\"return this\")();\n} catch (e) {\n\t// This works if the window reference is available\n\tif (typeof window === \"object\") g = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it's\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./heading.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n  return false;\n}\n\nexport default stubFalse;\n","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./placeholder.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-placeholder:before,.ck .ck-placeholder:before{content:attr(data-placeholder);pointer-events:none}.ck.ck-read-only .ck-placeholder:before{display:none}.ck.ck-placeholder:before,.ck .ck-placeholder:before{cursor:text;color:var(--ck-color-engine-placeholder-text)}\"","var api = require(\"!../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./globals.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck-hidden{display:none!important}.ck.ck-reset,.ck.ck-reset_all,.ck.ck-reset_all *{box-sizing:border-box;width:auto;height:auto;position:static}:root{--ck-z-default:1;--ck-z-modal:calc(var(--ck-z-default) + 999)}.ck-transitions-disabled,.ck-transitions-disabled *{transition:none!important}:root{--ck-color-base-foreground:#fafafa;--ck-color-base-background:#fff;--ck-color-base-border:#c4c4c4;--ck-color-base-action:#61b045;--ck-color-base-focus:#6cb5f9;--ck-color-base-text:#333;--ck-color-base-active:#198cf0;--ck-color-base-active-focus:#0e7fe1;--ck-color-base-error:#db3700;--ck-color-focus-border-coordinates:208,79%,51%;--ck-color-focus-border:hsl(var(--ck-color-focus-border-coordinates));--ck-color-focus-outer-shadow:#bcdefb;--ck-color-focus-disabled-shadow:rgba(119,186,248,0.3);--ck-color-focus-error-shadow:rgba(255,64,31,0.3);--ck-color-text:var(--ck-color-base-text);--ck-color-shadow-drop:rgba(0,0,0,0.15);--ck-color-shadow-drop-active:rgba(0,0,0,0.2);--ck-color-shadow-inner:rgba(0,0,0,0.1);--ck-color-button-default-background:transparent;--ck-color-button-default-hover-background:#e6e6e6;--ck-color-button-default-active-background:#d9d9d9;--ck-color-button-default-active-shadow:#bfbfbf;--ck-color-button-default-disabled-background:transparent;--ck-color-button-on-background:#dedede;--ck-color-button-on-hover-background:#c4c4c4;--ck-color-button-on-active-background:#bababa;--ck-color-button-on-active-shadow:#a1a1a1;--ck-color-button-on-disabled-background:#dedede;--ck-color-button-action-background:var(--ck-color-base-action);--ck-color-button-action-hover-background:#579e3d;--ck-color-button-action-active-background:#53973b;--ck-color-button-action-active-shadow:#498433;--ck-color-button-action-disabled-background:#7ec365;--ck-color-button-action-text:var(--ck-color-base-background);--ck-color-button-save:#008a00;--ck-color-button-cancel:#db3700;--ck-color-switch-button-off-background:#b0b0b0;--ck-color-switch-button-off-hover-background:#a3a3a3;--ck-color-switch-button-on-background:var(--ck-color-button-action-background);--ck-color-switch-button-on-hover-background:#579e3d;--ck-color-switch-button-inner-background:var(--ck-color-base-background);--ck-color-switch-button-inner-shadow:rgba(0,0,0,0.1);--ck-color-dropdown-panel-background:var(--ck-color-base-background);--ck-color-dropdown-panel-border:var(--ck-color-base-border);--ck-color-input-background:var(--ck-color-base-background);--ck-color-input-border:#c7c7c7;--ck-color-input-error-border:var(--ck-color-base-error);--ck-color-input-text:var(--ck-color-base-text);--ck-color-input-disabled-background:#f2f2f2;--ck-color-input-disabled-border:#c7c7c7;--ck-color-input-disabled-text:#757575;--ck-color-list-background:var(--ck-color-base-background);--ck-color-list-button-hover-background:var(--ck-color-button-default-hover-background);--ck-color-list-button-on-background:var(--ck-color-base-active);--ck-color-list-button-on-background-focus:var(--ck-color-base-active-focus);--ck-color-list-button-on-text:var(--ck-color-base-background);--ck-color-panel-background:var(--ck-color-base-background);--ck-color-panel-border:var(--ck-color-base-border);--ck-color-toolbar-background:var(--ck-color-base-foreground);--ck-color-toolbar-border:var(--ck-color-base-border);--ck-color-tooltip-background:var(--ck-color-base-text);--ck-color-tooltip-text:var(--ck-color-base-background);--ck-color-engine-placeholder-text:#707070;--ck-color-upload-bar-background:#6cb5f9;--ck-color-link-default:#0000f0;--ck-color-link-selected-background:rgba(31,177,255,0.1);--ck-color-link-fake-selection:rgba(31,177,255,0.3);--ck-disabled-opacity:.5;--ck-focus-outer-shadow-geometry:0 0 0 3px;--ck-focus-outer-shadow:var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-outer-shadow);--ck-focus-disabled-outer-shadow:var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-disabled-shadow);--ck-focus-error-outer-shadow:var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-error-shadow);--ck-focus-ring:1px solid var(--ck-color-focus-border);--ck-font-size-base:13px;--ck-line-height-base:1.84615;--ck-font-face:Helvetica,Arial,Tahoma,Verdana,Sans-Serif;--ck-font-size-tiny:0.7em;--ck-font-size-small:0.75em;--ck-font-size-normal:1em;--ck-font-size-big:1.4em;--ck-font-size-large:1.8em;--ck-ui-component-min-height:2.3em}.ck.ck-reset,.ck.ck-reset_all,.ck.ck-reset_all *{margin:0;padding:0;border:0;background:transparent;text-decoration:none;vertical-align:middle;transition:none;word-wrap:break-word}.ck.ck-reset_all,.ck.ck-reset_all *{border-collapse:collapse;font:normal normal normal var(--ck-font-size-base)/var(--ck-line-height-base) var(--ck-font-face);color:var(--ck-color-text);text-align:left;white-space:nowrap;cursor:auto;float:none}.ck.ck-reset_all .ck-rtl *{text-align:right}.ck.ck-reset_all iframe{vertical-align:inherit}.ck.ck-reset_all textarea{white-space:pre-wrap}.ck.ck-reset_all input[type=password],.ck.ck-reset_all input[type=text],.ck.ck-reset_all textarea{cursor:text}.ck.ck-reset_all input[type=password][disabled],.ck.ck-reset_all input[type=text][disabled],.ck.ck-reset_all textarea[disabled]{cursor:default}.ck.ck-reset_all fieldset{padding:10px;border:2px groove #dfdee3}.ck.ck-reset_all button::-moz-focus-inner{padding:0;border:0}.ck[dir=rtl],.ck[dir=rtl] .ck{text-align:right}:root{--ck-border-radius:2px;--ck-inner-shadow:2px 2px 3px var(--ck-color-shadow-inner) inset;--ck-drop-shadow:0 1px 2px 1px var(--ck-color-shadow-drop);--ck-drop-shadow-active:0 3px 6px 1px var(--ck-color-shadow-drop-active);--ck-spacing-unit:0.6em;--ck-spacing-large:calc(var(--ck-spacing-unit)*1.5);--ck-spacing-standard:var(--ck-spacing-unit);--ck-spacing-medium:calc(var(--ck-spacing-unit)*0.8);--ck-spacing-small:calc(var(--ck-spacing-unit)*0.5);--ck-spacing-tiny:calc(var(--ck-spacing-unit)*0.3);--ck-spacing-extra-tiny:calc(var(--ck-spacing-unit)*0.16)}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./editorui.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \":root{--ck-color-editable-blur-selection:#d9d9d9}.ck.ck-editor__editable:not(.ck-editor__nested-editable){border-radius:0}.ck-rounded-corners .ck.ck-editor__editable:not(.ck-editor__nested-editable),.ck.ck-editor__editable:not(.ck-editor__nested-editable).ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-editor__editable:not(.ck-editor__nested-editable).ck-focused{outline:none;border:var(--ck-focus-ring);box-shadow:var(--ck-inner-shadow),0 0}.ck.ck-editor__editable_inline{overflow:auto;padding:0 var(--ck-spacing-standard);border:1px solid transparent}.ck.ck-editor__editable_inline[dir=ltr]{text-align:left}.ck.ck-editor__editable_inline[dir=rtl]{text-align:right}.ck.ck-editor__editable_inline>:first-child{margin-top:var(--ck-spacing-large)}.ck.ck-editor__editable_inline>:last-child{margin-bottom:var(--ck-spacing-large)}.ck.ck-editor__editable_inline.ck-blurred ::selection{background:var(--ck-color-editable-blur-selection)}.ck.ck-balloon-panel.ck-toolbar-container[class*=arrow_n]:after{border-bottom-color:var(--ck-color-base-foreground)}.ck.ck-balloon-panel.ck-toolbar-container[class*=arrow_s]:after{border-top-color:var(--ck-color-base-foreground)}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./label.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-label{display:block}.ck.ck-voice-label{display:none}.ck.ck-label{font-weight:700}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./stickypanel.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-sticky-panel .ck-sticky-panel__content_sticky{z-index:var(--ck-z-modal);position:fixed;top:0}.ck.ck-sticky-panel .ck-sticky-panel__content_sticky_bottom-limit{top:auto;position:absolute}.ck.ck-sticky-panel .ck-sticky-panel__content_sticky{box-shadow:var(--ck-drop-shadow),0 0;border-width:0 1px 1px;border-top-left-radius:0;border-top-right-radius:0}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./dropdown.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-dropdown{display:inline-block;position:relative}.ck.ck-dropdown .ck-dropdown__arrow{pointer-events:none;z-index:var(--ck-z-default)}.ck.ck-dropdown .ck-button.ck-dropdown__button{width:100%}.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-on .ck-tooltip{display:none}.ck.ck-dropdown .ck-dropdown__panel{-webkit-backface-visibility:hidden;display:none;z-index:var(--ck-z-modal);position:absolute}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel-visible{display:inline-block}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_ne,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_nw{bottom:100%}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_se,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sw{top:100%;bottom:auto}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_ne,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_se{left:0}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_nw,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sw{right:0}.ck.ck-toolbar .ck-dropdown__panel{z-index:calc(var(--ck-z-modal) + 1)}:root{--ck-dropdown-arrow-size:calc(var(--ck-icon-size)*0.5)}.ck.ck-dropdown{font-size:inherit}.ck.ck-dropdown .ck-dropdown__arrow{width:var(--ck-dropdown-arrow-size)}[dir=ltr] .ck.ck-dropdown .ck-dropdown__arrow{right:var(--ck-spacing-standard);margin-left:var(--ck-spacing-standard)}[dir=rtl] .ck.ck-dropdown .ck-dropdown__arrow{left:var(--ck-spacing-standard);margin-right:var(--ck-spacing-small)}.ck.ck-dropdown.ck-disabled .ck-dropdown__arrow{opacity:var(--ck-disabled-opacity)}[dir=ltr] .ck.ck-dropdown .ck-button.ck-dropdown__button:not(.ck-button_with-text){padding-left:var(--ck-spacing-small)}[dir=rtl] .ck.ck-dropdown .ck-button.ck-dropdown__button:not(.ck-button_with-text){padding-right:var(--ck-spacing-small)}.ck.ck-dropdown .ck-button.ck-dropdown__button .ck-button__label{width:7em;overflow:hidden;text-overflow:ellipsis}.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-disabled .ck-button__label{opacity:var(--ck-disabled-opacity)}.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-on{border-bottom-left-radius:0;border-bottom-right-radius:0}.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-dropdown__button_label-width_auto .ck-button__label{width:auto}.ck.ck-dropdown__panel{border-radius:0}.ck-rounded-corners .ck.ck-dropdown__panel,.ck.ck-dropdown__panel.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-dropdown__panel{box-shadow:var(--ck-drop-shadow),0 0;background:var(--ck-color-dropdown-panel-background);border:1px solid var(--ck-color-dropdown-panel-border);bottom:0;min-width:100%}.ck.ck-dropdown__panel.ck-dropdown__panel_se{border-top-left-radius:0}.ck.ck-dropdown__panel.ck-dropdown__panel_sw{border-top-right-radius:0}.ck.ck-dropdown__panel.ck-dropdown__panel_ne{border-bottom-left-radius:0}.ck.ck-dropdown__panel.ck-dropdown__panel_nw{border-bottom-right-radius:0}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./icon.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-icon{vertical-align:middle}:root{--ck-icon-size:calc(var(--ck-line-height-base)*var(--ck-font-size-normal))}.ck.ck-icon{width:var(--ck-icon-size);height:var(--ck-icon-size);font-size:.8333350694em;will-change:transform}.ck.ck-icon,.ck.ck-icon *{color:inherit;cursor:inherit}.ck.ck-icon :not([fill]){fill:currentColor}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./tooltip.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-tooltip,.ck.ck-tooltip .ck-tooltip__text:after{position:absolute;pointer-events:none;-webkit-backface-visibility:hidden}.ck.ck-tooltip{visibility:hidden;opacity:0;display:none;z-index:var(--ck-z-modal)}.ck.ck-tooltip .ck-tooltip__text{display:inline-block}.ck.ck-tooltip .ck-tooltip__text:after{content:\\\"\\\";width:0;height:0}:root{--ck-tooltip-arrow-size:5px}.ck.ck-tooltip{left:50%;top:0;transition:opacity .2s ease-in-out .2s}.ck.ck-tooltip .ck-tooltip__text{border-radius:0}.ck-rounded-corners .ck.ck-tooltip .ck-tooltip__text,.ck.ck-tooltip .ck-tooltip__text.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-tooltip .ck-tooltip__text{font-size:.9em;line-height:1.5;color:var(--ck-color-tooltip-text);padding:var(--ck-spacing-small) var(--ck-spacing-medium);background:var(--ck-color-tooltip-background);position:relative;left:-50%}.ck.ck-tooltip .ck-tooltip__text:after{transition:opacity .2s ease-in-out .2s;border-style:solid;left:50%}.ck.ck-tooltip.ck-tooltip_s,.ck.ck-tooltip.ck-tooltip_se,.ck.ck-tooltip.ck-tooltip_sw{bottom:calc(var(--ck-tooltip-arrow-size)*-1);transform:translateY(100%)}.ck.ck-tooltip.ck-tooltip_s .ck-tooltip__text:after,.ck.ck-tooltip.ck-tooltip_se .ck-tooltip__text:after,.ck.ck-tooltip.ck-tooltip_sw .ck-tooltip__text:after{top:calc(var(--ck-tooltip-arrow-size)*-1 + 1px);transform:translateX(-50%);border-left-color:transparent;border-bottom-color:var(--ck-color-tooltip-background);border-right-color:transparent;border-top-color:transparent;border-left-width:var(--ck-tooltip-arrow-size);border-bottom-width:var(--ck-tooltip-arrow-size);border-right-width:var(--ck-tooltip-arrow-size);border-top-width:0}.ck.ck-tooltip.ck-tooltip_sw{right:50%;left:auto}.ck.ck-tooltip.ck-tooltip_sw .ck-tooltip__text{left:auto;right:calc(var(--ck-tooltip-arrow-size)*-2)}.ck.ck-tooltip.ck-tooltip_sw .ck-tooltip__text:after{left:auto;right:0}.ck.ck-tooltip.ck-tooltip_se{left:50%;right:auto}.ck.ck-tooltip.ck-tooltip_se .ck-tooltip__text{right:auto;left:calc(var(--ck-tooltip-arrow-size)*-2)}.ck.ck-tooltip.ck-tooltip_se .ck-tooltip__text:after{right:auto;left:0;transform:translateX(50%)}.ck.ck-tooltip.ck-tooltip_n{top:calc(var(--ck-tooltip-arrow-size)*-1);transform:translateY(-100%)}.ck.ck-tooltip.ck-tooltip_n .ck-tooltip__text:after{bottom:calc(var(--ck-tooltip-arrow-size)*-1);transform:translateX(-50%);border-left-color:transparent;border-bottom-color:transparent;border-right-color:transparent;border-top-color:var(--ck-color-tooltip-background);border-left-width:var(--ck-tooltip-arrow-size);border-bottom-width:0;border-right-width:var(--ck-tooltip-arrow-size);border-top-width:var(--ck-tooltip-arrow-size)}.ck.ck-tooltip.ck-tooltip_e{left:calc(100% + var(--ck-tooltip-arrow-size));top:50%}.ck.ck-tooltip.ck-tooltip_e .ck-tooltip__text{left:0;transform:translateY(-50%)}.ck.ck-tooltip.ck-tooltip_e .ck-tooltip__text:after{left:calc(var(--ck-tooltip-arrow-size)*-1);top:calc(50% - var(--ck-tooltip-arrow-size)*1);border-left-color:transparent;border-bottom-color:transparent;border-right-color:var(--ck-color-tooltip-background);border-top-color:transparent;border-left-width:0;border-bottom-width:var(--ck-tooltip-arrow-size);border-right-width:var(--ck-tooltip-arrow-size);border-top-width:var(--ck-tooltip-arrow-size)}.ck.ck-tooltip.ck-tooltip_w{right:calc(100% + var(--ck-tooltip-arrow-size));left:auto;top:50%}.ck.ck-tooltip.ck-tooltip_w .ck-tooltip__text{left:0;transform:translateY(-50%)}.ck.ck-tooltip.ck-tooltip_w .ck-tooltip__text:after{left:100%;top:calc(50% - var(--ck-tooltip-arrow-size)*1);border-left-color:var(--ck-color-tooltip-background);border-bottom-color:transparent;border-right-color:transparent;border-top-color:transparent;border-left-width:var(--ck-tooltip-arrow-size);border-bottom-width:var(--ck-tooltip-arrow-size);border-right-width:0;border-top-width:var(--ck-tooltip-arrow-size)}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./button.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-button,a.ck.ck-button{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.ck.ck-button .ck-tooltip,a.ck.ck-button .ck-tooltip{display:block}@media (hover:none){.ck.ck-button .ck-tooltip,a.ck.ck-button .ck-tooltip{display:none}}.ck.ck-button,a.ck.ck-button{position:relative;display:inline-flex;align-items:center;justify-content:left}.ck.ck-button .ck-button__label,a.ck.ck-button .ck-button__label{display:none}.ck.ck-button.ck-button_with-text .ck-button__label,a.ck.ck-button.ck-button_with-text .ck-button__label{display:inline-block}.ck.ck-button:not(.ck-button_with-text),a.ck.ck-button:not(.ck-button_with-text){justify-content:center}.ck.ck-button:hover .ck-tooltip,a.ck.ck-button:hover .ck-tooltip{visibility:visible;opacity:1}.ck.ck-button:focus:not(:hover) .ck-tooltip,a.ck.ck-button:focus:not(:hover) .ck-tooltip{display:none}.ck.ck-button,a.ck.ck-button{background:var(--ck-color-button-default-background)}.ck.ck-button:not(.ck-disabled):hover,a.ck.ck-button:not(.ck-disabled):hover{background:var(--ck-color-button-default-hover-background)}.ck.ck-button:not(.ck-disabled):active,a.ck.ck-button:not(.ck-disabled):active{background:var(--ck-color-button-default-active-background);box-shadow:inset 0 2px 2px var(--ck-color-button-default-active-shadow)}.ck.ck-button.ck-disabled,a.ck.ck-button.ck-disabled{background:var(--ck-color-button-default-disabled-background)}.ck.ck-button,a.ck.ck-button{border-radius:0}.ck-rounded-corners .ck.ck-button,.ck-rounded-corners a.ck.ck-button,.ck.ck-button.ck-rounded-corners,a.ck.ck-button.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-button,a.ck.ck-button{white-space:nowrap;cursor:default;vertical-align:middle;padding:var(--ck-spacing-tiny);text-align:center;min-width:var(--ck-ui-component-min-height);min-height:var(--ck-ui-component-min-height);line-height:1;font-size:inherit;border:1px solid transparent;transition:box-shadow .2s ease-in-out,border .2s ease-in-out;-webkit-appearance:none}.ck.ck-button:active,.ck.ck-button:focus,a.ck.ck-button:active,a.ck.ck-button:focus{outline:none;border:var(--ck-focus-ring);box-shadow:var(--ck-focus-outer-shadow),0 0}.ck.ck-button .ck-button__icon use,.ck.ck-button .ck-button__icon use *,a.ck.ck-button .ck-button__icon use,a.ck.ck-button .ck-button__icon use *{color:inherit}.ck.ck-button .ck-button__label,a.ck.ck-button .ck-button__label{font-size:inherit;font-weight:inherit;color:inherit;cursor:inherit;vertical-align:middle}[dir=ltr] .ck.ck-button .ck-button__label,[dir=ltr] a.ck.ck-button .ck-button__label{text-align:left}[dir=rtl] .ck.ck-button .ck-button__label,[dir=rtl] a.ck.ck-button .ck-button__label{text-align:right}.ck.ck-button .ck-button__keystroke,a.ck.ck-button .ck-button__keystroke{color:inherit}[dir=ltr] .ck.ck-button .ck-button__keystroke,[dir=ltr] a.ck.ck-button .ck-button__keystroke{margin-left:var(--ck-spacing-large)}[dir=rtl] .ck.ck-button .ck-button__keystroke,[dir=rtl] a.ck.ck-button .ck-button__keystroke{margin-right:var(--ck-spacing-large)}.ck.ck-button .ck-button__keystroke,a.ck.ck-button .ck-button__keystroke{font-weight:700;opacity:.7}.ck.ck-button.ck-disabled:active,.ck.ck-button.ck-disabled:focus,a.ck.ck-button.ck-disabled:active,a.ck.ck-button.ck-disabled:focus{box-shadow:var(--ck-focus-disabled-outer-shadow),0 0}.ck.ck-button.ck-disabled .ck-button__icon,a.ck.ck-button.ck-disabled .ck-button__icon{opacity:var(--ck-disabled-opacity)}.ck.ck-button.ck-disabled .ck-button__label,a.ck.ck-button.ck-disabled .ck-button__label{opacity:var(--ck-disabled-opacity)}.ck.ck-button.ck-disabled .ck-button__keystroke,a.ck.ck-button.ck-disabled .ck-button__keystroke{opacity:.3}.ck.ck-button.ck-button_with-text,a.ck.ck-button.ck-button_with-text{padding:var(--ck-spacing-tiny) var(--ck-spacing-standard)}[dir=ltr] .ck.ck-button.ck-button_with-text .ck-button__icon,[dir=ltr] a.ck.ck-button.ck-button_with-text .ck-button__icon{margin-left:calc(var(--ck-spacing-small)*-1);margin-right:var(--ck-spacing-small)}[dir=rtl] .ck.ck-button.ck-button_with-text .ck-button__icon,[dir=rtl] a.ck.ck-button.ck-button_with-text .ck-button__icon{margin-right:calc(var(--ck-spacing-small)*-1);margin-left:var(--ck-spacing-small)}.ck.ck-button.ck-button_with-keystroke .ck-button__label,a.ck.ck-button.ck-button_with-keystroke .ck-button__label{flex-grow:1}.ck.ck-button.ck-on,a.ck.ck-button.ck-on{background:var(--ck-color-button-on-background)}.ck.ck-button.ck-on:not(.ck-disabled):hover,a.ck.ck-button.ck-on:not(.ck-disabled):hover{background:var(--ck-color-button-on-hover-background)}.ck.ck-button.ck-on:not(.ck-disabled):active,a.ck.ck-button.ck-on:not(.ck-disabled):active{background:var(--ck-color-button-on-active-background);box-shadow:inset 0 2px 2px var(--ck-color-button-on-active-shadow)}.ck.ck-button.ck-on.ck-disabled,a.ck.ck-button.ck-on.ck-disabled{background:var(--ck-color-button-on-disabled-background)}.ck.ck-button.ck-button-save,a.ck.ck-button.ck-button-save{color:var(--ck-color-button-save)}.ck.ck-button.ck-button-cancel,a.ck.ck-button.ck-button-cancel{color:var(--ck-color-button-cancel)}.ck.ck-button-action,a.ck.ck-button-action{background:var(--ck-color-button-action-background)}.ck.ck-button-action:not(.ck-disabled):hover,a.ck.ck-button-action:not(.ck-disabled):hover{background:var(--ck-color-button-action-hover-background)}.ck.ck-button-action:not(.ck-disabled):active,a.ck.ck-button-action:not(.ck-disabled):active{background:var(--ck-color-button-action-active-background);box-shadow:inset 0 2px 2px var(--ck-color-button-action-active-shadow)}.ck.ck-button-action.ck-disabled,a.ck.ck-button-action.ck-disabled{background:var(--ck-color-button-action-disabled-background)}.ck.ck-button-action,a.ck.ck-button-action{color:var(--ck-color-button-action-text)}.ck.ck-button-bold,a.ck.ck-button-bold{font-weight:700}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./list.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-list{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;display:flex;flex-direction:column}.ck.ck-list .ck-list__item,.ck.ck-list .ck-list__separator{display:block}.ck.ck-list .ck-list__item>:focus{position:relative;z-index:var(--ck-z-default)}.ck.ck-list{border-radius:0}.ck-rounded-corners .ck.ck-list,.ck.ck-list.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-list{list-style-type:none;background:var(--ck-color-list-background)}.ck.ck-list__item{cursor:default;min-width:12em}.ck.ck-list__item .ck-button{min-height:unset;width:100%;text-align:left;border-radius:0;padding:calc(var(--ck-line-height-base)*0.2*var(--ck-font-size-base)) calc(var(--ck-line-height-base)*0.4*var(--ck-font-size-base))}.ck.ck-list__item .ck-button .ck-button__label{line-height:calc(var(--ck-line-height-base)*1.2*var(--ck-font-size-base))}.ck.ck-list__item .ck-button:active{box-shadow:none}.ck.ck-list__item .ck-button.ck-on{background:var(--ck-color-list-button-on-background);color:var(--ck-color-list-button-on-text)}.ck.ck-list__item .ck-button.ck-on:active{box-shadow:none}.ck.ck-list__item .ck-button.ck-on:hover:not(.ck-disabled){background:var(--ck-color-list-button-on-background-focus)}.ck.ck-list__item .ck-button.ck-on:focus:not(.ck-disabled){border-color:var(--ck-color-base-background)}.ck.ck-list__item .ck-button:hover:not(.ck-disabled){background:var(--ck-color-list-button-hover-background)}.ck.ck-list__item .ck-switchbutton.ck-on{background:var(--ck-color-list-background);color:inherit}.ck.ck-list__item .ck-switchbutton.ck-on:hover:not(.ck-disabled){background:var(--ck-color-list-button-hover-background);color:inherit}.ck.ck-list__separator{height:1px;width:100%;background:var(--ck-color-base-border)}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./switchbutton.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-button.ck-switchbutton .ck-button__toggle,.ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner{display:block}:root{--ck-switch-button-toggle-width:2.6153846154em;--ck-switch-button-toggle-inner-size:1.0769230769em;--ck-switch-button-toggle-spacing:1px;--ck-switch-button-translation:calc(var(--ck-switch-button-toggle-width) - var(--ck-switch-button-toggle-inner-size) - var(--ck-switch-button-toggle-spacing)*2)}[dir=ltr] .ck.ck-button.ck-switchbutton .ck-button__label{margin-right:calc(var(--ck-spacing-large)*2)}[dir=rtl] .ck.ck-button.ck-switchbutton .ck-button__label{margin-left:calc(var(--ck-spacing-large)*2)}.ck.ck-button.ck-switchbutton .ck-button__toggle{border-radius:0}.ck-rounded-corners .ck.ck-button.ck-switchbutton .ck-button__toggle,.ck.ck-button.ck-switchbutton .ck-button__toggle.ck-rounded-corners{border-radius:var(--ck-border-radius)}[dir=ltr] .ck.ck-button.ck-switchbutton .ck-button__toggle{margin-left:auto}[dir=rtl] .ck.ck-button.ck-switchbutton .ck-button__toggle{margin-right:auto}.ck.ck-button.ck-switchbutton .ck-button__toggle{transition:background .4s ease;width:var(--ck-switch-button-toggle-width);background:var(--ck-color-switch-button-off-background)}.ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner{border-radius:0}.ck-rounded-corners .ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner,.ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner.ck-rounded-corners{border-radius:var(--ck-border-radius);border-radius:calc(var(--ck-border-radius)*0.5)}.ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner{margin:var(--ck-switch-button-toggle-spacing);width:var(--ck-switch-button-toggle-inner-size);height:var(--ck-switch-button-toggle-inner-size);background:var(--ck-color-switch-button-inner-background);transition:all .3s ease}.ck.ck-button.ck-switchbutton .ck-button__toggle:hover{background:var(--ck-color-switch-button-off-hover-background)}.ck.ck-button.ck-switchbutton .ck-button__toggle:hover .ck-button__toggle__inner{box-shadow:0 0 0 5px var(--ck-color-switch-button-inner-shadow)}.ck.ck-button.ck-switchbutton.ck-disabled .ck-button__toggle{opacity:var(--ck-disabled-opacity)}.ck.ck-button.ck-switchbutton.ck-on .ck-button__toggle{background:var(--ck-color-switch-button-on-background)}.ck.ck-button.ck-switchbutton.ck-on .ck-button__toggle:hover{background:var(--ck-color-switch-button-on-hover-background)}[dir=ltr] .ck.ck-button.ck-switchbutton.ck-on .ck-button__toggle .ck-button__toggle__inner{transform:translateX(var(--ck-switch-button-translation))}[dir=rtl] .ck.ck-button.ck-switchbutton.ck-on .ck-button__toggle .ck-button__toggle__inner{transform:translateX(calc(var(--ck-switch-button-translation)*-1))}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./toolbardropdown.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \":root{--ck-toolbar-dropdown-max-width:60vw}.ck.ck-toolbar-dropdown .ck-dropdown__panel{width:max-content;max-width:var(--ck-toolbar-dropdown-max-width)}.ck.ck-toolbar-dropdown .ck-dropdown__panel .ck-button:focus{z-index:calc(var(--ck-z-default) + 1)}.ck.ck-toolbar-dropdown .ck-toolbar{border:0}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./listdropdown.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-dropdown .ck-dropdown__panel .ck-list{border-radius:0}.ck-rounded-corners .ck.ck-dropdown .ck-dropdown__panel .ck-list,.ck.ck-dropdown .ck-dropdown__panel .ck-list.ck-rounded-corners{border-radius:var(--ck-border-radius);border-top-left-radius:0}.ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:first-child .ck-button{border-radius:0}.ck-rounded-corners .ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:first-child .ck-button,.ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:first-child .ck-button.ck-rounded-corners{border-radius:var(--ck-border-radius);border-top-left-radius:0;border-bottom-left-radius:0;border-bottom-right-radius:0}.ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:last-child .ck-button{border-radius:0}.ck-rounded-corners .ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:last-child .ck-button,.ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:last-child .ck-button.ck-rounded-corners{border-radius:var(--ck-border-radius);border-top-left-radius:0;border-top-right-radius:0}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./toolbar.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-toolbar{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;display:flex;flex-flow:row nowrap;align-items:center}.ck.ck-toolbar>.ck-toolbar__items{display:flex;flex-flow:row wrap;align-items:center;flex-grow:1}.ck.ck-toolbar .ck.ck-toolbar__separator{display:inline-block}.ck.ck-toolbar .ck.ck-toolbar__separator:first-child,.ck.ck-toolbar .ck.ck-toolbar__separator:last-child{display:none}.ck.ck-toolbar .ck-toolbar__line-break{flex-basis:100%}.ck.ck-toolbar.ck-toolbar_grouping>.ck-toolbar__items{flex-wrap:nowrap}.ck.ck-toolbar.ck-toolbar_vertical>.ck-toolbar__items{flex-direction:column}.ck.ck-toolbar.ck-toolbar_floating>.ck-toolbar__items{flex-wrap:nowrap}.ck.ck-toolbar>.ck.ck-toolbar__grouped-dropdown>.ck-dropdown__button .ck-dropdown__arrow{display:none}.ck.ck-toolbar{border-radius:0}.ck-rounded-corners .ck.ck-toolbar,.ck.ck-toolbar.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-toolbar{background:var(--ck-color-toolbar-background);padding:0 var(--ck-spacing-small);border:1px solid var(--ck-color-toolbar-border)}.ck.ck-toolbar .ck.ck-toolbar__separator{align-self:stretch;width:1px;min-width:1px;background:var(--ck-color-toolbar-border);margin-top:var(--ck-spacing-small);margin-bottom:var(--ck-spacing-small)}.ck.ck-toolbar .ck-toolbar__line-break{height:0}.ck.ck-toolbar>.ck-toolbar__items>:not(.ck-toolbar__line-break){margin-right:var(--ck-spacing-small)}.ck.ck-toolbar>.ck-toolbar__items:empty+.ck.ck-toolbar__separator{display:none}.ck.ck-toolbar>.ck-toolbar__items>:not(.ck-toolbar__line-break),.ck.ck-toolbar>.ck.ck-toolbar__grouped-dropdown{margin-top:var(--ck-spacing-small);margin-bottom:var(--ck-spacing-small)}.ck.ck-toolbar.ck-toolbar_vertical{padding:0}.ck.ck-toolbar.ck-toolbar_vertical>.ck-toolbar__items>.ck{width:100%;margin:0;border-radius:0;border:0}.ck.ck-toolbar.ck-toolbar_compact{padding:0}.ck.ck-toolbar.ck-toolbar_compact>.ck-toolbar__items>*{margin:0}.ck.ck-toolbar.ck-toolbar_compact>.ck-toolbar__items>:not(:first-child):not(:last-child){border-radius:0}.ck.ck-toolbar>.ck.ck-toolbar__grouped-dropdown>.ck.ck-button.ck-dropdown__button{padding-left:var(--ck-spacing-tiny)}.ck-toolbar-container .ck.ck-toolbar{border:0}.ck.ck-toolbar[dir=rtl]>.ck-toolbar__items>.ck,[dir=rtl] .ck.ck-toolbar>.ck-toolbar__items>.ck{margin-right:0}.ck.ck-toolbar[dir=rtl]:not(.ck-toolbar_compact)>.ck-toolbar__items>.ck,[dir=rtl] .ck.ck-toolbar:not(.ck-toolbar_compact)>.ck-toolbar__items>.ck{margin-left:var(--ck-spacing-small)}.ck.ck-toolbar[dir=rtl]>.ck-toolbar__items>.ck:last-child,[dir=rtl] .ck.ck-toolbar>.ck-toolbar__items>.ck:last-child{margin-left:0}.ck.ck-toolbar[dir=rtl].ck-toolbar_compact>.ck-toolbar__items>.ck:first-child,[dir=rtl] .ck.ck-toolbar.ck-toolbar_compact>.ck-toolbar__items>.ck:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.ck.ck-toolbar[dir=rtl].ck-toolbar_compact>.ck-toolbar__items>.ck:last-child,[dir=rtl] .ck.ck-toolbar.ck-toolbar_compact>.ck-toolbar__items>.ck:last-child{border-top-right-radius:0;border-bottom-right-radius:0}.ck.ck-toolbar[dir=rtl]>.ck.ck-toolbar__separator,[dir=rtl] .ck.ck-toolbar>.ck.ck-toolbar__separator{margin-left:var(--ck-spacing-small)}.ck.ck-toolbar[dir=rtl].ck-toolbar_grouping>.ck-toolbar__items:not(:empty):not(:only-child),[dir=rtl] .ck.ck-toolbar.ck-toolbar_grouping>.ck-toolbar__items:not(:empty):not(:only-child){margin-left:var(--ck-spacing-small)}.ck.ck-toolbar[dir=ltr]>.ck-toolbar__items>.ck:last-child,[dir=ltr] .ck.ck-toolbar>.ck-toolbar__items>.ck:last-child{margin-right:0}.ck.ck-toolbar[dir=ltr].ck-toolbar_compact>.ck-toolbar__items>.ck:first-child,[dir=ltr] .ck.ck-toolbar.ck-toolbar_compact>.ck-toolbar__items>.ck:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.ck.ck-toolbar[dir=ltr].ck-toolbar_compact>.ck-toolbar__items>.ck:last-child,[dir=ltr] .ck.ck-toolbar.ck-toolbar_compact>.ck-toolbar__items>.ck:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.ck.ck-toolbar[dir=ltr]>.ck.ck-toolbar__separator,[dir=ltr] .ck.ck-toolbar>.ck.ck-toolbar__separator{margin-right:var(--ck-spacing-small)}.ck.ck-toolbar[dir=ltr].ck-toolbar_grouping>.ck-toolbar__items:not(:empty):not(:only-child),[dir=ltr] .ck.ck-toolbar.ck-toolbar_grouping>.ck-toolbar__items:not(:empty):not(:only-child){margin-right:var(--ck-spacing-small)}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./classiceditor.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-editor{position:relative}.ck.ck-editor .ck-editor__top .ck-sticky-panel .ck-toolbar{z-index:var(--ck-z-modal)}.ck.ck-editor__top .ck-sticky-panel .ck-toolbar{border-radius:0}.ck-rounded-corners .ck.ck-editor__top .ck-sticky-panel .ck-toolbar,.ck.ck-editor__top .ck-sticky-panel .ck-toolbar.ck-rounded-corners{border-radius:var(--ck-border-radius);border-bottom-left-radius:0;border-bottom-right-radius:0}.ck.ck-editor__top .ck-sticky-panel .ck-toolbar{border-bottom-width:0}.ck.ck-editor__top .ck-sticky-panel .ck-sticky-panel__content_sticky .ck-toolbar{border-bottom-width:1px;border-radius:0}.ck-rounded-corners .ck.ck-editor__top .ck-sticky-panel .ck-sticky-panel__content_sticky .ck-toolbar,.ck.ck-editor__top .ck-sticky-panel .ck-sticky-panel__content_sticky .ck-toolbar.ck-rounded-corners{border-radius:var(--ck-border-radius);border-radius:0}.ck.ck-editor__main>.ck-editor__editable{background:var(--ck-color-base-background);border-radius:0}.ck-rounded-corners .ck.ck-editor__main>.ck-editor__editable,.ck.ck-editor__main>.ck-editor__editable.ck-rounded-corners{border-radius:var(--ck-border-radius);border-top-left-radius:0;border-top-right-radius:0}.ck.ck-editor__main>.ck-editor__editable:not(.ck-focused){border-color:var(--ck-color-base-border)}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./blockquote.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck-content blockquote{overflow:hidden;padding-right:1.5em;padding-left:1.5em;margin-left:0;margin-right:0;font-style:italic;border-left:5px solid #ccc}.ck-content[dir=rtl] blockquote{border-left:0;border-right:5px solid #ccc}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./balloonpanel.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \":root{--ck-balloon-panel-arrow-z-index:calc(var(--ck-z-default) - 3)}.ck.ck-balloon-panel{display:none;position:absolute;z-index:var(--ck-z-modal)}.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:after,.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:before{content:\\\"\\\";position:absolute}.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:before{z-index:var(--ck-balloon-panel-arrow-z-index)}.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:after{z-index:calc(var(--ck-balloon-panel-arrow-z-index) + 1)}.ck.ck-balloon-panel[class*=arrow_n]:before{z-index:var(--ck-balloon-panel-arrow-z-index)}.ck.ck-balloon-panel[class*=arrow_n]:after{z-index:calc(var(--ck-balloon-panel-arrow-z-index) + 1)}.ck.ck-balloon-panel[class*=arrow_s]:before{z-index:var(--ck-balloon-panel-arrow-z-index)}.ck.ck-balloon-panel[class*=arrow_s]:after{z-index:calc(var(--ck-balloon-panel-arrow-z-index) + 1)}.ck.ck-balloon-panel.ck-balloon-panel_visible{display:block}:root{--ck-balloon-arrow-offset:2px;--ck-balloon-arrow-height:10px;--ck-balloon-arrow-half-width:8px;--ck-balloon-arrow-drop-shadow:0 2px 2px var(--ck-color-shadow-drop)}.ck.ck-balloon-panel{border-radius:0}.ck-rounded-corners .ck.ck-balloon-panel,.ck.ck-balloon-panel.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-balloon-panel{box-shadow:var(--ck-drop-shadow),0 0;min-height:15px;background:var(--ck-color-panel-background);border:1px solid var(--ck-color-panel-border)}.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:after,.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:before{width:0;height:0;border-style:solid}.ck.ck-balloon-panel[class*=arrow_n]:after,.ck.ck-balloon-panel[class*=arrow_n]:before{border-left-width:var(--ck-balloon-arrow-half-width);border-bottom-width:var(--ck-balloon-arrow-height);border-right-width:var(--ck-balloon-arrow-half-width);border-top-width:0}.ck.ck-balloon-panel[class*=arrow_n]:before{border-bottom-color:var(--ck-color-panel-border)}.ck.ck-balloon-panel[class*=arrow_n]:after,.ck.ck-balloon-panel[class*=arrow_n]:before{border-left-color:transparent;border-right-color:transparent;border-top-color:transparent}.ck.ck-balloon-panel[class*=arrow_n]:after{border-bottom-color:var(--ck-color-panel-background);margin-top:var(--ck-balloon-arrow-offset)}.ck.ck-balloon-panel[class*=arrow_s]:after,.ck.ck-balloon-panel[class*=arrow_s]:before{border-left-width:var(--ck-balloon-arrow-half-width);border-bottom-width:0;border-right-width:var(--ck-balloon-arrow-half-width);border-top-width:var(--ck-balloon-arrow-height)}.ck.ck-balloon-panel[class*=arrow_s]:before{border-top-color:var(--ck-color-panel-border);filter:drop-shadow(var(--ck-balloon-arrow-drop-shadow))}.ck.ck-balloon-panel[class*=arrow_s]:after,.ck.ck-balloon-panel[class*=arrow_s]:before{border-left-color:transparent;border-bottom-color:transparent;border-right-color:transparent}.ck.ck-balloon-panel[class*=arrow_s]:after{border-top-color:var(--ck-color-panel-background);margin-bottom:var(--ck-balloon-arrow-offset)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_n:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_n:before{left:50%;margin-left:calc(var(--ck-balloon-arrow-half-width)*-1);top:calc(var(--ck-balloon-arrow-height)*-1)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_nw:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_nw:before{left:calc(var(--ck-balloon-arrow-half-width)*2);top:calc(var(--ck-balloon-arrow-height)*-1)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_ne:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_ne:before{right:calc(var(--ck-balloon-arrow-half-width)*2);top:calc(var(--ck-balloon-arrow-height)*-1)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_s:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_s:before{left:50%;margin-left:calc(var(--ck-balloon-arrow-half-width)*-1);bottom:calc(var(--ck-balloon-arrow-height)*-1)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_sw:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_sw:before{left:calc(var(--ck-balloon-arrow-half-width)*2);bottom:calc(var(--ck-balloon-arrow-height)*-1)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_se:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_se:before{right:calc(var(--ck-balloon-arrow-half-width)*2);bottom:calc(var(--ck-balloon-arrow-height)*-1)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_sme:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_sme:before{right:25%;margin-right:calc(var(--ck-balloon-arrow-half-width)*2);bottom:calc(var(--ck-balloon-arrow-height)*-1)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_smw:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_smw:before{left:25%;margin-left:calc(var(--ck-balloon-arrow-half-width)*2);bottom:calc(var(--ck-balloon-arrow-height)*-1)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_nme:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_nme:before{right:25%;margin-right:calc(var(--ck-balloon-arrow-half-width)*2);top:calc(var(--ck-balloon-arrow-height)*-1)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_nmw:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_nmw:before{left:25%;margin-left:calc(var(--ck-balloon-arrow-half-width)*2);top:calc(var(--ck-balloon-arrow-height)*-1)}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./link.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck .ck-link_selected{background:var(--ck-color-link-selected-background)}.ck .ck-fake-link-selection{background:var(--ck-color-link-fake-selection)}.ck .ck-fake-link-selection_collapsed{height:100%;border-right:1px solid var(--ck-color-base-text);margin-right:-1px;outline:1px solid hsla(0,0%,100%,.5)}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./widgettypearound.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck .ck-widget .ck-widget__type-around__button{display:block;position:absolute;overflow:hidden;z-index:var(--ck-z-default)}.ck .ck-widget .ck-widget__type-around__button svg{position:absolute;top:50%;left:50%;z-index:calc(var(--ck-z-default) + 2)}.ck .ck-widget .ck-widget__type-around__button.ck-widget__type-around__button_before{top:calc(var(--ck-widget-outline-thickness)*-0.5);left:min(10%,30px);transform:translateY(-50%)}.ck .ck-widget .ck-widget__type-around__button.ck-widget__type-around__button_after{bottom:calc(var(--ck-widget-outline-thickness)*-0.5);right:min(10%,30px);transform:translateY(50%)}.ck .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button:after,.ck .ck-widget>.ck-widget__type-around>.ck-widget__type-around__button:hover:after{content:\\\"\\\";display:block;position:absolute;top:1px;left:1px;z-index:calc(var(--ck-z-default) + 1)}.ck .ck-widget>.ck-widget__type-around>.ck-widget__type-around__fake-caret{display:none;position:absolute;left:0;right:0}.ck .ck-widget:hover>.ck-widget__type-around>.ck-widget__type-around__fake-caret{left:calc(var(--ck-widget-outline-thickness)*-1);right:calc(var(--ck-widget-outline-thickness)*-1)}.ck .ck-widget.ck-widget_type-around_show-fake-caret_before>.ck-widget__type-around>.ck-widget__type-around__fake-caret{top:calc(var(--ck-widget-outline-thickness)*-1 - 1px);display:block}.ck .ck-widget.ck-widget_type-around_show-fake-caret_after>.ck-widget__type-around>.ck-widget__type-around__fake-caret{bottom:calc(var(--ck-widget-outline-thickness)*-1 - 1px);display:block}.ck.ck-editor__editable.ck-read-only .ck-widget__type-around,.ck.ck-editor__editable.ck-restricted-editing_mode_restricted .ck-widget__type-around,.ck.ck-editor__editable.ck-widget__type-around_disabled .ck-widget__type-around{display:none}:root{--ck-widget-type-around-button-size:20px;--ck-color-widget-type-around-button-active:var(--ck-color-focus-border);--ck-color-widget-type-around-button-hover:var(--ck-color-widget-hover-border);--ck-color-widget-type-around-button-blurred-editable:var(--ck-color-widget-blurred-border);--ck-color-widget-type-around-button-radar-start-alpha:0;--ck-color-widget-type-around-button-radar-end-alpha:.3;--ck-color-widget-type-around-button-icon:var(--ck-color-base-background)}.ck .ck-widget .ck-widget__type-around__button{width:var(--ck-widget-type-around-button-size);height:var(--ck-widget-type-around-button-size);background:var(--ck-color-widget-type-around-button);border-radius:100px;transition:opacity var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve),background var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve);opacity:0;pointer-events:none}.ck .ck-widget .ck-widget__type-around__button svg{width:10px;height:8px;transform:translate(-50%,-50%);transition:transform .5s ease;margin-top:1px}.ck .ck-widget .ck-widget__type-around__button svg *{stroke-dasharray:10;stroke-dashoffset:0;fill:none;stroke:var(--ck-color-widget-type-around-button-icon);stroke-width:1.5px;stroke-linecap:round;stroke-linejoin:round}.ck .ck-widget .ck-widget__type-around__button svg line{stroke-dasharray:7}.ck .ck-widget .ck-widget__type-around__button:hover{animation:ck-widget-type-around-button-sonar 1s ease infinite}.ck .ck-widget .ck-widget__type-around__button:hover svg polyline{animation:ck-widget-type-around-arrow-dash 2s linear}.ck .ck-widget .ck-widget__type-around__button:hover svg line{animation:ck-widget-type-around-arrow-tip-dash 2s linear}.ck .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button,.ck .ck-widget:hover>.ck-widget__type-around>.ck-widget__type-around__button{opacity:1;pointer-events:auto}.ck .ck-widget:not(.ck-widget_selected)>.ck-widget__type-around>.ck-widget__type-around__button{background:var(--ck-color-widget-type-around-button-hover)}.ck .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button,.ck .ck-widget>.ck-widget__type-around>.ck-widget__type-around__button:hover{background:var(--ck-color-widget-type-around-button-active)}.ck .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button:after,.ck .ck-widget>.ck-widget__type-around>.ck-widget__type-around__button:hover:after{width:calc(var(--ck-widget-type-around-button-size) - 2px);height:calc(var(--ck-widget-type-around-button-size) - 2px);border-radius:100px;background:linear-gradient(135deg,hsla(0,0%,100%,0),hsla(0,0%,100%,.3))}.ck .ck-widget.ck-widget_with-selection-handle>.ck-widget__type-around>.ck-widget__type-around__button_before{margin-left:20px}.ck .ck-widget .ck-widget__type-around__fake-caret{pointer-events:none;height:1px;animation:ck-widget-type-around-fake-caret-pulse 1s linear infinite normal forwards;outline:1px solid hsla(0,0%,100%,.5);background:var(--ck-color-base-text)}.ck .ck-widget.ck-widget_selected.ck-widget_type-around_show-fake-caret_after,.ck .ck-widget.ck-widget_selected.ck-widget_type-around_show-fake-caret_before{outline-color:transparent}.ck .ck-widget.ck-widget_type-around_show-fake-caret_after.ck-widget_selected:hover,.ck .ck-widget.ck-widget_type-around_show-fake-caret_before.ck-widget_selected:hover{outline-color:var(--ck-color-widget-hover-border)}.ck .ck-widget.ck-widget_type-around_show-fake-caret_after>.ck-widget__type-around>.ck-widget__type-around__button,.ck .ck-widget.ck-widget_type-around_show-fake-caret_before>.ck-widget__type-around>.ck-widget__type-around__button{opacity:0;pointer-events:none}.ck .ck-widget.ck-widget_type-around_show-fake-caret_after.ck-widget_with-selection-handle.ck-widget_selected:hover>.ck-widget__selection-handle,.ck .ck-widget.ck-widget_type-around_show-fake-caret_after.ck-widget_with-selection-handle.ck-widget_selected>.ck-widget__selection-handle,.ck .ck-widget.ck-widget_type-around_show-fake-caret_before.ck-widget_with-selection-handle.ck-widget_selected:hover>.ck-widget__selection-handle,.ck .ck-widget.ck-widget_type-around_show-fake-caret_before.ck-widget_with-selection-handle.ck-widget_selected>.ck-widget__selection-handle{opacity:0}.ck .ck-widget.ck-widget_type-around_show-fake-caret_after.ck-widget_selected.ck-widget_with-resizer>.ck-widget__resizer,.ck .ck-widget.ck-widget_type-around_show-fake-caret_before.ck-widget_selected.ck-widget_with-resizer>.ck-widget__resizer{opacity:0}.ck[dir=rtl] .ck-widget.ck-widget_with-selection-handle .ck-widget__type-around>.ck-widget__type-around__button_before{margin-left:0;margin-right:20px}.ck-editor__nested-editable.ck-editor__editable_selected .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button,.ck-editor__nested-editable.ck-editor__editable_selected .ck-widget:hover>.ck-widget__type-around>.ck-widget__type-around__button{opacity:0;pointer-events:none}.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button:not(:hover){background:var(--ck-color-widget-type-around-button-blurred-editable)}.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button:not(:hover) svg *{stroke:#999}@keyframes ck-widget-type-around-arrow-dash{0%{stroke-dashoffset:10}20%,to{stroke-dashoffset:0}}@keyframes ck-widget-type-around-arrow-tip-dash{0%,20%{stroke-dashoffset:7}40%,to{stroke-dashoffset:0}}@keyframes ck-widget-type-around-button-sonar{0%{box-shadow:0 0 0 0 hsla(var(--ck-color-focus-border-coordinates),var(--ck-color-widget-type-around-button-radar-start-alpha))}50%{box-shadow:0 0 0 5px hsla(var(--ck-color-focus-border-coordinates),var(--ck-color-widget-type-around-button-radar-end-alpha))}to{box-shadow:0 0 0 5px hsla(var(--ck-color-focus-border-coordinates),var(--ck-color-widget-type-around-button-radar-start-alpha))}}@keyframes ck-widget-type-around-fake-caret-pulse{0%{opacity:1}49%{opacity:1}50%{opacity:0}99%{opacity:0}to{opacity:1}}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./widget.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \":root{--ck-color-resizer:var(--ck-color-focus-border);--ck-resizer-size:10px;--ck-resizer-border-width:1px;--ck-resizer-border-radius:2px;--ck-resizer-offset:calc(var(--ck-resizer-size)/-2 - 2px);--ck-resizer-tooltip-offset:10px;--ck-color-resizer-tooltip-background:#262626;--ck-color-resizer-tooltip-text:#f2f2f2}.ck .ck-widget,.ck .ck-widget.ck-widget_with-selection-handle{position:relative}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle{position:absolute}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle .ck-icon{display:block}.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected .ck-widget__selection-handle,.ck .ck-widget.ck-widget_with-selection-handle:hover .ck-widget__selection-handle{visibility:visible}.ck .ck-size-view{background:var(--ck-color-resizer-tooltip-background);color:var(--ck-color-resizer-tooltip-text);border:1px solid var(--ck-color-resizer-tooltip-text);border-radius:var(--ck-resizer-border-radius);font-size:var(--ck-font-size-tiny);display:block;padding:var(--ck-spacing-small)}.ck .ck-size-view.ck-orientation-bottom-left,.ck .ck-size-view.ck-orientation-bottom-right,.ck .ck-size-view.ck-orientation-top-left,.ck .ck-size-view.ck-orientation-top-right{position:absolute}.ck .ck-size-view.ck-orientation-top-left{top:var(--ck-resizer-tooltip-offset);left:var(--ck-resizer-tooltip-offset)}.ck .ck-size-view.ck-orientation-top-right{top:var(--ck-resizer-tooltip-offset);right:var(--ck-resizer-tooltip-offset)}.ck .ck-size-view.ck-orientation-bottom-right{bottom:var(--ck-resizer-tooltip-offset);right:var(--ck-resizer-tooltip-offset)}.ck .ck-size-view.ck-orientation-bottom-left{bottom:var(--ck-resizer-tooltip-offset);left:var(--ck-resizer-tooltip-offset)}:root{--ck-widget-outline-thickness:3px;--ck-widget-handler-icon-size:16px;--ck-widget-handler-animation-duration:200ms;--ck-widget-handler-animation-curve:ease;--ck-color-widget-blurred-border:#dedede;--ck-color-widget-hover-border:#ffc83d;--ck-color-widget-editable-focus-background:var(--ck-color-base-background);--ck-color-widget-drag-handler-icon-color:var(--ck-color-base-background)}.ck .ck-widget{outline-width:var(--ck-widget-outline-thickness);outline-style:solid;outline-color:transparent;transition:outline-color var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve)}.ck .ck-widget.ck-widget_selected,.ck .ck-widget.ck-widget_selected:hover{outline:var(--ck-widget-outline-thickness) solid var(--ck-color-focus-border)}.ck .ck-widget:hover{outline-color:var(--ck-color-widget-hover-border)}.ck .ck-editor__nested-editable{border:1px solid transparent}.ck .ck-editor__nested-editable.ck-editor__nested-editable_focused,.ck .ck-editor__nested-editable:focus{outline:none;border:var(--ck-focus-ring);box-shadow:var(--ck-inner-shadow),0 0;background-color:var(--ck-color-widget-editable-focus-background)}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle{padding:4px;box-sizing:border-box;background-color:transparent;opacity:0;transition:background-color var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve),visibility var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve),opacity var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve);border-radius:var(--ck-border-radius) var(--ck-border-radius) 0 0;transform:translateY(-100%);left:calc(0px - var(--ck-widget-outline-thickness))}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle .ck-icon{width:var(--ck-widget-handler-icon-size);height:var(--ck-widget-handler-icon-size);color:var(--ck-color-widget-drag-handler-icon-color)}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle .ck-icon .ck-icon__selected-indicator{opacity:0;transition:opacity .3s var(--ck-widget-handler-animation-curve)}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle:hover .ck-icon .ck-icon__selected-indicator{opacity:1}.ck .ck-widget.ck-widget_with-selection-handle:hover .ck-widget__selection-handle{opacity:1;background-color:var(--ck-color-widget-hover-border)}.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected .ck-widget__selection-handle,.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected:hover .ck-widget__selection-handle{opacity:1;background-color:var(--ck-color-focus-border)}.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected .ck-widget__selection-handle .ck-icon .ck-icon__selected-indicator,.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected:hover .ck-widget__selection-handle .ck-icon .ck-icon__selected-indicator{opacity:1}.ck[dir=rtl] .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle{left:auto;right:calc(0px - var(--ck-widget-outline-thickness))}.ck.ck-editor__editable.ck-read-only .ck-widget{transition:none}.ck.ck-editor__editable.ck-read-only .ck-widget:not(.ck-widget_selected){--ck-widget-outline-thickness:0px}.ck.ck-editor__editable.ck-read-only .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle,.ck.ck-editor__editable.ck-read-only .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle:hover{background:var(--ck-color-widget-blurred-border)}.ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected,.ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected:hover{outline-color:var(--ck-color-widget-blurred-border)}.ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected.ck-widget_with-selection-handle .ck-widget__selection-handle,.ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected.ck-widget_with-selection-handle .ck-widget__selection-handle:hover,.ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected:hover.ck-widget_with-selection-handle .ck-widget__selection-handle,.ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected:hover.ck-widget_with-selection-handle .ck-widget__selection-handle:hover{background:var(--ck-color-widget-blurred-border)}.ck.ck-editor__editable>.ck-widget.ck-widget_with-selection-handle:first-child,.ck.ck-editor__editable blockquote>.ck-widget.ck-widget_with-selection-handle:first-child{margin-top:calc(1em + var(--ck-widget-handler-icon-size))}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./labeledfieldview.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper{display:flex;position:relative}.ck.ck-labeled-field-view .ck.ck-label{display:block;position:absolute}:root{--ck-labeled-field-view-transition:.1s cubic-bezier(0,0,0.24,0.95);--ck-labeled-field-empty-unfocused-max-width:100% - 2 * var(--ck-spacing-medium);--ck-color-labeled-field-label-background:var(--ck-color-base-background)}.ck.ck-labeled-field-view{border-radius:0}.ck-rounded-corners .ck.ck-labeled-field-view,.ck.ck-labeled-field-view.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper{width:100%}.ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{top:0}[dir=ltr] .ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{left:0}[dir=rtl] .ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{right:0}.ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{pointer-events:none;transform-origin:0 0;transform:translate(var(--ck-spacing-medium),-6px) scale(.75);background:var(--ck-color-labeled-field-label-background);padding:0 calc(var(--ck-font-size-tiny)*0.5);line-height:normal;font-weight:400;text-overflow:ellipsis;overflow:hidden;max-width:100%;transition:transform var(--ck-labeled-field-view-transition),padding var(--ck-labeled-field-view-transition),background var(--ck-labeled-field-view-transition)}.ck.ck-labeled-field-view.ck-error .ck-input:not([readonly])+.ck.ck-label,.ck.ck-labeled-field-view.ck-error>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{color:var(--ck-color-base-error)}.ck.ck-labeled-field-view .ck-labeled-field-view__status{font-size:var(--ck-font-size-small);margin-top:var(--ck-spacing-small);white-space:normal}.ck.ck-labeled-field-view .ck-labeled-field-view__status.ck-labeled-field-view__status_error{color:var(--ck-color-base-error)}.ck.ck-labeled-field-view.ck-disabled>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label,.ck.ck-labeled-field-view.ck-labeled-field-view_empty:not(.ck-labeled-field-view_focused)>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{color:var(--ck-color-input-disabled-text)}[dir=ltr] .ck.ck-labeled-field-view.ck-disabled>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label,[dir=ltr] .ck.ck-labeled-field-view.ck-labeled-field-view_empty:not(.ck-labeled-field-view_focused):not(.ck-labeled-field-view_placeholder)>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{transform:translate(var(--ck-spacing-medium),calc(var(--ck-font-size-base)*0.6)) scale(1)}[dir=rtl] .ck.ck-labeled-field-view.ck-disabled>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label,[dir=rtl] .ck.ck-labeled-field-view.ck-labeled-field-view_empty:not(.ck-labeled-field-view_focused):not(.ck-labeled-field-view_placeholder)>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{transform:translate(calc(var(--ck-spacing-medium)*-1),calc(var(--ck-font-size-base)*0.6)) scale(1)}.ck.ck-labeled-field-view.ck-disabled>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label,.ck.ck-labeled-field-view.ck-labeled-field-view_empty:not(.ck-labeled-field-view_focused):not(.ck-labeled-field-view_placeholder)>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{max-width:calc(var(--ck-labeled-field-empty-unfocused-max-width));background:transparent;padding:0}.ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper>.ck-dropdown>.ck.ck-button{background:transparent}.ck.ck-labeled-field-view.ck-labeled-field-view_empty>.ck.ck-labeled-field-view__input-wrapper>.ck-dropdown>.ck-button>.ck-button__label{opacity:0}.ck.ck-labeled-field-view.ck-labeled-field-view_empty:not(.ck-labeled-field-view_focused):not(.ck-labeled-field-view_placeholder)>.ck.ck-labeled-field-view__input-wrapper>.ck-dropdown+.ck-label{max-width:calc(var(--ck-labeled-field-empty-unfocused-max-width) - var(--ck-dropdown-arrow-size) - var(--ck-spacing-standard))}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./inputtext.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \":root{--ck-input-text-width:18em}.ck.ck-input-text{border-radius:0}.ck-rounded-corners .ck.ck-input-text,.ck.ck-input-text.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-input-text{background:var(--ck-color-input-background);border:1px solid var(--ck-color-input-border);padding:var(--ck-spacing-extra-tiny) var(--ck-spacing-medium);min-width:var(--ck-input-text-width);min-height:var(--ck-ui-component-min-height);transition:box-shadow .1s ease-in-out,border .1s ease-in-out}.ck.ck-input-text:focus{outline:none;border:var(--ck-focus-ring);box-shadow:var(--ck-focus-outer-shadow),0 0}.ck.ck-input-text[readonly]{border:1px solid var(--ck-color-input-disabled-border);background:var(--ck-color-input-disabled-background);color:var(--ck-color-input-disabled-text)}.ck.ck-input-text[readonly]:focus{box-shadow:var(--ck-focus-disabled-outer-shadow),0 0}.ck.ck-input-text.ck-error{border-color:var(--ck-color-input-error-border);animation:ck-text-input-shake .3s ease both}.ck.ck-input-text.ck-error:focus{box-shadow:var(--ck-focus-error-outer-shadow),0 0}@keyframes ck-text-input-shake{20%{transform:translateX(-2px)}40%{transform:translateX(2px)}60%{transform:translateX(-1px)}80%{transform:translateX(1px)}}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./textalternativeform.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-text-alternative-form{display:flex;flex-direction:row;flex-wrap:nowrap}.ck.ck-text-alternative-form .ck-labeled-field-view{display:inline-block}.ck.ck-text-alternative-form .ck-label{display:none}@media screen and (max-width:600px){.ck.ck-text-alternative-form{flex-wrap:wrap}.ck.ck-text-alternative-form .ck-labeled-field-view{flex-basis:100%}.ck.ck-text-alternative-form .ck-button{flex-basis:50%}}\"","module.exports = \".ck-vertical-form .ck-button:after{content:\\\"\\\";width:0;position:absolute;right:-1px;top:var(--ck-spacing-small);bottom:var(--ck-spacing-small);z-index:1}@media screen and (max-width:600px){.ck.ck-responsive-form .ck-button:after{content:\\\"\\\";width:0;position:absolute;right:-1px;top:var(--ck-spacing-small);bottom:var(--ck-spacing-small);z-index:1}}.ck-vertical-form>.ck-button:nth-last-child(2):after{border-right:1px solid var(--ck-color-base-border)}.ck.ck-responsive-form{padding:var(--ck-spacing-large)}.ck.ck-responsive-form:focus{outline:none}[dir=ltr] .ck.ck-responsive-form>:not(:first-child),[dir=rtl] .ck.ck-responsive-form>:not(:last-child){margin-left:var(--ck-spacing-standard)}@media screen and (max-width:600px){.ck.ck-responsive-form{padding:0;width:calc(var(--ck-input-text-width)*0.8)}.ck.ck-responsive-form .ck-labeled-field-view{margin:var(--ck-spacing-large) var(--ck-spacing-large) 0}.ck.ck-responsive-form .ck-labeled-field-view .ck-input-text{min-width:0;width:100%}.ck.ck-responsive-form .ck-labeled-field-view .ck-labeled-field-view__error{white-space:normal}.ck.ck-responsive-form>.ck-button:last-child,.ck.ck-responsive-form>.ck-button:nth-last-child(2){padding:var(--ck-spacing-standard);margin-top:var(--ck-spacing-large);border-radius:0;border:0;border-top:1px solid var(--ck-color-base-border)}[dir=ltr] .ck.ck-responsive-form>.ck-button:last-child,[dir=ltr] .ck.ck-responsive-form>.ck-button:nth-last-child(2),[dir=rtl] .ck.ck-responsive-form>.ck-button:last-child,[dir=rtl] .ck.ck-responsive-form>.ck-button:nth-last-child(2){margin-left:0}.ck.ck-responsive-form>.ck-button:nth-last-child(2):after,[dir=rtl] .ck.ck-responsive-form>.ck-button:last-child:last-of-type,[dir=rtl] .ck.ck-responsive-form>.ck-button:nth-last-child(2):last-of-type{border-right:1px solid var(--ck-color-base-border)}}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./balloonrotator.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck .ck-balloon-rotator__navigation{display:flex;align-items:center;justify-content:center}.ck .ck-balloon-rotator__content .ck-toolbar{justify-content:center}.ck .ck-balloon-rotator__navigation{background:var(--ck-color-toolbar-background);border-bottom:1px solid var(--ck-color-toolbar-border);padding:0 var(--ck-spacing-small)}.ck .ck-balloon-rotator__navigation>*{margin-right:var(--ck-spacing-small);margin-top:var(--ck-spacing-small);margin-bottom:var(--ck-spacing-small)}.ck .ck-balloon-rotator__navigation .ck-balloon-rotator__counter{margin-right:var(--ck-spacing-standard);margin-left:var(--ck-spacing-small)}.ck .ck-balloon-rotator__content .ck.ck-annotation-wrapper{box-shadow:none}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./fakepanel.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck .ck-fake-panel{position:absolute;z-index:calc(var(--ck-z-modal) - 1)}.ck .ck-fake-panel div{position:absolute}.ck .ck-fake-panel div:first-child{z-index:2}.ck .ck-fake-panel div:nth-child(2){z-index:1}:root{--ck-balloon-fake-panel-offset-horizontal:6px;--ck-balloon-fake-panel-offset-vertical:6px}.ck .ck-fake-panel div{box-shadow:var(--ck-drop-shadow),0 0;min-height:15px;background:var(--ck-color-panel-background);border:1px solid var(--ck-color-panel-border);border-radius:var(--ck-border-radius);width:100%;height:100%}.ck .ck-fake-panel div:first-child{margin-left:var(--ck-balloon-fake-panel-offset-horizontal);margin-top:var(--ck-balloon-fake-panel-offset-vertical)}.ck .ck-fake-panel div:nth-child(2){margin-left:calc(var(--ck-balloon-fake-panel-offset-horizontal)*2);margin-top:calc(var(--ck-balloon-fake-panel-offset-vertical)*2)}.ck .ck-fake-panel div:nth-child(3){margin-left:calc(var(--ck-balloon-fake-panel-offset-horizontal)*3);margin-top:calc(var(--ck-balloon-fake-panel-offset-vertical)*3)}.ck .ck-balloon-panel_arrow_s+.ck-fake-panel,.ck .ck-balloon-panel_arrow_se+.ck-fake-panel,.ck .ck-balloon-panel_arrow_sw+.ck-fake-panel{--ck-balloon-fake-panel-offset-vertical:-6px}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./image.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck-content .image{display:table;clear:both;text-align:center;margin:1em auto}.ck-content .image img{display:block;margin:0 auto;max-width:100%;min-width:50px}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./imageuploadprogress.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-editor__editable .image{position:relative}.ck.ck-editor__editable .image .ck-progress-bar{position:absolute;top:0;left:0}.ck.ck-editor__editable .image.ck-appear{animation:fadeIn .7s}.ck.ck-editor__editable .image .ck-progress-bar{height:2px;width:0;background:var(--ck-color-upload-bar-background);transition:width .1s}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./imageuploadicon.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck-image-upload-complete-icon{display:block;position:absolute;top:10px;right:10px;border-radius:50%}.ck-image-upload-complete-icon:after{content:\\\"\\\";position:absolute}:root{--ck-color-image-upload-icon:#fff;--ck-color-image-upload-icon-background:#008a00;--ck-image-upload-icon-size:20px;--ck-image-upload-icon-width:2px}.ck-image-upload-complete-icon{width:var(--ck-image-upload-icon-size);height:var(--ck-image-upload-icon-size);opacity:0;background:var(--ck-color-image-upload-icon-background);animation-name:ck-upload-complete-icon-show,ck-upload-complete-icon-hide;animation-fill-mode:forwards,forwards;animation-duration:.5s,.5s;font-size:var(--ck-image-upload-icon-size);animation-delay:0ms,3s}.ck-image-upload-complete-icon:after{left:25%;top:50%;opacity:0;height:0;width:0;transform:scaleX(-1) rotate(135deg);transform-origin:left top;border-top:var(--ck-image-upload-icon-width) solid var(--ck-color-image-upload-icon);border-right:var(--ck-image-upload-icon-width) solid var(--ck-color-image-upload-icon);animation-name:ck-upload-complete-icon-check;animation-duration:.5s;animation-delay:.5s;animation-fill-mode:forwards;box-sizing:border-box}@keyframes ck-upload-complete-icon-show{0%{opacity:0}to{opacity:1}}@keyframes ck-upload-complete-icon-hide{0%{opacity:1}to{opacity:0}}@keyframes ck-upload-complete-icon-check{0%{opacity:1;width:0;height:0}33%{width:.3em;height:0}to{opacity:1;width:.3em;height:.45em}}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./imageuploadloader.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck .ck-upload-placeholder-loader{position:absolute;display:flex;align-items:center;justify-content:center;top:0;left:0}.ck .ck-upload-placeholder-loader:before{content:\\\"\\\";position:relative}:root{--ck-color-upload-placeholder-loader:#b3b3b3;--ck-upload-placeholder-loader-size:32px}.ck .ck-image-upload-placeholder{width:100%;margin:0}.ck .ck-upload-placeholder-loader{width:100%;height:100%}.ck .ck-upload-placeholder-loader:before{width:var(--ck-upload-placeholder-loader-size);height:var(--ck-upload-placeholder-loader-size);border-radius:50%;border-top:3px solid var(--ck-color-upload-placeholder-loader);border-right:2px solid transparent;animation:ck-upload-placeholder-loader 1s linear infinite}@keyframes ck-upload-placeholder-loader{to{transform:rotate(1turn)}}\"","module.exports = \".ck.ck-heading_heading1{font-size:20px}.ck.ck-heading_heading2{font-size:17px}.ck.ck-heading_heading3{font-size:14px}.ck[class*=ck-heading_heading]{font-weight:700}.ck.ck-dropdown.ck-heading-dropdown .ck-dropdown__button .ck-button__label{width:8em}.ck.ck-dropdown.ck-heading-dropdown .ck-dropdown__panel .ck-list__item{min-width:18em}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./imagecaption.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck-content .image>figcaption{display:table-caption;caption-side:bottom;word-break:break-word;color:#333;background-color:#f7f7f7;padding:.6em;font-size:.75em;outline-offset:-1px}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./imagestyle.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \":root{--ck-image-style-spacing:1.5em}.ck-content .image-style-side{float:right;margin-left:var(--ck-image-style-spacing);max-width:50%}.ck-content .image-style-align-left{float:left;margin-right:var(--ck-image-style-spacing)}.ck-content .image-style-align-center{margin-left:auto;margin-right:auto}.ck-content .image-style-align-right{float:right;margin-left:var(--ck-image-style-spacing)}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./linkform.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-link-form{display:flex}.ck.ck-link-form .ck-label{display:none}@media screen and (max-width:600px){.ck.ck-link-form{flex-wrap:wrap}.ck.ck-link-form .ck-labeled-field-view{flex-basis:100%}.ck.ck-link-form .ck-button{flex-basis:50%}}.ck.ck-link-form_layout-vertical{display:block}.ck.ck-link-form_layout-vertical .ck-button.ck-button-cancel,.ck.ck-link-form_layout-vertical .ck-button.ck-button-save{margin-top:var(--ck-spacing-medium)}.ck.ck-link-form_layout-vertical{padding:0;min-width:var(--ck-input-text-width)}.ck.ck-link-form_layout-vertical .ck-labeled-field-view{margin:var(--ck-spacing-large) var(--ck-spacing-large) var(--ck-spacing-small)}.ck.ck-link-form_layout-vertical .ck-labeled-field-view .ck-input-text{min-width:0;width:100%}.ck.ck-link-form_layout-vertical .ck-button{padding:var(--ck-spacing-standard);margin:0;border-radius:0;border:0;border-top:1px solid var(--ck-color-base-border);width:50%}[dir=ltr] .ck.ck-link-form_layout-vertical .ck-button,[dir=rtl] .ck.ck-link-form_layout-vertical .ck-button{margin-left:0}[dir=rtl] .ck.ck-link-form_layout-vertical .ck-button:last-of-type{border-right:1px solid var(--ck-color-base-border)}.ck.ck-link-form_layout-vertical .ck.ck-list{margin:var(--ck-spacing-standard) var(--ck-spacing-large)}.ck.ck-link-form_layout-vertical .ck.ck-list .ck-button.ck-switchbutton{border:0;padding:0;width:100%}.ck.ck-link-form_layout-vertical .ck.ck-list .ck-button.ck-switchbutton:hover{background:none}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./linkactions.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-link-actions{display:flex;flex-direction:row;flex-wrap:nowrap}.ck.ck-link-actions .ck-link-actions__preview{display:inline-block}.ck.ck-link-actions .ck-link-actions__preview .ck-button__label{overflow:hidden}@media screen and (max-width:600px){.ck.ck-link-actions{flex-wrap:wrap}.ck.ck-link-actions .ck-link-actions__preview{flex-basis:100%}.ck.ck-link-actions .ck-button:not(.ck-link-actions__preview){flex-basis:50%}}.ck.ck-link-actions .ck-button.ck-link-actions__preview{padding-left:0;padding-right:0}.ck.ck-link-actions .ck-button.ck-link-actions__preview .ck-button__label{padding:0 var(--ck-spacing-medium);color:var(--ck-color-link-default);text-overflow:ellipsis;cursor:pointer;max-width:var(--ck-input-text-width);min-width:3em;text-align:center}.ck.ck-link-actions .ck-button.ck-link-actions__preview .ck-button__label:hover{text-decoration:underline}.ck.ck-link-actions .ck-button.ck-link-actions__preview,.ck.ck-link-actions .ck-button.ck-link-actions__preview:active,.ck.ck-link-actions .ck-button.ck-link-actions__preview:focus,.ck.ck-link-actions .ck-button.ck-link-actions__preview:hover{background:none}.ck.ck-link-actions .ck-button.ck-link-actions__preview:active{box-shadow:none}.ck.ck-link-actions .ck-button.ck-link-actions__preview:focus .ck-button__label{text-decoration:underline}[dir=ltr] .ck.ck-link-actions .ck-button:not(:first-child),[dir=rtl] .ck.ck-link-actions .ck-button:not(:last-child){margin-left:var(--ck-spacing-standard)}@media screen and (max-width:600px){.ck.ck-link-actions .ck-button.ck-link-actions__preview{margin:var(--ck-spacing-standard) var(--ck-spacing-standard) 0}.ck.ck-link-actions .ck-button.ck-link-actions__preview .ck-button__label{min-width:0;max-width:100%}[dir=ltr] .ck.ck-link-actions .ck-button:not(.ck-link-actions__preview),[dir=rtl] .ck.ck-link-actions .ck-button:not(.ck-link-actions__preview){margin-left:0}}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./mediaembedediting.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck-media__wrapper .ck-media__placeholder{display:flex;flex-direction:column;align-items:center}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url .ck-tooltip{display:block}@media (hover:none){.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url .ck-tooltip{display:none}}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url{max-width:100%;position:relative}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url:hover .ck-tooltip{visibility:visible;opacity:1}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url .ck-media__placeholder__url__text{overflow:hidden;display:block}.ck-media__wrapper[data-oembed-url*=\\\"facebook.com\\\"] .ck-media__placeholder__icon *,.ck-media__wrapper[data-oembed-url*=\\\"google.com/maps\\\"] .ck-media__placeholder__icon *,.ck-media__wrapper[data-oembed-url*=\\\"instagram.com\\\"] .ck-media__placeholder__icon *,.ck-media__wrapper[data-oembed-url*=\\\"twitter.com\\\"] .ck-media__placeholder__icon *{display:none}.ck-editor__editable:not(.ck-read-only) .ck-media__wrapper>:not(.ck-media__placeholder),.ck-editor__editable:not(.ck-read-only) .ck-widget:not(.ck-widget_selected) .ck-media__placeholder{pointer-events:none}:root{--ck-media-embed-placeholder-icon-size:3em;--ck-color-media-embed-placeholder-url-text:#757575;--ck-color-media-embed-placeholder-url-text-hover:var(--ck-color-base-text)}.ck-media__wrapper{margin:0 auto}.ck-media__wrapper .ck-media__placeholder{padding:calc(var(--ck-spacing-standard)*3);background:var(--ck-color-base-foreground)}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__icon{min-width:var(--ck-media-embed-placeholder-icon-size);height:var(--ck-media-embed-placeholder-icon-size);margin-bottom:var(--ck-spacing-large);background-position:50%;background-size:cover}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__icon .ck-icon{width:100%;height:100%}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url__text{color:var(--ck-color-media-embed-placeholder-url-text);white-space:nowrap;text-align:center;font-style:italic;text-overflow:ellipsis}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url__text:hover{color:var(--ck-color-media-embed-placeholder-url-text-hover);cursor:pointer;text-decoration:underline}.ck-media__wrapper[data-oembed-url*=\\\"open.spotify.com\\\"]{max-width:300px;max-height:380px}.ck-media__wrapper[data-oembed-url*=\\\"google.com/maps\\\"] .ck-media__placeholder__icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNTAuMzc4IiBoZWlnaHQ9IjI1NC4xNjciIHZpZXdCb3g9IjAgMCA2Ni4yNDYgNjcuMjQ4Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTcyLjUzMSAtMjE4LjQ1NSkgc2NhbGUoLjk4MDEyKSI+PHJlY3Qgcnk9IjUuMjM4IiByeD0iNS4yMzgiIHk9IjIzMS4zOTkiIHg9IjE3Ni4wMzEiIGhlaWdodD0iNjAuMDk5IiB3aWR0aD0iNjAuMDk5IiBmaWxsPSIjMzRhNjY4IiBwYWludC1vcmRlcj0ibWFya2VycyBzdHJva2UgZmlsbCIvPjxwYXRoIGQ9Ik0yMDYuNDc3IDI2MC45bC0yOC45ODcgMjguOTg3YTUuMjE4IDUuMjE4IDAgMDAzLjc4IDEuNjFoNDkuNjIxYzEuNjk0IDAgMy4xOS0uNzk4IDQuMTQ2LTIuMDM3eiIgZmlsbD0iIzVjODhjNSIvPjxwYXRoIGQ9Ik0yMjYuNzQyIDIyMi45ODhjLTkuMjY2IDAtMTYuNzc3IDcuMTctMTYuNzc3IDE2LjAxNC4wMDcgMi43NjIuNjYzIDUuNDc0IDIuMDkzIDcuODc1LjQzLjcwMy44MyAxLjQwOCAxLjE5IDIuMTA3LjMzMy41MDIuNjUgMS4wMDUuOTUgMS41MDguMzQzLjQ3Ny42NzMuOTU3Ljk4OCAxLjQ0IDEuMzEgMS43NjkgMi41IDMuNTAyIDMuNjM3IDUuMTY4Ljc5MyAxLjI3NSAxLjY4MyAyLjY0IDIuNDY2IDMuOTkgMi4zNjMgNC4wOTQgNC4wMDcgOC4wOTIgNC42IDEzLjkxNHYuMDEyYy4xODIuNDEyLjUxNi42NjYuODc5LjY2Ny40MDMtLjAwMS43NjgtLjMxNC45My0uNzk5LjYwMy01Ljc1NiAyLjIzOC05LjcyOSA0LjU4NS0xMy43OTQuNzgyLTEuMzUgMS42NzMtMi43MTUgMi40NjUtMy45OSAxLjEzNy0xLjY2NiAyLjMyOC0zLjQgMy42MzgtNS4xNjkuMzE1LS40ODIuNjQ1LS45NjIuOTg4LTEuNDM5LjMtLjUwMy42MTctMS4wMDYuOTUtMS41MDguMzU5LS43Ljc2LTEuNDA0IDEuMTktMi4xMDcgMS40MjYtMi40MDIgMi01LjExNCAyLjAwNC03Ljg3NSAwLTguODQ0LTcuNTExLTE2LjAxNC0xNi43NzYtMTYuMDE0eiIgZmlsbD0iI2RkNGIzZSIgcGFpbnQtb3JkZXI9Im1hcmtlcnMgc3Ryb2tlIGZpbGwiLz48ZWxsaXBzZSByeT0iNS41NjQiIHJ4PSI1LjgyOCIgY3k9IjIzOS4wMDIiIGN4PSIyMjYuNzQyIiBmaWxsPSIjODAyZDI3IiBwYWludC1vcmRlcj0ibWFya2VycyBzdHJva2UgZmlsbCIvPjxwYXRoIGQ9Ik0xOTAuMzAxIDIzNy4yODNjLTQuNjcgMC04LjQ1NyAzLjg1My04LjQ1NyA4LjYwNnMzLjc4NiA4LjYwNyA4LjQ1NyA4LjYwN2MzLjA0MyAwIDQuODA2LS45NTggNi4zMzctMi41MTYgMS41My0xLjU1NyAyLjA4Ny0zLjkxMyAyLjA4Ny02LjI5IDAtLjM2Mi0uMDIzLS43MjItLjA2NC0xLjA3OWgtOC4yNTd2My4wNDNoNC44NWMtLjE5Ny43NTktLjUzMSAxLjQ1LTEuMDU4IDEuOTg2LS45NDIuOTU4LTIuMDI4IDEuNTQ4LTMuOTAxIDEuNTQ4LTIuODc2IDAtNS4yMDgtMi4zNzItNS4yMDgtNS4yOTkgMC0yLjkyNiAyLjMzMi01LjI5OSA1LjIwOC01LjI5OSAxLjM5OSAwIDIuNjE4LjQwNyAzLjU4NCAxLjI5M2wyLjM4MS0yLjM4YzAtLjAwMi0uMDAzLS4wMDQtLjAwNC0uMDA1LTEuNTg4LTEuNTI0LTMuNjItMi4yMTUtNS45NTUtMi4yMTV6bTQuNDMgNS42NmwuMDAzLjAwNnYtLjAwM3oiIGZpbGw9IiNmZmYiIHBhaW50LW9yZGVyPSJtYXJrZXJzIHN0cm9rZSBmaWxsIi8+PHBhdGggZD0iTTIxNS4xODQgMjUxLjkyOWwtNy45OCA3Ljk3OSAyOC40NzcgMjguNDc1YTUuMjMzIDUuMjMzIDAgMDAuNDQ5LTIuMTIzdi0zMS4xNjVjLS40NjkuNjc1LS45MzQgMS4zNDktMS4zODIgMi4wMDUtLjc5MiAxLjI3NS0xLjY4MiAyLjY0LTIuNDY1IDMuOTktMi4zNDcgNC4wNjUtMy45ODIgOC4wMzgtNC41ODUgMTMuNzk0LS4xNjIuNDg1LS41MjcuNzk4LS45My43OTktLjM2My0uMDAxLS42OTctLjI1NS0uODc5LS42Njd2LS4wMTJjLS41OTMtNS44MjItMi4yMzctOS44Mi00LjYtMTMuOTE0LS43ODMtMS4zNS0xLjY3My0yLjcxNS0yLjQ2Ni0zLjk5LTEuMTM3LTEuNjY2LTIuMzI3LTMuNC0zLjYzNy01LjE2OWwtLjAwMi0uMDAzeiIgZmlsbD0iI2MzYzNjMyIvPjxwYXRoIGQ9Ik0yMTIuOTgzIDI0OC40OTVsLTM2Ljk1MiAzNi45NTN2LjgxMmE1LjIyNyA1LjIyNyAwIDAwNS4yMzggNS4yMzhoMS4wMTVsMzUuNjY2LTM1LjY2NmExMzYuMjc1IDEzNi4yNzUgMCAwMC0yLjc2NC0zLjkgMzcuNTc1IDM3LjU3NSAwIDAwLS45ODktMS40NCAzNS4xMjcgMzUuMTI3IDAgMDAtLjk1LTEuNTA4Yy0uMDgzLS4xNjItLjE3Ni0uMzI2LS4yNjQtLjQ4OXoiIGZpbGw9IiNmZGRjNGYiIHBhaW50LW9yZGVyPSJtYXJrZXJzIHN0cm9rZSBmaWxsIi8+PHBhdGggZD0iTTIxMS45OTggMjYxLjA4M2wtNi4xNTIgNi4xNTEgMjQuMjY0IDI0LjI2NGguNzgxYTUuMjI3IDUuMjI3IDAgMDA1LjIzOS01LjIzOHYtMS4wNDV6IiBmaWxsPSIjZmZmIiBwYWludC1vcmRlcj0ibWFya2VycyBzdHJva2UgZmlsbCIvPjwvZz48L3N2Zz4=)}.ck-media__wrapper[data-oembed-url*=\\\"facebook.com\\\"] .ck-media__placeholder{background:#4268b3}.ck-media__wrapper[data-oembed-url*=\\\"facebook.com\\\"] .ck-media__placeholder .ck-media__placeholder__icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAyNCIgaGVpZ2h0PSIxMDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik05NjcuNDg0IDBINTYuNTE3QzI1LjMwNCAwIDAgMjUuMzA0IDAgNTYuNTE3djkxMC45NjZDMCA5OTguNjk0IDI1LjI5NyAxMDI0IDU2LjUyMiAxMDI0SDU0N1Y2MjhINDE0VjQ3M2gxMzNWMzU5LjAyOWMwLTEzMi4yNjIgODAuNzczLTIwNC4yODIgMTk4Ljc1Ni0yMDQuMjgyIDU2LjUxMyAwIDEwNS4wODYgNC4yMDggMTE5LjI0NCA2LjA4OVYyOTlsLTgxLjYxNi4wMzdjLTYzLjk5MyAwLTc2LjM4NCAzMC40OTItNzYuMzg0IDc1LjIzNlY0NzNoMTUzLjQ4N2wtMTkuOTg2IDE1NUg3MDd2Mzk2aDI2MC40ODRjMzEuMjEzIDAgNTYuNTE2LTI1LjMwMyA1Ni41MTYtNTYuNTE2VjU2LjUxNUMxMDI0IDI1LjMwMyA5OTguNjk3IDAgOTY3LjQ4NCAwIiBmaWxsPSIjRkZGRkZFIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4=)}.ck-media__wrapper[data-oembed-url*=\\\"facebook.com\\\"] .ck-media__placeholder .ck-media__placeholder__url__text{color:#cdf}.ck-media__wrapper[data-oembed-url*=\\\"facebook.com\\\"] .ck-media__placeholder .ck-media__placeholder__url__text:hover{color:#fff}.ck-media__wrapper[data-oembed-url*=\\\"instagram.com\\\"] .ck-media__placeholder{background:linear-gradient(-135deg,#1400c7,#b800b1,#f50000)}.ck-media__wrapper[data-oembed-url*=\\\"instagram.com\\\"] .ck-media__placeholder .ck-media__placeholder__icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTA0IiBoZWlnaHQ9IjUwNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+PGRlZnM+PHBhdGggaWQ9ImEiIGQ9Ik0wIC4xNTloNTAzLjg0MVY1MDMuOTRIMHoiLz48L2RlZnM+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48bWFzayBpZD0iYiIgZmlsbD0iI2ZmZiI+PHVzZSB4bGluazpocmVmPSIjYSIvPjwvbWFzaz48cGF0aCBkPSJNMjUxLjkyMS4xNTljLTY4LjQxOCAwLTc2Ljk5Ny4yOS0xMDMuODY3IDEuNTE2LTI2LjgxNCAxLjIyMy00NS4xMjcgNS40ODItNjEuMTUxIDExLjcxLTE2LjU2NiA2LjQzNy0zMC42MTUgMTUuMDUxLTQ0LjYyMSAyOS4wNTYtMTQuMDA1IDE0LjAwNi0yMi42MTkgMjguMDU1LTI5LjA1NiA0NC42MjEtNi4yMjggMTYuMDI0LTEwLjQ4NyAzNC4zMzctMTEuNzEgNjEuMTUxQy4yOSAxNzUuMDgzIDAgMTgzLjY2MiAwIDI1Mi4wOGMwIDY4LjQxNy4yOSA3Ni45OTYgMS41MTYgMTAzLjg2NiAxLjIyMyAyNi44MTQgNS40ODIgNDUuMTI3IDExLjcxIDYxLjE1MSA2LjQzNyAxNi41NjYgMTUuMDUxIDMwLjYxNSAyOS4wNTYgNDQuNjIxIDE0LjAwNiAxNC4wMDUgMjguMDU1IDIyLjYxOSA0NC42MjEgMjkuMDU3IDE2LjAyNCA2LjIyNyAzNC4zMzcgMTAuNDg2IDYxLjE1MSAxMS43MDkgMjYuODcgMS4yMjYgMzUuNDQ5IDEuNTE2IDEwMy44NjcgMS41MTYgNjguNDE3IDAgNzYuOTk2LS4yOSAxMDMuODY2LTEuNTE2IDI2LjgxNC0xLjIyMyA0NS4xMjctNS40ODIgNjEuMTUxLTExLjcwOSAxNi41NjYtNi40MzggMzAuNjE1LTE1LjA1MiA0NC42MjEtMjkuMDU3IDE0LjAwNS0xNC4wMDYgMjIuNjE5LTI4LjA1NSAyOS4wNTctNDQuNjIxIDYuMjI3LTE2LjAyNCAxMC40ODYtMzQuMzM3IDExLjcwOS02MS4xNTEgMS4yMjYtMjYuODcgMS41MTYtMzUuNDQ5IDEuNTE2LTEwMy44NjYgMC02OC40MTgtLjI5LTc2Ljk5Ny0xLjUxNi0xMDMuODY3LTEuMjIzLTI2LjgxNC01LjQ4Mi00NS4xMjctMTEuNzA5LTYxLjE1MS02LjQzOC0xNi41NjYtMTUuMDUyLTMwLjYxNS0yOS4wNTctNDQuNjIxLTE0LjAwNi0xNC4wMDUtMjguMDU1LTIyLjYxOS00NC42MjEtMjkuMDU2LTE2LjAyNC02LjIyOC0zNC4zMzctMTAuNDg3LTYxLjE1MS0xMS43MUMzMjguOTE3LjQ0OSAzMjAuMzM4LjE1OSAyNTEuOTIxLjE1OXptMCA0NS4zOTFjNjcuMjY1IDAgNzUuMjMzLjI1NyAxMDEuNzk3IDEuNDY5IDI0LjU2MiAxLjEyIDM3LjkwMSA1LjIyNCA0Ni43NzggOC42NzQgMTEuNzU5IDQuNTcgMjAuMTUxIDEwLjAyOSAyOC45NjYgMTguODQ1IDguODE2IDguODE1IDE0LjI3NSAxNy4yMDcgMTguODQ1IDI4Ljk2NiAzLjQ1IDguODc3IDcuNTU0IDIyLjIxNiA4LjY3NCA0Ni43NzggMS4yMTIgMjYuNTY0IDEuNDY5IDM0LjUzMiAxLjQ2OSAxMDEuNzk4IDAgNjcuMjY1LS4yNTcgNzUuMjMzLTEuNDY5IDEwMS43OTctMS4xMiAyNC41NjItNS4yMjQgMzcuOTAxLTguNjc0IDQ2Ljc3OC00LjU3IDExLjc1OS0xMC4wMjkgMjAuMTUxLTE4Ljg0NSAyOC45NjYtOC44MTUgOC44MTYtMTcuMjA3IDE0LjI3NS0yOC45NjYgMTguODQ1LTguODc3IDMuNDUtMjIuMjE2IDcuNTU0LTQ2Ljc3OCA4LjY3NC0yNi41NiAxLjIxMi0zNC41MjcgMS40NjktMTAxLjc5NyAxLjQ2OS02Ny4yNzEgMC03NS4yMzctLjI1Ny0xMDEuNzk4LTEuNDY5LTI0LjU2Mi0xLjEyLTM3LjkwMS01LjIyNC00Ni43NzgtOC42NzQtMTEuNzU5LTQuNTctMjAuMTUxLTEwLjAyOS0yOC45NjYtMTguODQ1LTguODE1LTguODE1LTE0LjI3NS0xNy4yMDctMTguODQ1LTI4Ljk2Ni0zLjQ1LTguODc3LTcuNTU0LTIyLjIxNi04LjY3NC00Ni43NzgtMS4yMTItMjYuNTY0LTEuNDY5LTM0LjUzMi0xLjQ2OS0xMDEuNzk3IDAtNjcuMjY2LjI1Ny03NS4yMzQgMS40NjktMTAxLjc5OCAxLjEyLTI0LjU2MiA1LjIyNC0zNy45MDEgOC42NzQtNDYuNzc4IDQuNTctMTEuNzU5IDEwLjAyOS0yMC4xNTEgMTguODQ1LTI4Ljk2NiA4LjgxNS04LjgxNiAxNy4yMDctMTQuMjc1IDI4Ljk2Ni0xOC44NDUgOC44NzctMy40NSAyMi4yMTYtNy41NTQgNDYuNzc4LTguNjc0IDI2LjU2NC0xLjIxMiAzNC41MzItMS40NjkgMTAxLjc5OC0xLjQ2OXoiIGZpbGw9IiNGRkYiIG1hc2s9InVybCgjYikiLz48cGF0aCBkPSJNMjUxLjkyMSAzMzYuMDUzYy00Ni4zNzggMC04My45NzQtMzcuNTk2LTgzLjk3NC04My45NzMgMC00Ni4zNzggMzcuNTk2LTgzLjk3NCA4My45NzQtODMuOTc0IDQ2LjM3NyAwIDgzLjk3MyAzNy41OTYgODMuOTczIDgzLjk3NCAwIDQ2LjM3Ny0zNy41OTYgODMuOTczLTgzLjk3MyA4My45NzN6bTAtMjEzLjMzOGMtNzEuNDQ3IDAtMTI5LjM2NSA1Ny45MTgtMTI5LjM2NSAxMjkuMzY1IDAgNzEuNDQ2IDU3LjkxOCAxMjkuMzY0IDEyOS4zNjUgMTI5LjM2NCA3MS40NDYgMCAxMjkuMzY0LTU3LjkxOCAxMjkuMzY0LTEyOS4zNjQgMC03MS40NDctNTcuOTE4LTEyOS4zNjUtMTI5LjM2NC0xMjkuMzY1ek00MTYuNjI3IDExNy42MDRjMCAxNi42OTYtMTMuNTM1IDMwLjIzLTMwLjIzMSAzMC4yMy0xNi42OTUgMC0zMC4yMy0xMy41MzQtMzAuMjMtMzAuMjMgMC0xNi42OTYgMTMuNTM1LTMwLjIzMSAzMC4yMy0zMC4yMzEgMTYuNjk2IDAgMzAuMjMxIDEzLjUzNSAzMC4yMzEgMzAuMjMxIiBmaWxsPSIjRkZGIi8+PC9nPjwvc3ZnPg==)}.ck-media__wrapper[data-oembed-url*=\\\"instagram.com\\\"] .ck-media__placeholder .ck-media__placeholder__url__text{color:#ffe0fe}.ck-media__wrapper[data-oembed-url*=\\\"instagram.com\\\"] .ck-media__placeholder .ck-media__placeholder__url__text:hover{color:#fff}.ck-media__wrapper[data-oembed-url*=\\\"twitter.com\\\"] .ck.ck-media__placeholder{background:linear-gradient(90deg,#71c6f4,#0d70a5)}.ck-media__wrapper[data-oembed-url*=\\\"twitter.com\\\"] .ck.ck-media__placeholder .ck-media__placeholder__icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MDAgNDAwIj48cGF0aCBkPSJNNDAwIDIwMGMwIDExMC41LTg5LjUgMjAwLTIwMCAyMDBTMCAzMTAuNSAwIDIwMCA4OS41IDAgMjAwIDBzMjAwIDg5LjUgMjAwIDIwMHpNMTYzLjQgMzA1LjVjODguNyAwIDEzNy4yLTczLjUgMTM3LjItMTM3LjIgMC0yLjEgMC00LjItLjEtNi4yIDkuNC02LjggMTcuNi0xNS4zIDI0LjEtMjUtOC42IDMuOC0xNy45IDYuNC0yNy43IDcuNiAxMC02IDE3LjYtMTUuNCAyMS4yLTI2LjctOS4zIDUuNS0xOS42IDkuNS0zMC42IDExLjctOC44LTkuNC0yMS4zLTE1LjItMzUuMi0xNS4yLTI2LjYgMC00OC4yIDIxLjYtNDguMiA0OC4yIDAgMy44LjQgNy41IDEuMyAxMS00MC4xLTItNzUuNi0yMS4yLTk5LjQtNTAuNC00LjEgNy4xLTYuNSAxNS40LTYuNSAyNC4yIDAgMTYuNyA4LjUgMzEuNSAyMS41IDQwLjEtNy45LS4yLTE1LjMtMi40LTIxLjgtNnYuNmMwIDIzLjQgMTYuNiA0Mi44IDM4LjcgNDcuMy00IDEuMS04LjMgMS43LTEyLjcgMS43LTMuMSAwLTYuMS0uMy05LjEtLjkgNi4xIDE5LjIgMjMuOSAzMy4xIDQ1IDMzLjUtMTYuNSAxMi45LTM3LjMgMjAuNi01OS45IDIwLjYtMy45IDAtNy43LS4yLTExLjUtLjcgMjEuMSAxMy44IDQ2LjUgMjEuOCA3My43IDIxLjgiIGZpbGw9IiNmZmYiLz48L3N2Zz4=)}.ck-media__wrapper[data-oembed-url*=\\\"twitter.com\\\"] .ck.ck-media__placeholder .ck-media__placeholder__url__text{color:#b8e6ff}.ck-media__wrapper[data-oembed-url*=\\\"twitter.com\\\"] .ck.ck-media__placeholder .ck-media__placeholder__url__text:hover{color:#fff}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./mediaform.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-media-form{display:flex;align-items:flex-start;flex-direction:row;flex-wrap:nowrap}.ck.ck-media-form .ck-labeled-field-view{display:inline-block}.ck.ck-media-form .ck-label{display:none}@media screen and (max-width:600px){.ck.ck-media-form{flex-wrap:wrap}.ck.ck-media-form .ck-labeled-field-view{flex-basis:100%}.ck.ck-media-form .ck-button{flex-basis:50%}}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./mediaembed.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck-content .media{clear:both;margin:1em 0;display:block;min-width:15em}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./tableediting.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \":root{--ck-color-table-focused-cell-background:rgba(158,207,250,0.3)}.ck-widget.table td.ck-editor__nested-editable.ck-editor__nested-editable_focused,.ck-widget.table td.ck-editor__nested-editable:focus,.ck-widget.table th.ck-editor__nested-editable.ck-editor__nested-editable_focused,.ck-widget.table th.ck-editor__nested-editable:focus{background:var(--ck-color-table-focused-cell-background);border-style:none;outline:1px solid var(--ck-color-focus-border);outline-offset:-1px}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./splitbutton.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-splitbutton{font-size:inherit}.ck.ck-splitbutton .ck-splitbutton__action:focus{z-index:calc(var(--ck-z-default) + 1)}.ck.ck-splitbutton.ck-splitbutton_open>.ck-button .ck-tooltip{display:none}:root{--ck-color-split-button-hover-background:#ebebeb;--ck-color-split-button-hover-border:#b3b3b3}[dir=ltr] .ck.ck-splitbutton>.ck-splitbutton__action{border-top-right-radius:unset;border-bottom-right-radius:unset}[dir=rtl] .ck.ck-splitbutton>.ck-splitbutton__action{border-top-left-radius:unset;border-bottom-left-radius:unset}.ck.ck-splitbutton>.ck-splitbutton__arrow{min-width:unset}[dir=ltr] .ck.ck-splitbutton>.ck-splitbutton__arrow{border-radius:0}.ck-rounded-corners [dir=ltr] .ck.ck-splitbutton>.ck-splitbutton__arrow,[dir=ltr] .ck.ck-splitbutton>.ck-splitbutton__arrow.ck-rounded-corners{border-radius:var(--ck-border-radius);border-top-left-radius:unset;border-bottom-left-radius:unset}[dir=rtl] .ck.ck-splitbutton>.ck-splitbutton__arrow{border-top-right-radius:unset;border-bottom-right-radius:unset}.ck.ck-splitbutton>.ck-splitbutton__arrow svg{width:var(--ck-dropdown-arrow-size)}.ck.ck-splitbutton.ck-splitbutton_open>.ck-button:not(.ck-on):not(.ck-disabled):not(:hover),.ck.ck-splitbutton:hover>.ck-button:not(.ck-on):not(.ck-disabled):not(:hover){background:var(--ck-color-split-button-hover-background)}[dir=ltr] .ck.ck-splitbutton.ck-splitbutton_open>.ck-splitbutton__arrow:not(.ck-disabled),[dir=ltr] .ck.ck-splitbutton:hover>.ck-splitbutton__arrow:not(.ck-disabled){border-left-color:var(--ck-color-split-button-hover-border)}[dir=rtl] .ck.ck-splitbutton.ck-splitbutton_open>.ck-splitbutton__arrow:not(.ck-disabled),[dir=rtl] .ck.ck-splitbutton:hover>.ck-splitbutton__arrow:not(.ck-disabled){border-right-color:var(--ck-color-split-button-hover-border)}.ck.ck-splitbutton.ck-splitbutton_open{border-radius:0}.ck-rounded-corners .ck.ck-splitbutton.ck-splitbutton_open,.ck.ck-splitbutton.ck-splitbutton_open.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck-rounded-corners .ck.ck-splitbutton.ck-splitbutton_open>.ck-splitbutton__action,.ck.ck-splitbutton.ck-splitbutton_open.ck-rounded-corners>.ck-splitbutton__action{border-bottom-left-radius:0}.ck-rounded-corners .ck.ck-splitbutton.ck-splitbutton_open>.ck-splitbutton__arrow,.ck.ck-splitbutton.ck-splitbutton_open.ck-rounded-corners>.ck-splitbutton__arrow{border-bottom-right-radius:0}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./inserttable.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck .ck-insert-table-dropdown__grid{display:flex;flex-direction:row;flex-wrap:wrap}:root{--ck-insert-table-dropdown-padding:10px;--ck-insert-table-dropdown-box-height:11px;--ck-insert-table-dropdown-box-width:12px;--ck-insert-table-dropdown-box-margin:1px}.ck .ck-insert-table-dropdown__grid{width:calc(var(--ck-insert-table-dropdown-box-width)*10 + var(--ck-insert-table-dropdown-box-margin)*20 + var(--ck-insert-table-dropdown-padding)*2);padding:var(--ck-insert-table-dropdown-padding) var(--ck-insert-table-dropdown-padding) 0}.ck .ck-insert-table-dropdown__label{text-align:center}.ck .ck-insert-table-dropdown-grid-box{width:var(--ck-insert-table-dropdown-box-width);height:var(--ck-insert-table-dropdown-box-height);margin:var(--ck-insert-table-dropdown-box-margin);border:1px solid var(--ck-color-base-border);border-radius:1px}.ck .ck-insert-table-dropdown-grid-box.ck-on{border-color:var(--ck-color-focus-border);background:var(--ck-color-focus-outer-shadow)}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./tableselection.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \":root{--ck-table-selected-cell-background:rgba(158,207,250,0.3)}.ck.ck-editor__editable .table table td.ck-editor__editable_selected,.ck.ck-editor__editable .table table th.ck-editor__editable_selected{position:relative;caret-color:transparent;outline:unset;box-shadow:unset}.ck.ck-editor__editable .table table td.ck-editor__editable_selected:after,.ck.ck-editor__editable .table table th.ck-editor__editable_selected:after{content:\\\"\\\";pointer-events:none;background-color:var(--ck-table-selected-cell-background);position:absolute;top:0;left:0;right:0;bottom:0}.ck.ck-editor__editable .table table td.ck-editor__editable_selected ::selection,.ck.ck-editor__editable .table table td.ck-editor__editable_selected:focus,.ck.ck-editor__editable .table table th.ck-editor__editable_selected ::selection,.ck.ck-editor__editable .table table th.ck-editor__editable_selected:focus{background-color:transparent}.ck.ck-editor__editable .table table td.ck-editor__editable_selected .ck-widget_selected,.ck.ck-editor__editable .table table th.ck-editor__editable_selected .ck-widget_selected{outline:unset}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n            var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./table.css\");\n\n            content = content.__esModule ? content.default : content;\n\n            if (typeof content === 'string') {\n              content = [[module.id, content, '']];\n            }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck-content .table{margin:1em auto;display:table}.ck-content .table table{border-collapse:collapse;border-spacing:0;width:100%;height:100%;border:1px double #b3b3b3}.ck-content .table table td,.ck-content .table table th{min-width:2em;padding:.4em;border:1px solid #bfbfbf}.ck-content .table table th{font-weight:700;background:hsla(0,0%,0%,5%)}.ck-content[dir=rtl] .table th{text-align:right}.ck-content[dir=ltr] .table th{text-align:left}\"","import root from './_root.js';\n\n/** Built-in value references. */\nvar Symbol = root.Symbol;\n\nexport default Symbol;\n","import Symbol from './_Symbol.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.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 */\nvar nativeObjectToString = objectProto.toString;\n\n/** Built-in value references. */\nvar symToStringTag = 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 */\nfunction getRawTag(value) {\n  var isOwn = hasOwnProperty.call(value, symToStringTag),\n      tag = value[symToStringTag];\n\n  try {\n    value[symToStringTag] = undefined;\n    var unmasked = true;\n  } catch (e) {}\n\n  var result = nativeObjectToString.call(value);\n  if (unmasked) {\n    if (isOwn) {\n      value[symToStringTag] = tag;\n    } else {\n      delete value[symToStringTag];\n    }\n  }\n  return result;\n}\n\nexport default getRawTag;\n","/** Used for built-in method references. */\nvar objectProto = 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 */\nvar nativeObjectToString = objectProto.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 */\nfunction objectToString(value) {\n  return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","import Symbol from './_Symbol.js';\nimport getRawTag from './_getRawTag.js';\nimport objectToString from './_objectToString.js';\n\n/** `Object#toString` result references. */\nvar nullTag = '[object Null]',\n    undefinedTag = '[object Undefined]';\n\n/** Built-in value references. */\nvar 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 */\nfunction 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\nexport default baseGetTag;\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n  return function(arg) {\n    return func(transform(arg));\n  };\n}\n\nexport default overArg;\n","import overArg from './_overArg.js';\n\n/** Built-in value references. */\nvar getPrototype = overArg(Object.getPrototypeOf, Object);\n\nexport default getPrototype;\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 */\nfunction isObjectLike(value) {\n  return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","import baseGetTag from './_baseGetTag.js';\nimport getPrototype from './_getPrototype.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar objectTag = '[object Object]';\n\n/** Used for built-in method references. */\nvar funcProto = Function.prototype,\n    objectProto = Object.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Used to infer the `Object` constructor. */\nvar objectCtorString = funcToString.call(Object);\n\n/**\n * Checks if `value` is a plain object, that is, an object created by the\n * `Object` constructor or one with a `[[Prototype]]` of `null`.\n *\n * @static\n * @memberOf _\n * @since 0.8.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.\n * @example\n *\n * function Foo() {\n *   this.a = 1;\n * }\n *\n * _.isPlainObject(new Foo);\n * // => false\n *\n * _.isPlainObject([1, 2, 3]);\n * // => false\n *\n * _.isPlainObject({ 'x': 0, 'y': 0 });\n * // => true\n *\n * _.isPlainObject(Object.create(null));\n * // => true\n */\nfunction isPlainObject(value) {\n  if (!isObjectLike(value) || baseGetTag(value) != objectTag) {\n    return false;\n  }\n  var proto = getPrototype(value);\n  if (proto === null) {\n    return true;\n  }\n  var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;\n  return typeof Ctor == 'function' && Ctor instanceof Ctor &&\n    funcToString.call(Ctor) == objectCtorString;\n}\n\nexport default isPlainObject;\n","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n  this.__data__ = [];\n  this.size = 0;\n}\n\nexport default listCacheClear;\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 */\nfunction eq(value, other) {\n  return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","import eq from './eq.js';\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 */\nfunction assocIndexOf(array, key) {\n  var length = array.length;\n  while (length--) {\n    if (eq(array[length][0], key)) {\n      return length;\n    }\n  }\n  return -1;\n}\n\nexport default assocIndexOf;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/** Used for built-in method references. */\nvar arrayProto = Array.prototype;\n\n/** Built-in value references. */\nvar 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 */\nfunction 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\nexport default listCacheDelete;\n","import assocIndexOf from './_assocIndexOf.js';\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 */\nfunction listCacheGet(key) {\n  var data = this.__data__,\n      index = assocIndexOf(data, key);\n\n  return index < 0 ? undefined : data[index][1];\n}\n\nexport default listCacheGet;\n","import assocIndexOf from './_assocIndexOf.js';\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 */\nfunction listCacheHas(key) {\n  return assocIndexOf(this.__data__, key) > -1;\n}\n\nexport default listCacheHas;\n","import assocIndexOf from './_assocIndexOf.js';\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 */\nfunction 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\nexport default listCacheSet;\n","import listCacheClear from './_listCacheClear.js';\nimport listCacheDelete from './_listCacheDelete.js';\nimport listCacheGet from './_listCacheGet.js';\nimport listCacheHas from './_listCacheHas.js';\nimport listCacheSet from './_listCacheSet.js';\n\n/**\n * Creates an list cache object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction 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`.\nListCache.prototype.clear = listCacheClear;\nListCache.prototype['delete'] = listCacheDelete;\nListCache.prototype.get = listCacheGet;\nListCache.prototype.has = listCacheHas;\nListCache.prototype.set = listCacheSet;\n\nexport default ListCache;\n","import ListCache from './_ListCache.js';\n\n/**\n * Removes all key-value entries from the stack.\n *\n * @private\n * @name clear\n * @memberOf Stack\n */\nfunction stackClear() {\n  this.__data__ = new ListCache;\n  this.size = 0;\n}\n\nexport default stackClear;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n  var data = this.__data__,\n      result = data['delete'](key);\n\n  this.size = data.size;\n  return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n  return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\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 */\nfunction stackHas(key) {\n  return this.__data__.has(key);\n}\n\nexport default stackHas;\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 */\nfunction isObject(value) {\n  var type = typeof value;\n  return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","import baseGetTag from './_baseGetTag.js';\nimport isObject from './isObject.js';\n\n/** `Object#toString` result references. */\nvar 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 */\nfunction isFunction(value) {\n  if (!isObject(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\nexport default isFunction;\n","import coreJsData from './_coreJsData.js';\n\n/** Used to detect methods masquerading as native. */\nvar 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 */\nfunction isMasked(func) {\n  return !!maskSrcKey && (maskSrcKey in func);\n}\n\nexport default isMasked;\n","import root from './_root.js';\n\n/** Used to detect overreaching core-js shims. */\nvar coreJsData = root['__core-js_shared__'];\n\nexport default coreJsData;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.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 */\nfunction toSource(func) {\n  if (func != null) {\n    try {\n      return funcToString.call(func);\n    } catch (e) {}\n    try {\n      return (func + '');\n    } catch (e) {}\n  }\n  return '';\n}\n\nexport default toSource;\n","import isFunction from './isFunction.js';\nimport isMasked from './_isMasked.js';\nimport isObject from './isObject.js';\nimport toSource from './_toSource.js';\n\n/**\n * Used to match `RegExp`\n * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).\n */\nvar reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g;\n\n/** Used to detect host constructors (Safari). */\nvar reIsHostCtor = /^\\[object .+?Constructor\\]$/;\n\n/** Used for built-in method references. */\nvar funcProto = Function.prototype,\n    objectProto = Object.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Used to detect if a method is native. */\nvar reIsNative = RegExp('^' +\n  funcToString.call(hasOwnProperty).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 */\nfunction baseIsNative(value) {\n  if (!isObject(value) || isMasked(value)) {\n    return false;\n  }\n  var pattern = isFunction(value) ? reIsNative : reIsHostCtor;\n  return pattern.test(toSource(value));\n}\n\nexport default baseIsNative;\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 */\nfunction getValue(object, key) {\n  return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","import baseIsNative from './_baseIsNative.js';\nimport getValue from './_getValue.js';\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 */\nfunction getNative(object, key) {\n  var value = getValue(object, key);\n  return baseIsNative(value) ? value : undefined;\n}\n\nexport default getNative;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar Map = getNative(root, 'Map');\n\nexport default Map;\n","import getNative from './_getNative.js';\n\n/* Built-in method references that are verified to be native. */\nvar nativeCreate = getNative(Object, 'create');\n\nexport default nativeCreate;\n","import nativeCreate from './_nativeCreate.js';\n\n/**\n * Removes all key-value entries from the hash.\n *\n * @private\n * @name clear\n * @memberOf Hash\n */\nfunction hashClear() {\n  this.__data__ = nativeCreate ? nativeCreate(null) : {};\n  this.size = 0;\n}\n\nexport default hashClear;\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 */\nfunction hashDelete(key) {\n  var result = this.has(key) && delete this.__data__[key];\n  this.size -= result ? 1 : 0;\n  return result;\n}\n\nexport default hashDelete;\n","import nativeCreate from './_nativeCreate.js';\n\n/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.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 */\nfunction hashGet(key) {\n  var data = this.__data__;\n  if (nativeCreate) {\n    var result = data[key];\n    return result === HASH_UNDEFINED ? undefined : result;\n  }\n  return hasOwnProperty.call(data, key) ? data[key] : undefined;\n}\n\nexport default hashGet;\n","import nativeCreate from './_nativeCreate.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.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 */\nfunction hashHas(key) {\n  var data = this.__data__;\n  return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);\n}\n\nexport default hashHas;\n","import nativeCreate from './_nativeCreate.js';\n\n/** Used to stand-in for `undefined` hash values. */\nvar 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 */\nfunction 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\nexport default hashSet;\n","import hashClear from './_hashClear.js';\nimport hashDelete from './_hashDelete.js';\nimport hashGet from './_hashGet.js';\nimport hashHas from './_hashHas.js';\nimport hashSet from './_hashSet.js';\n\n/**\n * Creates a hash object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction 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`.\nHash.prototype.clear = hashClear;\nHash.prototype['delete'] = hashDelete;\nHash.prototype.get = hashGet;\nHash.prototype.has = hashHas;\nHash.prototype.set = hashSet;\n\nexport default Hash;\n","import Hash from './_Hash.js';\nimport ListCache from './_ListCache.js';\nimport Map from './_Map.js';\n\n/**\n * Removes all key-value entries from the map.\n *\n * @private\n * @name clear\n * @memberOf MapCache\n */\nfunction mapCacheClear() {\n  this.size = 0;\n  this.__data__ = {\n    'hash': new Hash,\n    'map': new (Map || ListCache),\n    'string': new Hash\n  };\n}\n\nexport default mapCacheClear;\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 */\nfunction 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\nexport default isKeyable;\n","import isKeyable from './_isKeyable.js';\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 */\nfunction getMapData(map, key) {\n  var data = map.__data__;\n  return isKeyable(key)\n    ? data[typeof key == 'string' ? 'string' : 'hash']\n    : data.map;\n}\n\nexport default getMapData;\n","import getMapData from './_getMapData.js';\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 */\nfunction mapCacheDelete(key) {\n  var result = getMapData(this, key)['delete'](key);\n  this.size -= result ? 1 : 0;\n  return result;\n}\n\nexport default mapCacheDelete;\n","import getMapData from './_getMapData.js';\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 */\nfunction mapCacheGet(key) {\n  return getMapData(this, key).get(key);\n}\n\nexport default mapCacheGet;\n","import getMapData from './_getMapData.js';\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 */\nfunction mapCacheHas(key) {\n  return getMapData(this, key).has(key);\n}\n\nexport default mapCacheHas;\n","import getMapData from './_getMapData.js';\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 */\nfunction 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\nexport default mapCacheSet;\n","import mapCacheClear from './_mapCacheClear.js';\nimport mapCacheDelete from './_mapCacheDelete.js';\nimport mapCacheGet from './_mapCacheGet.js';\nimport mapCacheHas from './_mapCacheHas.js';\nimport mapCacheSet from './_mapCacheSet.js';\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 */\nfunction 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`.\nMapCache.prototype.clear = mapCacheClear;\nMapCache.prototype['delete'] = mapCacheDelete;\nMapCache.prototype.get = mapCacheGet;\nMapCache.prototype.has = mapCacheHas;\nMapCache.prototype.set = mapCacheSet;\n\nexport default MapCache;\n","import ListCache from './_ListCache.js';\nimport Map from './_Map.js';\nimport MapCache from './_MapCache.js';\n\n/** Used as the size to enable large array optimizations. */\nvar LARGE_ARRAY_SIZE = 200;\n\n/**\n * Sets the stack `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Stack\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the stack cache instance.\n */\nfunction stackSet(key, value) {\n  var data = this.__data__;\n  if (data instanceof ListCache) {\n    var pairs = data.__data__;\n    if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {\n      pairs.push([key, value]);\n      this.size = ++data.size;\n      return this;\n    }\n    data = this.__data__ = new MapCache(pairs);\n  }\n  data.set(key, value);\n  this.size = data.size;\n  return this;\n}\n\nexport default stackSet;\n","import ListCache from './_ListCache.js';\nimport stackClear from './_stackClear.js';\nimport stackDelete from './_stackDelete.js';\nimport stackGet from './_stackGet.js';\nimport stackHas from './_stackHas.js';\nimport stackSet from './_stackSet.js';\n\n/**\n * Creates a stack cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Stack(entries) {\n  var data = this.__data__ = new ListCache(entries);\n  this.size = data.size;\n}\n\n// Add methods to `Stack`.\nStack.prototype.clear = stackClear;\nStack.prototype['delete'] = stackDelete;\nStack.prototype.get = stackGet;\nStack.prototype.has = stackHas;\nStack.prototype.set = stackSet;\n\nexport default Stack;\n","/**\n * A specialized version of `_.forEach` for arrays without support for\n * iteratee 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 `array`.\n */\nfunction arrayEach(array, iteratee) {\n  var index = -1,\n      length = array == null ? 0 : array.length;\n\n  while (++index < length) {\n    if (iteratee(array[index], index, array) === false) {\n      break;\n    }\n  }\n  return array;\n}\n\nexport default arrayEach;\n","import getNative from './_getNative.js';\n\nvar defineProperty = (function() {\n  try {\n    var func = getNative(Object, 'defineProperty');\n    func({}, '', {});\n    return func;\n  } catch (e) {}\n}());\n\nexport default defineProperty;\n","import defineProperty from './_defineProperty.js';\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 */\nfunction 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\nexport default baseAssignValue;\n","import baseAssignValue from './_baseAssignValue.js';\nimport eq from './eq.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar 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 */\nfunction assignValue(object, key, value) {\n  var objValue = object[key];\n  if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||\n      (value === undefined && !(key in object))) {\n    baseAssignValue(object, key, value);\n  }\n}\n\nexport default assignValue;\n","import assignValue from './_assignValue.js';\nimport baseAssignValue from './_baseAssignValue.js';\n\n/**\n * Copies properties of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy properties from.\n * @param {Array} props The property identifiers to copy.\n * @param {Object} [object={}] The object to copy properties to.\n * @param {Function} [customizer] The function to customize copied values.\n * @returns {Object} Returns `object`.\n */\nfunction copyObject(source, props, object, customizer) {\n  var isNew = !object;\n  object || (object = {});\n\n  var index = -1,\n      length = props.length;\n\n  while (++index < length) {\n    var key = props[index];\n\n    var newValue = customizer\n      ? customizer(object[key], source[key], key, object, source)\n      : undefined;\n\n    if (newValue === undefined) {\n      newValue = source[key];\n    }\n    if (isNew) {\n      baseAssignValue(object, key, newValue);\n    } else {\n      assignValue(object, key, newValue);\n    }\n  }\n  return object;\n}\n\nexport default copyObject;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n  var index = -1,\n      result = Array(n);\n\n  while (++index < n) {\n    result[index] = iteratee(index);\n  }\n  return result;\n}\n\nexport default baseTimes;\n","import baseGetTag from './_baseGetTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]';\n\n/**\n * The base implementation of `_.isArguments`.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n */\nfunction baseIsArguments(value) {\n  return isObjectLike(value) && baseGetTag(value) == argsTag;\n}\n\nexport default baseIsArguments;\n","import baseIsArguments from './_baseIsArguments.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Built-in value references. */\nvar propertyIsEnumerable = objectProto.propertyIsEnumerable;\n\n/**\n * Checks if `value` is likely an `arguments` 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 `arguments` object,\n *  else `false`.\n * @example\n *\n * _.isArguments(function() { return arguments; }());\n * // => true\n *\n * _.isArguments([1, 2, 3]);\n * // => false\n */\nvar isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {\n  return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&\n    !propertyIsEnumerable.call(value, 'callee');\n};\n\nexport default isArguments;\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 */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar 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 */\nfunction 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\nexport default isIndex;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\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 valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n  return typeof value == 'number' &&\n    value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","import baseGetTag from './_baseGetTag.js';\nimport isLength from './isLength.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n    arrayTag = '[object Array]',\n    boolTag = '[object Boolean]',\n    dateTag = '[object Date]',\n    errorTag = '[object Error]',\n    funcTag = '[object Function]',\n    mapTag = '[object Map]',\n    numberTag = '[object Number]',\n    objectTag = '[object Object]',\n    regexpTag = '[object RegExp]',\n    setTag = '[object Set]',\n    stringTag = '[object String]',\n    weakMapTag = '[object WeakMap]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n    dataViewTag = '[object DataView]',\n    float32Tag = '[object Float32Array]',\n    float64Tag = '[object Float64Array]',\n    int8Tag = '[object Int8Array]',\n    int16Tag = '[object Int16Array]',\n    int32Tag = '[object Int32Array]',\n    uint8Tag = '[object Uint8Array]',\n    uint8ClampedTag = '[object Uint8ClampedArray]',\n    uint16Tag = '[object Uint16Array]',\n    uint32Tag = '[object Uint32Array]';\n\n/** Used to identify `toStringTag` values of typed arrays. */\nvar typedArrayTags = {};\ntypedArrayTags[float32Tag] = typedArrayTags[float64Tag] =\ntypedArrayTags[int8Tag] = typedArrayTags[int16Tag] =\ntypedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =\ntypedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =\ntypedArrayTags[uint32Tag] = true;\ntypedArrayTags[argsTag] = typedArrayTags[arrayTag] =\ntypedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =\ntypedArrayTags[dataViewTag] = typedArrayTags[dateTag] =\ntypedArrayTags[errorTag] = typedArrayTags[funcTag] =\ntypedArrayTags[mapTag] = typedArrayTags[numberTag] =\ntypedArrayTags[objectTag] = typedArrayTags[regexpTag] =\ntypedArrayTags[setTag] = typedArrayTags[stringTag] =\ntypedArrayTags[weakMapTag] = false;\n\n/**\n * The base implementation of `_.isTypedArray` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n */\nfunction baseIsTypedArray(value) {\n  return isObjectLike(value) &&\n    isLength(value.length) && !!typedArrayTags[baseGetTag(value)];\n}\n\nexport default baseIsTypedArray;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n  return function(value) {\n    return func(value);\n  };\n}\n\nexport default baseUnary;\n","import baseIsTypedArray from './_baseIsTypedArray.js';\nimport baseUnary from './_baseUnary.js';\nimport nodeUtil from './_nodeUtil.js';\n\n/* Node.js helper references. */\nvar nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;\n\n/**\n * Checks if `value` is classified as a typed array.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n * @example\n *\n * _.isTypedArray(new Uint8Array);\n * // => true\n *\n * _.isTypedArray([]);\n * // => false\n */\nvar isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;\n\nexport default isTypedArray;\n","import baseTimes from './_baseTimes.js';\nimport isArguments from './isArguments.js';\nimport isArray from './isArray.js';\nimport isBuffer from './isBuffer.js';\nimport isIndex from './_isIndex.js';\nimport isTypedArray from './isTypedArray.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Creates an array of the enumerable property names of the array-like `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @param {boolean} inherited Specify returning inherited property names.\n * @returns {Array} Returns the array of property names.\n */\nfunction arrayLikeKeys(value, inherited) {\n  var isArr = isArray(value),\n      isArg = !isArr && isArguments(value),\n      isBuff = !isArr && !isArg && isBuffer(value),\n      isType = !isArr && !isArg && !isBuff && isTypedArray(value),\n      skipIndexes = isArr || isArg || isBuff || isType,\n      result = skipIndexes ? baseTimes(value.length, String) : [],\n      length = result.length;\n\n  for (var key in value) {\n    if ((inherited || hasOwnProperty.call(value, key)) &&\n        !(skipIndexes && (\n           // Safari 9 has enumerable `arguments.length` in strict mode.\n           key == 'length' ||\n           // Node.js 0.10 has enumerable non-index properties on buffers.\n           (isBuff && (key == 'offset' || key == 'parent')) ||\n           // PhantomJS 2 has enumerable non-index properties on typed arrays.\n           (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||\n           // Skip index properties.\n           isIndex(key, length)\n        ))) {\n      result.push(key);\n    }\n  }\n  return result;\n}\n\nexport default arrayLikeKeys;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n  var Ctor = value && value.constructor,\n      proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n  return value === proto;\n}\n\nexport default isPrototype;\n","import overArg from './_overArg.js';\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeKeys = overArg(Object.keys, Object);\n\nexport default nativeKeys;\n","import isPrototype from './_isPrototype.js';\nimport nativeKeys from './_nativeKeys.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeys(object) {\n  if (!isPrototype(object)) {\n    return nativeKeys(object);\n  }\n  var result = [];\n  for (var key in Object(object)) {\n    if (hasOwnProperty.call(object, key) && key != 'constructor') {\n      result.push(key);\n    }\n  }\n  return result;\n}\n\nexport default baseKeys;\n","import isFunction from './isFunction.js';\nimport isLength from './isLength.js';\n\n/**\n * Checks if `value` is array-like. A value is considered array-like if it's\n * not a function and has a `value.length` that's an integer greater than or\n * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.\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 array-like, else `false`.\n * @example\n *\n * _.isArrayLike([1, 2, 3]);\n * // => true\n *\n * _.isArrayLike(document.body.children);\n * // => true\n *\n * _.isArrayLike('abc');\n * // => true\n *\n * _.isArrayLike(_.noop);\n * // => false\n */\nfunction isArrayLike(value) {\n  return value != null && isLength(value.length) && !isFunction(value);\n}\n\nexport default isArrayLike;\n","import arrayLikeKeys from './_arrayLikeKeys.js';\nimport baseKeys from './_baseKeys.js';\nimport isArrayLike from './isArrayLike.js';\n\n/**\n * Creates an array of the own enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects. See the\n * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * for more details.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n *   this.a = 1;\n *   this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keys(new Foo);\n * // => ['a', 'b'] (iteration order is not guaranteed)\n *\n * _.keys('hi');\n * // => ['0', '1']\n */\nfunction keys(object) {\n  return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);\n}\n\nexport default keys;\n","import copyObject from './_copyObject.js';\nimport keys from './keys.js';\n\n/**\n * The base implementation of `_.assign` without support for multiple sources\n * or `customizer` functions.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @returns {Object} Returns `object`.\n */\nfunction baseAssign(object, source) {\n  return object && copyObject(source, keys(source), object);\n}\n\nexport default baseAssign;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n  var result = [];\n  if (object != null) {\n    for (var key in Object(object)) {\n      result.push(key);\n    }\n  }\n  return result;\n}\n\nexport default nativeKeysIn;\n","import isObject from './isObject.js';\nimport isPrototype from './_isPrototype.js';\nimport nativeKeysIn from './_nativeKeysIn.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeysIn(object) {\n  if (!isObject(object)) {\n    return nativeKeysIn(object);\n  }\n  var isProto = isPrototype(object),\n      result = [];\n\n  for (var key in object) {\n    if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {\n      result.push(key);\n    }\n  }\n  return result;\n}\n\nexport default baseKeysIn;\n","import arrayLikeKeys from './_arrayLikeKeys.js';\nimport baseKeysIn from './_baseKeysIn.js';\nimport isArrayLike from './isArrayLike.js';\n\n/**\n * Creates an array of the own and inherited enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n *   this.a = 1;\n *   this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keysIn(new Foo);\n * // => ['a', 'b', 'c'] (iteration order is not guaranteed)\n */\nfunction keysIn(object) {\n  return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);\n}\n\nexport default keysIn;\n","import copyObject from './_copyObject.js';\nimport keysIn from './keysIn.js';\n\n/**\n * The base implementation of `_.assignIn` without support for multiple sources\n * or `customizer` functions.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @returns {Object} Returns `object`.\n */\nfunction baseAssignIn(object, source) {\n  return object && copyObject(source, keysIn(source), object);\n}\n\nexport default baseAssignIn;\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 */\nfunction 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\nexport default copyArray;\n","/**\n * A specialized version of `_.filter` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n */\nfunction arrayFilter(array, predicate) {\n  var index = -1,\n      length = array == null ? 0 : array.length,\n      resIndex = 0,\n      result = [];\n\n  while (++index < length) {\n    var value = array[index];\n    if (predicate(value, index, array)) {\n      result[resIndex++] = value;\n    }\n  }\n  return result;\n}\n\nexport default arrayFilter;\n","/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n  return [];\n}\n\nexport default stubArray;\n","import arrayFilter from './_arrayFilter.js';\nimport stubArray from './stubArray.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Built-in value references. */\nvar propertyIsEnumerable = objectProto.propertyIsEnumerable;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeGetSymbols = Object.getOwnPropertySymbols;\n\n/**\n * Creates an array of the own enumerable symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of symbols.\n */\nvar getSymbols = !nativeGetSymbols ? stubArray : function(object) {\n  if (object == null) {\n    return [];\n  }\n  object = Object(object);\n  return arrayFilter(nativeGetSymbols(object), function(symbol) {\n    return propertyIsEnumerable.call(object, symbol);\n  });\n};\n\nexport default getSymbols;\n","import copyObject from './_copyObject.js';\nimport getSymbols from './_getSymbols.js';\n\n/**\n * Copies own symbols of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy symbols from.\n * @param {Object} [object={}] The object to copy symbols to.\n * @returns {Object} Returns `object`.\n */\nfunction copySymbols(source, object) {\n  return copyObject(source, getSymbols(source), object);\n}\n\nexport default copySymbols;\n","/**\n * Appends the elements of `values` to `array`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns `array`.\n */\nfunction arrayPush(array, values) {\n  var index = -1,\n      length = values.length,\n      offset = array.length;\n\n  while (++index < length) {\n    array[offset + index] = values[index];\n  }\n  return array;\n}\n\nexport default arrayPush;\n","import arrayPush from './_arrayPush.js';\nimport getPrototype from './_getPrototype.js';\nimport getSymbols from './_getSymbols.js';\nimport stubArray from './stubArray.js';\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeGetSymbols = Object.getOwnPropertySymbols;\n\n/**\n * Creates an array of the own and inherited enumerable symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of symbols.\n */\nvar getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) {\n  var result = [];\n  while (object) {\n    arrayPush(result, getSymbols(object));\n    object = getPrototype(object);\n  }\n  return result;\n};\n\nexport default getSymbolsIn;\n","import copyObject from './_copyObject.js';\nimport getSymbolsIn from './_getSymbolsIn.js';\n\n/**\n * Copies own and inherited symbols of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy symbols from.\n * @param {Object} [object={}] The object to copy symbols to.\n * @returns {Object} Returns `object`.\n */\nfunction copySymbolsIn(source, object) {\n  return copyObject(source, getSymbolsIn(source), object);\n}\n\nexport default copySymbolsIn;\n","import arrayPush from './_arrayPush.js';\nimport isArray from './isArray.js';\n\n/**\n * The base implementation of `getAllKeys` and `getAllKeysIn` which uses\n * `keysFunc` and `symbolsFunc` to get the enumerable property names and\n * symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Function} keysFunc The function to get the keys of `object`.\n * @param {Function} symbolsFunc The function to get the symbols of `object`.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction baseGetAllKeys(object, keysFunc, symbolsFunc) {\n  var result = keysFunc(object);\n  return isArray(object) ? result : arrayPush(result, symbolsFunc(object));\n}\n\nexport default baseGetAllKeys;\n","import baseGetAllKeys from './_baseGetAllKeys.js';\nimport getSymbols from './_getSymbols.js';\nimport keys from './keys.js';\n\n/**\n * Creates an array of own enumerable property names and symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction getAllKeys(object) {\n  return baseGetAllKeys(object, keys, getSymbols);\n}\n\nexport default getAllKeys;\n","import baseGetAllKeys from './_baseGetAllKeys.js';\nimport getSymbolsIn from './_getSymbolsIn.js';\nimport keysIn from './keysIn.js';\n\n/**\n * Creates an array of own and inherited enumerable property names and\n * symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction getAllKeysIn(object) {\n  return baseGetAllKeys(object, keysIn, getSymbolsIn);\n}\n\nexport default getAllKeysIn;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar DataView = getNative(root, 'DataView');\n\nexport default DataView;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar Promise = getNative(root, 'Promise');\n\nexport default Promise;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar Set = getNative(root, 'Set');\n\nexport default Set;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar WeakMap = getNative(root, 'WeakMap');\n\nexport default WeakMap;\n","import DataView from './_DataView.js';\nimport Map from './_Map.js';\nimport Promise from './_Promise.js';\nimport Set from './_Set.js';\nimport WeakMap from './_WeakMap.js';\nimport baseGetTag from './_baseGetTag.js';\nimport toSource from './_toSource.js';\n\n/** `Object#toString` result references. */\nvar mapTag = '[object Map]',\n    objectTag = '[object Object]',\n    promiseTag = '[object Promise]',\n    setTag = '[object Set]',\n    weakMapTag = '[object WeakMap]';\n\nvar dataViewTag = '[object DataView]';\n\n/** Used to detect maps, sets, and weakmaps. */\nvar dataViewCtorString = toSource(DataView),\n    mapCtorString = toSource(Map),\n    promiseCtorString = toSource(Promise),\n    setCtorString = toSource(Set),\n    weakMapCtorString = toSource(WeakMap);\n\n/**\n * Gets the `toStringTag` of `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nvar getTag = baseGetTag;\n\n// Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.\nif ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||\n    (Map && getTag(new Map) != mapTag) ||\n    (Promise && getTag(Promise.resolve()) != promiseTag) ||\n    (Set && getTag(new Set) != setTag) ||\n    (WeakMap && getTag(new WeakMap) != weakMapTag)) {\n  getTag = function(value) {\n    var result = baseGetTag(value),\n        Ctor = result == objectTag ? value.constructor : undefined,\n        ctorString = Ctor ? toSource(Ctor) : '';\n\n    if (ctorString) {\n      switch (ctorString) {\n        case dataViewCtorString: return dataViewTag;\n        case mapCtorString: return mapTag;\n        case promiseCtorString: return promiseTag;\n        case setCtorString: return setTag;\n        case weakMapCtorString: return weakMapTag;\n      }\n    }\n    return result;\n  };\n}\n\nexport default getTag;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Initializes an array clone.\n *\n * @private\n * @param {Array} array The array to clone.\n * @returns {Array} Returns the initialized clone.\n */\nfunction initCloneArray(array) {\n  var length = array.length,\n      result = new array.constructor(length);\n\n  // Add properties assigned by `RegExp#exec`.\n  if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {\n    result.index = array.index;\n    result.input = array.input;\n  }\n  return result;\n}\n\nexport default initCloneArray;\n","import root from './_root.js';\n\n/** Built-in value references. */\nvar Uint8Array = root.Uint8Array;\n\nexport default Uint8Array;\n","import Uint8Array from './_Uint8Array.js';\n\n/**\n * Creates a clone of `arrayBuffer`.\n *\n * @private\n * @param {ArrayBuffer} arrayBuffer The array buffer to clone.\n * @returns {ArrayBuffer} Returns the cloned array buffer.\n */\nfunction cloneArrayBuffer(arrayBuffer) {\n  var result = new arrayBuffer.constructor(arrayBuffer.byteLength);\n  new Uint8Array(result).set(new Uint8Array(arrayBuffer));\n  return result;\n}\n\nexport default cloneArrayBuffer;\n","import cloneArrayBuffer from './_cloneArrayBuffer.js';\n\n/**\n * Creates a clone of `dataView`.\n *\n * @private\n * @param {Object} dataView The data view to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned data view.\n */\nfunction cloneDataView(dataView, isDeep) {\n  var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;\n  return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);\n}\n\nexport default cloneDataView;\n","/** Used to match `RegExp` flags from their coerced string values. */\nvar reFlags = /\\w*$/;\n\n/**\n * Creates a clone of `regexp`.\n *\n * @private\n * @param {Object} regexp The regexp to clone.\n * @returns {Object} Returns the cloned regexp.\n */\nfunction cloneRegExp(regexp) {\n  var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));\n  result.lastIndex = regexp.lastIndex;\n  return result;\n}\n\nexport default cloneRegExp;\n","import Symbol from './_Symbol.js';\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n    symbolValueOf = symbolProto ? symbolProto.valueOf : undefined;\n\n/**\n * Creates a clone of the `symbol` object.\n *\n * @private\n * @param {Object} symbol The symbol object to clone.\n * @returns {Object} Returns the cloned symbol object.\n */\nfunction cloneSymbol(symbol) {\n  return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};\n}\n\nexport default cloneSymbol;\n","import cloneArrayBuffer from './_cloneArrayBuffer.js';\n\n/**\n * Creates a clone of `typedArray`.\n *\n * @private\n * @param {Object} typedArray The typed array to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned typed array.\n */\nfunction cloneTypedArray(typedArray, isDeep) {\n  var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;\n  return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);\n}\n\nexport default cloneTypedArray;\n","import cloneArrayBuffer from './_cloneArrayBuffer.js';\nimport cloneDataView from './_cloneDataView.js';\nimport cloneRegExp from './_cloneRegExp.js';\nimport cloneSymbol from './_cloneSymbol.js';\nimport cloneTypedArray from './_cloneTypedArray.js';\n\n/** `Object#toString` result references. */\nvar boolTag = '[object Boolean]',\n    dateTag = '[object Date]',\n    mapTag = '[object Map]',\n    numberTag = '[object Number]',\n    regexpTag = '[object RegExp]',\n    setTag = '[object Set]',\n    stringTag = '[object String]',\n    symbolTag = '[object Symbol]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n    dataViewTag = '[object DataView]',\n    float32Tag = '[object Float32Array]',\n    float64Tag = '[object Float64Array]',\n    int8Tag = '[object Int8Array]',\n    int16Tag = '[object Int16Array]',\n    int32Tag = '[object Int32Array]',\n    uint8Tag = '[object Uint8Array]',\n    uint8ClampedTag = '[object Uint8ClampedArray]',\n    uint16Tag = '[object Uint16Array]',\n    uint32Tag = '[object Uint32Array]';\n\n/**\n * Initializes an object clone based on its `toStringTag`.\n *\n * **Note:** This function only supports cloning values with tags of\n * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`.\n *\n * @private\n * @param {Object} object The object to clone.\n * @param {string} tag The `toStringTag` of the object to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the initialized clone.\n */\nfunction initCloneByTag(object, tag, isDeep) {\n  var Ctor = object.constructor;\n  switch (tag) {\n    case arrayBufferTag:\n      return cloneArrayBuffer(object);\n\n    case boolTag:\n    case dateTag:\n      return new Ctor(+object);\n\n    case dataViewTag:\n      return cloneDataView(object, isDeep);\n\n    case float32Tag: case float64Tag:\n    case int8Tag: case int16Tag: case int32Tag:\n    case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:\n      return cloneTypedArray(object, isDeep);\n\n    case mapTag:\n      return new Ctor;\n\n    case numberTag:\n    case stringTag:\n      return new Ctor(object);\n\n    case regexpTag:\n      return cloneRegExp(object);\n\n    case setTag:\n      return new Ctor;\n\n    case symbolTag:\n      return cloneSymbol(object);\n  }\n}\n\nexport default initCloneByTag;\n","import isObject from './isObject.js';\n\n/** Built-in value references. */\nvar objectCreate = Object.create;\n\n/**\n * The base implementation of `_.create` without support for assigning\n * properties to the created object.\n *\n * @private\n * @param {Object} proto The object to inherit from.\n * @returns {Object} Returns the new object.\n */\nvar baseCreate = (function() {\n  function object() {}\n  return function(proto) {\n    if (!isObject(proto)) {\n      return {};\n    }\n    if (objectCreate) {\n      return objectCreate(proto);\n    }\n    object.prototype = proto;\n    var result = new object;\n    object.prototype = undefined;\n    return result;\n  };\n}());\n\nexport default baseCreate;\n","import baseCreate from './_baseCreate.js';\nimport getPrototype from './_getPrototype.js';\nimport isPrototype from './_isPrototype.js';\n\n/**\n * Initializes an object clone.\n *\n * @private\n * @param {Object} object The object to clone.\n * @returns {Object} Returns the initialized clone.\n */\nfunction initCloneObject(object) {\n  return (typeof object.constructor == 'function' && !isPrototype(object))\n    ? baseCreate(getPrototype(object))\n    : {};\n}\n\nexport default initCloneObject;\n","import getTag from './_getTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar mapTag = '[object Map]';\n\n/**\n * The base implementation of `_.isMap` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a map, else `false`.\n */\nfunction baseIsMap(value) {\n  return isObjectLike(value) && getTag(value) == mapTag;\n}\n\nexport default baseIsMap;\n","import baseIsMap from './_baseIsMap.js';\nimport baseUnary from './_baseUnary.js';\nimport nodeUtil from './_nodeUtil.js';\n\n/* Node.js helper references. */\nvar nodeIsMap = nodeUtil && nodeUtil.isMap;\n\n/**\n * Checks if `value` is classified as a `Map` object.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a map, else `false`.\n * @example\n *\n * _.isMap(new Map);\n * // => true\n *\n * _.isMap(new WeakMap);\n * // => false\n */\nvar isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap;\n\nexport default isMap;\n","import getTag from './_getTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar setTag = '[object Set]';\n\n/**\n * The base implementation of `_.isSet` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a set, else `false`.\n */\nfunction baseIsSet(value) {\n  return isObjectLike(value) && getTag(value) == setTag;\n}\n\nexport default baseIsSet;\n","import baseIsSet from './_baseIsSet.js';\nimport baseUnary from './_baseUnary.js';\nimport nodeUtil from './_nodeUtil.js';\n\n/* Node.js helper references. */\nvar nodeIsSet = nodeUtil && nodeUtil.isSet;\n\n/**\n * Checks if `value` is classified as a `Set` object.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a set, else `false`.\n * @example\n *\n * _.isSet(new Set);\n * // => true\n *\n * _.isSet(new WeakSet);\n * // => false\n */\nvar isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet;\n\nexport default isSet;\n","import Stack from './_Stack.js';\nimport arrayEach from './_arrayEach.js';\nimport assignValue from './_assignValue.js';\nimport baseAssign from './_baseAssign.js';\nimport baseAssignIn from './_baseAssignIn.js';\nimport cloneBuffer from './_cloneBuffer.js';\nimport copyArray from './_copyArray.js';\nimport copySymbols from './_copySymbols.js';\nimport copySymbolsIn from './_copySymbolsIn.js';\nimport getAllKeys from './_getAllKeys.js';\nimport getAllKeysIn from './_getAllKeysIn.js';\nimport getTag from './_getTag.js';\nimport initCloneArray from './_initCloneArray.js';\nimport initCloneByTag from './_initCloneByTag.js';\nimport initCloneObject from './_initCloneObject.js';\nimport isArray from './isArray.js';\nimport isBuffer from './isBuffer.js';\nimport isMap from './isMap.js';\nimport isObject from './isObject.js';\nimport isSet from './isSet.js';\nimport keys from './keys.js';\n\n/** Used to compose bitmasks for cloning. */\nvar CLONE_DEEP_FLAG = 1,\n    CLONE_FLAT_FLAG = 2,\n    CLONE_SYMBOLS_FLAG = 4;\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n    arrayTag = '[object Array]',\n    boolTag = '[object Boolean]',\n    dateTag = '[object Date]',\n    errorTag = '[object Error]',\n    funcTag = '[object Function]',\n    genTag = '[object GeneratorFunction]',\n    mapTag = '[object Map]',\n    numberTag = '[object Number]',\n    objectTag = '[object Object]',\n    regexpTag = '[object RegExp]',\n    setTag = '[object Set]',\n    stringTag = '[object String]',\n    symbolTag = '[object Symbol]',\n    weakMapTag = '[object WeakMap]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n    dataViewTag = '[object DataView]',\n    float32Tag = '[object Float32Array]',\n    float64Tag = '[object Float64Array]',\n    int8Tag = '[object Int8Array]',\n    int16Tag = '[object Int16Array]',\n    int32Tag = '[object Int32Array]',\n    uint8Tag = '[object Uint8Array]',\n    uint8ClampedTag = '[object Uint8ClampedArray]',\n    uint16Tag = '[object Uint16Array]',\n    uint32Tag = '[object Uint32Array]';\n\n/** Used to identify `toStringTag` values supported by `_.clone`. */\nvar cloneableTags = {};\ncloneableTags[argsTag] = cloneableTags[arrayTag] =\ncloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =\ncloneableTags[boolTag] = cloneableTags[dateTag] =\ncloneableTags[float32Tag] = cloneableTags[float64Tag] =\ncloneableTags[int8Tag] = cloneableTags[int16Tag] =\ncloneableTags[int32Tag] = cloneableTags[mapTag] =\ncloneableTags[numberTag] = cloneableTags[objectTag] =\ncloneableTags[regexpTag] = cloneableTags[setTag] =\ncloneableTags[stringTag] = cloneableTags[symbolTag] =\ncloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =\ncloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;\ncloneableTags[errorTag] = cloneableTags[funcTag] =\ncloneableTags[weakMapTag] = false;\n\n/**\n * The base implementation of `_.clone` and `_.cloneDeep` which tracks\n * traversed objects.\n *\n * @private\n * @param {*} value The value to clone.\n * @param {boolean} bitmask The bitmask flags.\n *  1 - Deep clone\n *  2 - Flatten inherited properties\n *  4 - Clone symbols\n * @param {Function} [customizer] The function to customize cloning.\n * @param {string} [key] The key of `value`.\n * @param {Object} [object] The parent object of `value`.\n * @param {Object} [stack] Tracks traversed objects and their clone counterparts.\n * @returns {*} Returns the cloned value.\n */\nfunction baseClone(value, bitmask, customizer, key, object, stack) {\n  var result,\n      isDeep = bitmask & CLONE_DEEP_FLAG,\n      isFlat = bitmask & CLONE_FLAT_FLAG,\n      isFull = bitmask & CLONE_SYMBOLS_FLAG;\n\n  if (customizer) {\n    result = object ? customizer(value, key, object, stack) : customizer(value);\n  }\n  if (result !== undefined) {\n    return result;\n  }\n  if (!isObject(value)) {\n    return value;\n  }\n  var isArr = isArray(value);\n  if (isArr) {\n    result = initCloneArray(value);\n    if (!isDeep) {\n      return copyArray(value, result);\n    }\n  } else {\n    var tag = getTag(value),\n        isFunc = tag == funcTag || tag == genTag;\n\n    if (isBuffer(value)) {\n      return cloneBuffer(value, isDeep);\n    }\n    if (tag == objectTag || tag == argsTag || (isFunc && !object)) {\n      result = (isFlat || isFunc) ? {} : initCloneObject(value);\n      if (!isDeep) {\n        return isFlat\n          ? copySymbolsIn(value, baseAssignIn(result, value))\n          : copySymbols(value, baseAssign(result, value));\n      }\n    } else {\n      if (!cloneableTags[tag]) {\n        return object ? value : {};\n      }\n      result = initCloneByTag(value, tag, isDeep);\n    }\n  }\n  // Check for circular references and return its corresponding clone.\n  stack || (stack = new Stack);\n  var stacked = stack.get(value);\n  if (stacked) {\n    return stacked;\n  }\n  stack.set(value, result);\n\n  if (isSet(value)) {\n    value.forEach(function(subValue) {\n      result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack));\n    });\n  } else if (isMap(value)) {\n    value.forEach(function(subValue, key) {\n      result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack));\n    });\n  }\n\n  var keysFunc = isFull\n    ? (isFlat ? getAllKeysIn : getAllKeys)\n    : (isFlat ? keysIn : keys);\n\n  var props = isArr ? undefined : keysFunc(value);\n  arrayEach(props || value, function(subValue, key) {\n    if (props) {\n      key = subValue;\n      subValue = value[key];\n    }\n    // Recursively populate clone (susceptible to call stack limits).\n    assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));\n  });\n  return result;\n}\n\nexport default baseClone;\n","import baseClone from './_baseClone.js';\n\n/** Used to compose bitmasks for cloning. */\nvar CLONE_DEEP_FLAG = 1,\n    CLONE_SYMBOLS_FLAG = 4;\n\n/**\n * This method is like `_.cloneWith` except that it recursively clones `value`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to recursively clone.\n * @param {Function} [customizer] The function to customize cloning.\n * @returns {*} Returns the deep cloned value.\n * @see _.cloneWith\n * @example\n *\n * function customizer(value) {\n *   if (_.isElement(value)) {\n *     return value.cloneNode(true);\n *   }\n * }\n *\n * var el = _.cloneDeepWith(document.body, customizer);\n *\n * console.log(el === document.body);\n * // => false\n * console.log(el.nodeName);\n * // => 'BODY'\n * console.log(el.childNodes.length);\n * // => 20\n */\nfunction cloneDeepWith(value, customizer) {\n  customizer = typeof customizer == 'function' ? customizer : undefined;\n  return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer);\n}\n\nexport default cloneDeepWith;\n","import isObjectLike from './isObjectLike.js';\nimport isPlainObject from './isPlainObject.js';\n\n/**\n * Checks if `value` is likely a DOM element.\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 DOM element, else `false`.\n * @example\n *\n * _.isElement(document.body);\n * // => true\n *\n * _.isElement('<body>');\n * // => false\n */\nfunction isElement(value) {\n  return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value);\n}\n\nexport default isElement;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/config\n */\n\nimport { isPlainObject, isElement, cloneDeepWith } from 'lodash-es';\n\n/**\n * Handles a configuration dictionary.\n */\nexport default class Config {\n\t/**\n\t * Creates an instance of the {@link ~Config} class.\n\t *\n\t * @param {Object} [configurations] The initial configurations to be set. Usually, provided by the user.\n\t * @param {Object} [defaultConfigurations] The default configurations. Usually, provided by the system.\n\t */\n\tconstructor( configurations, defaultConfigurations ) {\n\t\t/**\n\t\t * Store for the whole configuration.\n\t\t *\n\t\t * @private\n\t\t * @member {Object}\n\t\t */\n\t\tthis._config = {};\n\n\t\t// Set default configuration.\n\t\tif ( defaultConfigurations ) {\n\t\t\t// Clone the configuration to make sure that the properties will not be shared\n\t\t\t// between editors and make the watchdog feature work correctly.\n\t\t\tthis.define( cloneConfig( defaultConfigurations ) );\n\t\t}\n\n\t\t// Set initial configuration.\n\t\tif ( configurations ) {\n\t\t\tthis._setObjectToTarget( this._config, configurations );\n\t\t}\n\t}\n\n\t/**\n\t * Set configuration values.\n\t *\n\t * It accepts both a name/value pair or an object, which properties and values will be used to set\n\t * configurations.\n\t *\n\t * It also accepts setting a \"deep configuration\" by using dots in the name. For example, `'resize.width'` sets\n\t * the value for the `width` configuration in the `resize` subset.\n\t *\n\t *\t\tconfig.set( 'width', 500 );\n\t *\t\tconfig.set( 'toolbar.collapsed', true );\n\t *\n\t *\t\t// Equivalent to:\n\t *\t\tconfig.set( {\n\t *\t\t\twidth: 500\n\t *\t\t\ttoolbar: {\n\t *\t\t\t\tcollapsed: true\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * Passing an object as the value will amend the configuration, not replace it.\n\t *\n\t *\t\tconfig.set( 'toolbar', {\n\t *\t\t\tcollapsed: true,\n\t *\t\t} );\n\t *\n\t *\t\tconfig.set( 'toolbar', {\n\t *\t\t\tcolor: 'red',\n\t *\t\t} );\n\t *\n\t *\t\tconfig.get( 'toolbar.collapsed' ); // true\n\t *\t\tconfig.get( 'toolbar.color' ); // 'red'\n\t *\n\t * @param {String|Object} name The configuration name or an object from which take properties as\n\t * configuration entries. Configuration names are case-sensitive.\n\t * @param {*} value The configuration value. Used if a name is passed.\n\t */\n\tset( name, value ) {\n\t\tthis._setToTarget( this._config, name, value );\n\t}\n\n\t/**\n\t * Does exactly the same as {@link #set} with one exception – passed configuration extends\n\t * existing one, but does not overwrite already defined values.\n\t *\n\t * This method is supposed to be called by plugin developers to setup plugin's configurations. It would be\n\t * rarely used for other needs.\n\t *\n\t * @param {String|Object} name The configuration name or an object from which take properties as\n\t * configuration entries. Configuration names are case-sensitive.\n\t * @param {*} value The configuration value. Used if a name is passed.\n\t */\n\tdefine( name, value ) {\n\t\tconst isDefine = true;\n\n\t\tthis._setToTarget( this._config, name, value, isDefine );\n\t}\n\n\t/**\n\t * Gets the value for a configuration entry.\n\t *\n\t *\t\tconfig.get( 'name' );\n\t *\n\t * Deep configurations can be retrieved by separating each part with a dot.\n\t *\n\t *\t\tconfig.get( 'toolbar.collapsed' );\n\t *\n\t * @param {String} name The configuration name. Configuration names are case-sensitive.\n\t * @returns {*} The configuration value or `undefined` if the configuration entry was not found.\n\t */\n\tget( name ) {\n\t\treturn this._getFromSource( this._config, name );\n\t}\n\n\t/**\n\t * Iterates over all top level configuration names.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\t* names() {\n\t\tfor ( const name of Object.keys( this._config ) ) {\n\t\t\tyield name;\n\t\t}\n\t}\n\n\t/**\n\t * Saves passed configuration to the specified target (nested object).\n\t *\n\t * @private\n\t * @param {Object} target Nested config object.\n\t * @param {String|Object} name The configuration name or an object from which take properties as\n\t * configuration entries. Configuration names are case-sensitive.\n\t * @param {*} value The configuration value. Used if a name is passed.\n\t * @param {Boolean} [isDefine=false] Define if passed configuration should overwrite existing one.\n\t */\n\t_setToTarget( target, name, value, isDefine = false ) {\n\t\t// In case of an object, iterate through it and call `_setToTarget` again for each property.\n\t\tif ( isPlainObject( name ) ) {\n\t\t\tthis._setObjectToTarget( target, name, isDefine );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// The configuration name should be split into parts if it has dots. E.g. `resize.width` -> [`resize`, `width`].\n\t\tconst parts = name.split( '.' );\n\n\t\t// Take the name of the configuration out of the parts. E.g. `resize.width` -> `width`.\n\t\tname = parts.pop();\n\n\t\t// Iterate over parts to check if currently stored configuration has proper structure.\n\t\tfor ( const part of parts ) {\n\t\t\t// If there is no object for specified part then create one.\n\t\t\tif ( !isPlainObject( target[ part ] ) ) {\n\t\t\t\ttarget[ part ] = {};\n\t\t\t}\n\n\t\t\t// Nested object becomes a target.\n\t\t\ttarget = target[ part ];\n\t\t}\n\n\t\t// In case of value is an object.\n\t\tif ( isPlainObject( value ) ) {\n\t\t\t// We take care of proper config structure.\n\t\t\tif ( !isPlainObject( target[ name ] ) ) {\n\t\t\t\ttarget[ name ] = {};\n\t\t\t}\n\n\t\t\ttarget = target[ name ];\n\n\t\t\t// And iterate through this object calling `_setToTarget` again for each property.\n\t\t\tthis._setObjectToTarget( target, value, isDefine );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Do nothing if we are defining configuration for non empty name.\n\t\tif ( isDefine && typeof target[ name ] != 'undefined' ) {\n\t\t\treturn;\n\t\t}\n\n\t\ttarget[ name ] = value;\n\t}\n\n\t/**\n\t * Get specified configuration from specified source (nested object).\n\t *\n\t * @private\n\t * @param {Object} source level of nested object.\n\t * @param {String} name The configuration name. Configuration names are case-sensitive.\n\t * @returns {*} The configuration value or `undefined` if the configuration entry was not found.\n\t */\n\t_getFromSource( source, name ) {\n\t\t// The configuration name should be split into parts if it has dots. E.g. `resize.width` -> [`resize`, `width`].\n\t\tconst parts = name.split( '.' );\n\n\t\t// Take the name of the configuration out of the parts. E.g. `resize.width` -> `width`.\n\t\tname = parts.pop();\n\n\t\t// Iterate over parts to check if currently stored configuration has proper structure.\n\t\tfor ( const part of parts ) {\n\t\t\tif ( !isPlainObject( source[ part ] ) ) {\n\t\t\t\tsource = null;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Nested object becomes a source.\n\t\t\tsource = source[ part ];\n\t\t}\n\n\t\t// Always returns undefined for non existing configuration.\n\t\treturn source ? cloneConfig( source[ name ] ) : undefined;\n\t}\n\n\t/**\n\t * Iterates through passed object and calls {@link #_setToTarget} method with object key and value for each property.\n\t *\n\t * @private\n\t * @param {Object} target Nested config object.\n\t * @param {Object} configuration Configuration data set\n\t * @param {Boolean} [isDefine] Defines if passed configuration is default configuration or not.\n\t */\n\t_setObjectToTarget( target, configuration, isDefine ) {\n\t\tObject.keys( configuration ).forEach( key => {\n\t\t\tthis._setToTarget( target, key, configuration[ key ], isDefine );\n\t\t} );\n\t}\n}\n\n// Clones configuration object or value.\n// @param {*} source Source configuration\n// @returns {*} Cloned configuration value.\nfunction cloneConfig( source ) {\n\treturn cloneDeepWith( source, leaveDOMReferences );\n}\n\n// A customized function for cloneDeepWith.\n// It will leave references to DOM Elements instead of cloning them.\n//\n// @param {*} value\n// @returns {Element|undefined}\nfunction leaveDOMReferences( value ) {\n\treturn isElement( value ) ? value : undefined;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/spy\n */\n\n/**\n * Creates a spy function (ala Sinon.js) that can be used to inspect call to it.\n *\n * The following are the present features:\n *\n * * spy.called: property set to `true` if the function has been called at least once.\n *\n * @returns {Function} The spy function.\n */\nfunction spy() {\n\treturn function spy() {\n\t\tspy.called = true;\n\t};\n}\n\nexport default spy;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/eventinfo\n */\n\nimport spy from './spy';\n\n/**\n * The event object passed to event callbacks. It is used to provide information about the event as well as a tool to\n * manipulate it.\n */\nexport default class EventInfo {\n\t/**\n\t * @param {Object} source The emitter.\n\t * @param {String} name The event name.\n\t */\n\tconstructor( source, name ) {\n\t\t/**\n\t\t * The object that fired the event.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Object}\n\t\t */\n\t\tthis.source = source;\n\n\t\t/**\n\t\t * The event name.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.name = name;\n\n\t\t/**\n\t\t * Path this event has followed. See {@link module:utils/emittermixin~EmitterMixin#delegate}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<Object>}\n\t\t */\n\t\tthis.path = [];\n\n\t\t// The following methods are defined in the constructor because they must be re-created per instance.\n\n\t\t/**\n\t\t * Stops the event emitter to call further callbacks for this event interaction.\n\t\t *\n\t\t * @method #stop\n\t\t */\n\t\tthis.stop = spy();\n\n\t\t/**\n\t\t * Removes the current callback from future interactions of this event.\n\t\t *\n\t\t * @method #off\n\t\t */\n\t\tthis.off = spy();\n\n\t\t/**\n\t\t * The value which will be returned by {@link module:utils/emittermixin~EmitterMixin#fire}.\n\t\t *\n\t\t * It's `undefined` by default and can be changed by an event listener:\n\t\t *\n\t\t *\t\tdataController.fire( 'getSelectedContent', ( evt ) => {\n\t\t *\t\t\t// This listener will make `dataController.fire( 'getSelectedContent' )`\n\t\t *\t\t\t// always return an empty DocumentFragment.\n\t\t *\t\t\tevt.return = new DocumentFragment();\n\t\t *\n\t\t *\t\t\t// Make sure no other listeners are executed.\n\t\t *\t\t\tevt.stop();\n\t\t *\t\t} );\n\t\t *\n\t\t * @member #return\n\t\t */\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/uid\n */\n\n// A hash table of hex numbers to avoid using toString() in uid() which is costly.\n// [ '00', '01', '02', ..., 'fe', 'ff' ]\nconst HEX_NUMBERS = new Array( 256 ).fill()\n\t.map( ( val, index ) => ( '0' + ( index ).toString( 16 ) ).slice( -2 ) );\n\n/**\n * Returns a unique id. The id starts with an \"e\" character and a randomly generated string of\n * 32 alphanumeric characters.\n *\n * **Note**: The characters the unique id is built from correspond to the hex number notation\n * (from \"0\" to \"9\", from \"a\" to \"f\"). In other words, each id corresponds to an \"e\" followed\n * by 16 8-bit numbers next to each other.\n *\n * @returns {String} An unique id string.\n */\nexport default function uid() {\n\t// Let's create some positive random 32bit integers first.\n\t//\n\t// 1. Math.random() is a float between 0 and 1.\n\t// 2. 0x100000000 is 2^32 = 4294967296.\n\t// 3. >>> 0 enforces integer (in JS all numbers are floating point).\n\t//\n\t// For instance:\n\t//\t\tMath.random() * 0x100000000 = 3366450031.853859\n\t// but\n\t//\t\tMath.random() * 0x100000000 >>> 0 = 3366450031.\n\tconst r1 = Math.random() * 0x100000000 >>> 0;\n\tconst r2 = Math.random() * 0x100000000 >>> 0;\n\tconst r3 = Math.random() * 0x100000000 >>> 0;\n\tconst r4 = Math.random() * 0x100000000 >>> 0;\n\n\t// Make sure that id does not start with number.\n\treturn 'e' +\n\t\tHEX_NUMBERS[ r1 >> 0 & 0xFF ] +\n\t\tHEX_NUMBERS[ r1 >> 8 & 0xFF ] +\n\t\tHEX_NUMBERS[ r1 >> 16 & 0xFF ] +\n\t\tHEX_NUMBERS[ r1 >> 24 & 0xFF ] +\n\t\tHEX_NUMBERS[ r2 >> 0 & 0xFF ] +\n\t\tHEX_NUMBERS[ r2 >> 8 & 0xFF ] +\n\t\tHEX_NUMBERS[ r2 >> 16 & 0xFF ] +\n\t\tHEX_NUMBERS[ r2 >> 24 & 0xFF ] +\n\t\tHEX_NUMBERS[ r3 >> 0 & 0xFF ] +\n\t\tHEX_NUMBERS[ r3 >> 8 & 0xFF ] +\n\t\tHEX_NUMBERS[ r3 >> 16 & 0xFF ] +\n\t\tHEX_NUMBERS[ r3 >> 24 & 0xFF ] +\n\t\tHEX_NUMBERS[ r4 >> 0 & 0xFF ] +\n\t\tHEX_NUMBERS[ r4 >> 8 & 0xFF ] +\n\t\tHEX_NUMBERS[ r4 >> 16 & 0xFF ] +\n\t\tHEX_NUMBERS[ r4 >> 24 & 0xFF ];\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/priorities\n */\n\n/**\n * String representing a priority value.\n *\n * @typedef {'highest'|'high'|'normal'|'low'|'lowest'} module:utils/priorities~PriorityString\n */\n\n/**\n * Provides group of constants to use instead of hardcoding numeric priority values.\n *\n * @namespace\n */\nconst priorities = {\n\t/**\n\t * Converts a string with priority name to it's numeric value. If `Number` is given, it just returns it.\n\t *\n\t * @static\n\t * @param {module:utils/priorities~PriorityString|Number} priority Priority to convert.\n\t * @returns {Number} Converted priority.\n\t */\n\tget( priority ) {\n\t\tif ( typeof priority != 'number' ) {\n\t\t\treturn this[ priority ] || this.normal;\n\t\t} else {\n\t\t\treturn priority;\n\t\t}\n\t},\n\n\thighest: 100000,\n\thigh: 1000,\n\tnormal: 0,\n\tlow: -1000,\n\tlowest: -100000\n};\n\nexport default priorities;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/emittermixin\n */\n\nimport EventInfo from './eventinfo';\nimport uid from './uid';\nimport priorities from './priorities';\n\n// To check if component is loaded more than once.\nimport './version';\nimport CKEditorError from './ckeditorerror';\n\nconst _listeningTo = Symbol( 'listeningTo' );\nconst _emitterId = Symbol( 'emitterId' );\n\n/**\n * Mixin that injects the {@link ~Emitter events API} into its host.\n *\n * @mixin EmitterMixin\n * @implements module:utils/emittermixin~Emitter\n */\nconst EmitterMixin = {\n\t/**\n\t * @inheritDoc\n\t */\n\ton( event, callback, options = {} ) {\n\t\tthis.listenTo( this, event, callback, options );\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tonce( event, callback, options ) {\n\t\tlet wasFired = false;\n\n\t\tconst onceCallback = function( event, ...args ) {\n\t\t\t// Ensure the callback is called only once even if the callback itself leads to re-firing the event\n\t\t\t// (which would call the callback again).\n\t\t\tif ( !wasFired ) {\n\t\t\t\twasFired = true;\n\n\t\t\t\t// Go off() at the first call.\n\t\t\t\tevent.off();\n\n\t\t\t\t// Go with the original callback.\n\t\t\t\tcallback.call( this, event, ...args );\n\t\t\t}\n\t\t};\n\n\t\t// Make a similar on() call, simply replacing the callback.\n\t\tthis.listenTo( this, event, onceCallback, options );\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\toff( event, callback ) {\n\t\tthis.stopListening( this, event, callback );\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tlistenTo( emitter, event, callback, options = {} ) {\n\t\tlet emitterInfo, eventCallbacks;\n\n\t\t// _listeningTo contains a list of emitters that this object is listening to.\n\t\t// This list has the following format:\n\t\t//\n\t\t// _listeningTo: {\n\t\t//     emitterId: {\n\t\t//         emitter: emitter,\n\t\t//         callbacks: {\n\t\t//             event1: [ callback1, callback2, ... ]\n\t\t//             ....\n\t\t//         }\n\t\t//     },\n\t\t//     ...\n\t\t// }\n\n\t\tif ( !this[ _listeningTo ] ) {\n\t\t\tthis[ _listeningTo ] = {};\n\t\t}\n\n\t\tconst emitters = this[ _listeningTo ];\n\n\t\tif ( !_getEmitterId( emitter ) ) {\n\t\t\t_setEmitterId( emitter );\n\t\t}\n\n\t\tconst emitterId = _getEmitterId( emitter );\n\n\t\tif ( !( emitterInfo = emitters[ emitterId ] ) ) {\n\t\t\temitterInfo = emitters[ emitterId ] = {\n\t\t\t\temitter,\n\t\t\t\tcallbacks: {}\n\t\t\t};\n\t\t}\n\n\t\tif ( !( eventCallbacks = emitterInfo.callbacks[ event ] ) ) {\n\t\t\teventCallbacks = emitterInfo.callbacks[ event ] = [];\n\t\t}\n\n\t\teventCallbacks.push( callback );\n\n\t\t// Finally register the callback to the event.\n\t\tcreateEventNamespace( emitter, event );\n\t\tconst lists = getCallbacksListsForNamespace( emitter, event );\n\t\tconst priority = priorities.get( options.priority );\n\n\t\tconst callbackDefinition = {\n\t\t\tcallback,\n\t\t\tpriority\n\t\t};\n\n\t\t// Add the callback to all callbacks list.\n\t\tfor ( const callbacks of lists ) {\n\t\t\t// Add the callback to the list in the right priority position.\n\t\t\tlet added = false;\n\n\t\t\tfor ( let i = 0; i < callbacks.length; i++ ) {\n\t\t\t\tif ( callbacks[ i ].priority < priority ) {\n\t\t\t\t\tcallbacks.splice( i, 0, callbackDefinition );\n\t\t\t\t\tadded = true;\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add at the end, if right place was not found.\n\t\t\tif ( !added ) {\n\t\t\t\tcallbacks.push( callbackDefinition );\n\t\t\t}\n\t\t}\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstopListening( emitter, event, callback ) {\n\t\tconst emitters = this[ _listeningTo ];\n\t\tlet emitterId = emitter && _getEmitterId( emitter );\n\t\tconst emitterInfo = emitters && emitterId && emitters[ emitterId ];\n\t\tconst eventCallbacks = emitterInfo && event && emitterInfo.callbacks[ event ];\n\n\t\t// Stop if nothing has been listened.\n\t\tif ( !emitters || ( emitter && !emitterInfo ) || ( event && !eventCallbacks ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// All params provided. off() that single callback.\n\t\tif ( callback ) {\n\t\t\tremoveCallback( emitter, event, callback );\n\n\t\t\t// We must remove callbacks as well in order to prevent memory leaks.\n\t\t\t// See https://github.com/ckeditor/ckeditor5/pull/8480\n\t\t\tconst index = eventCallbacks.indexOf( callback );\n\n\t\t\tif ( index !== -1 ) {\n\t\t\t\tif ( eventCallbacks.length === 1 ) {\n\t\t\t\t\tdelete emitterInfo.callbacks[ event ];\n\t\t\t\t} else {\n\t\t\t\t\tremoveCallback( emitter, event, callback );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Only `emitter` and `event` provided. off() all callbacks for that event.\n\t\telse if ( eventCallbacks ) {\n\t\t\twhile ( ( callback = eventCallbacks.pop() ) ) {\n\t\t\t\tremoveCallback( emitter, event, callback );\n\t\t\t}\n\n\t\t\tdelete emitterInfo.callbacks[ event ];\n\t\t}\n\t\t// Only `emitter` provided. off() all events for that emitter.\n\t\telse if ( emitterInfo ) {\n\t\t\tfor ( event in emitterInfo.callbacks ) {\n\t\t\t\tthis.stopListening( emitter, event );\n\t\t\t}\n\t\t\tdelete emitters[ emitterId ];\n\t\t}\n\t\t// No params provided. off() all emitters.\n\t\telse {\n\t\t\tfor ( emitterId in emitters ) {\n\t\t\t\tthis.stopListening( emitters[ emitterId ].emitter );\n\t\t\t}\n\t\t\tdelete this[ _listeningTo ];\n\t\t}\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tfire( eventOrInfo, ...args ) {\n\t\ttry {\n\t\t\tconst eventInfo = eventOrInfo instanceof EventInfo ? eventOrInfo : new EventInfo( this, eventOrInfo );\n\t\t\tconst event = eventInfo.name;\n\t\t\tlet callbacks = getCallbacksForEvent( this, event );\n\n\t\t\t// Record that the event passed this emitter on its path.\n\t\t\teventInfo.path.push( this );\n\n\t\t\t// Handle event listener callbacks first.\n\t\t\tif ( callbacks ) {\n\t\t\t\t// Arguments passed to each callback.\n\t\t\t\tconst callbackArgs = [ eventInfo, ...args ];\n\n\t\t\t\t// Copying callbacks array is the easiest and most secure way of preventing infinite loops, when event callbacks\n\t\t\t\t// are added while processing other callbacks. Previous solution involved adding counters (unique ids) but\n\t\t\t\t// failed if callbacks were added to the queue before currently processed callback.\n\t\t\t\t// If this proves to be too inefficient, another method is to change `.on()` so callbacks are stored if same\n\t\t\t\t// event is currently processed. Then, `.fire()` at the end, would have to add all stored events.\n\t\t\t\tcallbacks = Array.from( callbacks );\n\n\t\t\t\tfor ( let i = 0; i < callbacks.length; i++ ) {\n\t\t\t\t\tcallbacks[ i ].callback.apply( this, callbackArgs );\n\n\t\t\t\t\t// Remove the callback from future requests if off() has been called.\n\t\t\t\t\tif ( eventInfo.off.called ) {\n\t\t\t\t\t\t// Remove the called mark for the next calls.\n\t\t\t\t\t\tdelete eventInfo.off.called;\n\n\t\t\t\t\t\tremoveCallback( this, event, callbacks[ i ].callback );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Do not execute next callbacks if stop() was called.\n\t\t\t\t\tif ( eventInfo.stop.called ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Delegate event to other emitters if needed.\n\t\t\tif ( this._delegations ) {\n\t\t\t\tconst destinations = this._delegations.get( event );\n\t\t\t\tconst passAllDestinations = this._delegations.get( '*' );\n\n\t\t\t\tif ( destinations ) {\n\t\t\t\t\tfireDelegatedEvents( destinations, eventInfo, args );\n\t\t\t\t}\n\n\t\t\t\tif ( passAllDestinations ) {\n\t\t\t\t\tfireDelegatedEvents( passAllDestinations, eventInfo, args );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn eventInfo.return;\n\t\t} catch ( err ) {\n\t\t\t// @if CK_DEBUG // throw err;\n\t\t\t/* istanbul ignore next */\n\t\t\tCKEditorError.rethrowUnexpectedError( err, this );\n\t\t}\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdelegate( ...events ) {\n\t\treturn {\n\t\t\tto: ( emitter, nameOrFunction ) => {\n\t\t\t\tif ( !this._delegations ) {\n\t\t\t\t\tthis._delegations = new Map();\n\t\t\t\t}\n\n\t\t\t\t// Originally there was a for..of loop which unfortunately caused an error in Babel that didn't allow\n\t\t\t\t// build an application. See: https://github.com/ckeditor/ckeditor5-react/issues/40.\n\t\t\t\tevents.forEach( eventName => {\n\t\t\t\t\tconst destinations = this._delegations.get( eventName );\n\n\t\t\t\t\tif ( !destinations ) {\n\t\t\t\t\t\tthis._delegations.set( eventName, new Map( [ [ emitter, nameOrFunction ] ] ) );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdestinations.set( emitter, nameOrFunction );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t};\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstopDelegating( event, emitter ) {\n\t\tif ( !this._delegations ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !event ) {\n\t\t\tthis._delegations.clear();\n\t\t} else if ( !emitter ) {\n\t\t\tthis._delegations.delete( event );\n\t\t} else {\n\t\t\tconst destinations = this._delegations.get( event );\n\n\t\t\tif ( destinations ) {\n\t\t\t\tdestinations.delete( emitter );\n\t\t\t}\n\t\t}\n\t}\n};\n\nexport default EmitterMixin;\n\n/**\n * Emitter/listener interface.\n *\n * Can be easily implemented by a class by mixing the {@link module:utils/emittermixin~EmitterMixin} mixin.\n *\n * @interface Emitter\n */\n\n/**\n * Registers a callback function to be executed when an event is fired.\n *\n * Shorthand for {@link #listenTo `this.listenTo( this, event, callback, options )`} (it makes the emitter\n * listen on itself).\n *\n * @method #on\n * @param {String} event The name of the event.\n * @param {Function} callback The function to be called on event.\n * @param {Object} [options={}] Additional options.\n * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher\n * the priority value the sooner the callback will be fired. Events having the same priority are called in the\n * order they were added.\n */\n\n/**\n * Registers a callback function to be executed on the next time the event is fired only. This is similar to\n * calling {@link #on} followed by {@link #off} in the callback.\n *\n * @method #once\n * @param {String} event The name of the event.\n * @param {Function} callback The function to be called on event.\n * @param {Object} [options={}] Additional options.\n * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher\n * the priority value the sooner the callback will be fired. Events having the same priority are called in the\n * order they were added.\n */\n\n/**\n * Stops executing the callback on the given event.\n * Shorthand for {@link #stopListening `this.stopListening( this, event, callback )`}.\n *\n * @method #off\n * @param {String} event The name of the event.\n * @param {Function} callback The function to stop being called.\n */\n\n/**\n * Registers a callback function to be executed when an event is fired in a specific (emitter) object.\n *\n * Events can be grouped in namespaces using `:`.\n * When namespaced event is fired, it additionally fires all callbacks for that namespace.\n *\n *\t\t// myEmitter.on( ... ) is a shorthand for myEmitter.listenTo( myEmitter, ... ).\n *\t\tmyEmitter.on( 'myGroup', genericCallback );\n *\t\tmyEmitter.on( 'myGroup:myEvent', specificCallback );\n *\n *\t\t// genericCallback is fired.\n *\t\tmyEmitter.fire( 'myGroup' );\n *\t\t// both genericCallback and specificCallback are fired.\n *\t\tmyEmitter.fire( 'myGroup:myEvent' );\n *\t\t// genericCallback is fired even though there are no callbacks for \"foo\".\n *\t\tmyEmitter.fire( 'myGroup:foo' );\n *\n * An event callback can {@link module:utils/eventinfo~EventInfo#stop stop the event} and\n * set the {@link module:utils/eventinfo~EventInfo#return return value} of the {@link #fire} method.\n *\n * @method #listenTo\n * @param {module:utils/emittermixin~Emitter} emitter The object that fires the event.\n * @param {String} event The name of the event.\n * @param {Function} callback The function to be called on event.\n * @param {Object} [options={}] Additional options.\n * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher\n * the priority value the sooner the callback will be fired. Events having the same priority are called in the\n * order they were added.\n */\n\n/**\n * Stops listening for events. It can be used at different levels:\n *\n * * To stop listening to a specific callback.\n * * To stop listening to a specific event.\n * * To stop listening to all events fired by a specific object.\n * * To stop listening to all events fired by all objects.\n *\n * @method #stopListening\n * @param {module:utils/emittermixin~Emitter} [emitter] The object to stop listening to. If omitted, stops it for all objects.\n * @param {String} [event] (Requires the `emitter`) The name of the event to stop listening to. If omitted, stops it\n * for all events from `emitter`.\n * @param {Function} [callback] (Requires the `event`) The function to be removed from the call list for the given\n * `event`.\n */\n\n/**\n * Fires an event, executing all callbacks registered for it.\n *\n * The first parameter passed to callbacks is an {@link module:utils/eventinfo~EventInfo} object,\n * followed by the optional `args` provided in the `fire()` method call.\n *\n * @method #fire\n * @param {String|module:utils/eventinfo~EventInfo} eventOrInfo The name of the event or `EventInfo` object if event is delegated.\n * @param {...*} [args] Additional arguments to be passed to the callbacks.\n * @returns {*} By default the method returns `undefined`. However, the return value can be changed by listeners\n * through modification of the {@link module:utils/eventinfo~EventInfo#return `evt.return`}'s property (the event info\n * is the first param of every callback).\n */\n\n/**\n * Delegates selected events to another {@link module:utils/emittermixin~Emitter}. For instance:\n *\n *\t\temitterA.delegate( 'eventX' ).to( emitterB );\n *\t\temitterA.delegate( 'eventX', 'eventY' ).to( emitterC );\n *\n * then `eventX` is delegated (fired by) `emitterB` and `emitterC` along with `data`:\n *\n *\t\temitterA.fire( 'eventX', data );\n *\n * and `eventY` is delegated (fired by) `emitterC` along with `data`:\n *\n *\t\temitterA.fire( 'eventY', data );\n *\n * @method #delegate\n * @param {...String} events Event names that will be delegated to another emitter.\n * @returns {module:utils/emittermixin~EmitterMixinDelegateChain}\n */\n\n/**\n * Stops delegating events. It can be used at different levels:\n *\n * * To stop delegating all events.\n * * To stop delegating a specific event to all emitters.\n * * To stop delegating a specific event to a specific emitter.\n *\n * @method #stopDelegating\n * @param {String} [event] The name of the event to stop delegating. If omitted, stops it all delegations.\n * @param {module:utils/emittermixin~Emitter} [emitter] (requires `event`) The object to stop delegating a particular event to.\n * If omitted, stops delegation of `event` to all emitters.\n */\n\n/**\n * Checks if `listeningEmitter` listens to an emitter with given `listenedToEmitterId` and if so, returns that emitter.\n * If not, returns `null`.\n *\n * @protected\n * @param {module:utils/emittermixin~Emitter} listeningEmitter An emitter that listens.\n * @param {String} listenedToEmitterId Unique emitter id of emitter listened to.\n * @returns {module:utils/emittermixin~Emitter|null}\n */\nexport function _getEmitterListenedTo( listeningEmitter, listenedToEmitterId ) {\n\tif ( listeningEmitter[ _listeningTo ] && listeningEmitter[ _listeningTo ][ listenedToEmitterId ] ) {\n\t\treturn listeningEmitter[ _listeningTo ][ listenedToEmitterId ].emitter;\n\t}\n\n\treturn null;\n}\n\n/**\n * Sets emitter's unique id.\n *\n * **Note:** `_emitterId` can be set only once.\n *\n * @protected\n * @param {module:utils/emittermixin~Emitter} emitter An emitter for which id will be set.\n * @param {String} [id] Unique id to set. If not passed, random unique id will be set.\n */\nexport function _setEmitterId( emitter, id ) {\n\tif ( !emitter[ _emitterId ] ) {\n\t\temitter[ _emitterId ] = id || uid();\n\t}\n}\n\n/**\n * Returns emitter's unique id.\n *\n * @protected\n * @param {module:utils/emittermixin~Emitter} emitter An emitter which id will be returned.\n */\nexport function _getEmitterId( emitter ) {\n\treturn emitter[ _emitterId ];\n}\n\n// Gets the internal `_events` property of the given object.\n// `_events` property store all lists with callbacks for registered event names.\n// If there were no events registered on the object, empty `_events` object is created.\nfunction getEvents( source ) {\n\tif ( !source._events ) {\n\t\tObject.defineProperty( source, '_events', {\n\t\t\tvalue: {}\n\t\t} );\n\t}\n\n\treturn source._events;\n}\n\n// Creates event node for generic-specific events relation architecture.\nfunction makeEventNode() {\n\treturn {\n\t\tcallbacks: [],\n\t\tchildEvents: []\n\t};\n}\n\n// Creates an architecture for generic-specific events relation.\n// If needed, creates all events for given eventName, i.e. if the first registered event\n// is foo:bar:abc, it will create foo:bar:abc, foo:bar and foo event and tie them together.\n// It also copies callbacks from more generic events to more specific events when\n// specific events are created.\nfunction createEventNamespace( source, eventName ) {\n\tconst events = getEvents( source );\n\n\t// First, check if the event we want to add to the structure already exists.\n\tif ( events[ eventName ] ) {\n\t\t// If it exists, we don't have to do anything.\n\t\treturn;\n\t}\n\n\t// In other case, we have to create the structure for the event.\n\t// Note, that we might need to create intermediate events too.\n\t// I.e. if foo:bar:abc is being registered and we only have foo in the structure,\n\t// we need to also register foo:bar.\n\n\t// Currently processed event name.\n\tlet name = eventName;\n\t// Name of the event that is a child event for currently processed event.\n\tlet childEventName = null;\n\n\t// Array containing all newly created specific events.\n\tconst newEventNodes = [];\n\n\t// While loop can't check for ':' index because we have to handle generic events too.\n\t// In each loop, we truncate event name, going from the most specific name to the generic one.\n\t// I.e. foo:bar:abc -> foo:bar -> foo.\n\twhile ( name !== '' ) {\n\t\tif ( events[ name ] ) {\n\t\t\t// If the currently processed event name is already registered, we can be sure\n\t\t\t// that it already has all the structure created, so we can break the loop here\n\t\t\t// as no more events need to be registered.\n\t\t\tbreak;\n\t\t}\n\n\t\t// If this event is not yet registered, create a new object for it.\n\t\tevents[ name ] = makeEventNode();\n\t\t// Add it to the array with newly created events.\n\t\tnewEventNodes.push( events[ name ] );\n\n\t\t// Add previously processed event name as a child of this event.\n\t\tif ( childEventName ) {\n\t\t\tevents[ name ].childEvents.push( childEventName );\n\t\t}\n\n\t\tchildEventName = name;\n\t\t// If `.lastIndexOf()` returns -1, `.substr()` will return '' which will break the loop.\n\t\tname = name.substr( 0, name.lastIndexOf( ':' ) );\n\t}\n\n\tif ( name !== '' ) {\n\t\t// If name is not empty, we found an already registered event that was a parent of the\n\t\t// event we wanted to register.\n\n\t\t// Copy that event's callbacks to newly registered events.\n\t\tfor ( const node of newEventNodes ) {\n\t\t\tnode.callbacks = events[ name ].callbacks.slice();\n\t\t}\n\n\t\t// Add last newly created event to the already registered event.\n\t\tevents[ name ].childEvents.push( childEventName );\n\t}\n}\n\n// Gets an array containing callbacks list for a given event and it's more specific events.\n// I.e. if given event is foo:bar and there is also foo:bar:abc event registered, this will\n// return callback list of foo:bar and foo:bar:abc (but not foo).\nfunction getCallbacksListsForNamespace( source, eventName ) {\n\tconst eventNode = getEvents( source )[ eventName ];\n\n\tif ( !eventNode ) {\n\t\treturn [];\n\t}\n\n\tlet callbacksLists = [ eventNode.callbacks ];\n\n\tfor ( let i = 0; i < eventNode.childEvents.length; i++ ) {\n\t\tconst childCallbacksLists = getCallbacksListsForNamespace( source, eventNode.childEvents[ i ] );\n\n\t\tcallbacksLists = callbacksLists.concat( childCallbacksLists );\n\t}\n\n\treturn callbacksLists;\n}\n\n// Get the list of callbacks for a given event, but only if there any callbacks have been registered.\n// If there are no callbacks registered for given event, it checks if this is a specific event and looks\n// for callbacks for it's more generic version.\nfunction getCallbacksForEvent( source, eventName ) {\n\tlet event;\n\n\tif ( !source._events || !( event = source._events[ eventName ] ) || !event.callbacks.length ) {\n\t\t// There are no callbacks registered for specified eventName.\n\t\t// But this could be a specific-type event that is in a namespace.\n\t\tif ( eventName.indexOf( ':' ) > -1 ) {\n\t\t\t// If the eventName is specific, try to find callback lists for more generic event.\n\t\t\treturn getCallbacksForEvent( source, eventName.substr( 0, eventName.lastIndexOf( ':' ) ) );\n\t\t} else {\n\t\t\t// If this is a top-level generic event, return null;\n\t\t\treturn null;\n\t\t}\n\t}\n\n\treturn event.callbacks;\n}\n\n// Fires delegated events for given map of destinations.\n//\n// @private\n// * @param {Map.<utils.Emitter>} destinations A map containing\n// `[ {@link module:utils/emittermixin~Emitter}, \"event name\" ]` pair destinations.\n// * @param {utils.EventInfo} eventInfo The original event info object.\n// * @param {Array.<*>} fireArgs Arguments the original event was fired with.\nfunction fireDelegatedEvents( destinations, eventInfo, fireArgs ) {\n\tfor ( let [ emitter, name ] of destinations ) {\n\t\tif ( !name ) {\n\t\t\tname = eventInfo.name;\n\t\t} else if ( typeof name == 'function' ) {\n\t\t\tname = name( eventInfo.name );\n\t\t}\n\n\t\tconst delegatedInfo = new EventInfo( eventInfo.source, name );\n\n\t\tdelegatedInfo.path = [ ...eventInfo.path ];\n\n\t\temitter.fire( delegatedInfo, ...fireArgs );\n\t}\n}\n\n// Removes callback from emitter for given event.\n//\n// @param {module:utils/emittermixin~Emitter} emitter\n// @param {String} event\n// @param {Function} callback\nfunction removeCallback( emitter, event, callback ) {\n\tconst lists = getCallbacksListsForNamespace( emitter, event );\n\n\tfor ( const callbacks of lists ) {\n\t\tfor ( let i = 0; i < callbacks.length; i++ ) {\n\t\t\tif ( callbacks[ i ].callback == callback ) {\n\t\t\t\t// Remove the callback from the list (fixing the next index).\n\t\t\t\tcallbacks.splice( i, 1 );\n\t\t\t\ti--;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * The return value of {@link ~EmitterMixin#delegate}.\n *\n * @interface module:utils/emittermixin~EmitterMixinDelegateChain\n */\n\n/**\n * Selects destination for {@link module:utils/emittermixin~EmitterMixin#delegate} events.\n *\n * @method #to\n * @param {module:utils/emittermixin~Emitter} emitter An `EmitterMixin` instance which is the destination for delegated events.\n * @param {String|Function} [nameOrFunction] A custom event name or function which converts the original name string.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/isiterable\n */\n\n/**\n * Checks if value implements iterator interface.\n *\n * @param {*} value The value to check.\n * @returns {Boolean} True if value implements iterator interface.\n */\nexport default function isIterable( value ) {\n\treturn !!( value && value[ Symbol.iterator ] );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/mix\n */\n\n/**\n * Copies enumerable properties and symbols from the objects given as 2nd+ parameters to the\n * prototype of first object (a constructor).\n *\n *\t\tclass Editor {\n *\t\t\t...\n *\t\t}\n *\n *\t\tconst SomeMixin = {\n *\t\t\ta() {\n *\t\t\t\treturn 'a';\n *\t\t\t}\n *\t\t};\n *\n *\t\tmix( Editor, SomeMixin, ... );\n *\n *\t\tnew Editor().a(); // -> 'a'\n *\n * Note: Properties which already exist in the base class will not be overriden.\n *\n * @param {Function} [baseClass] Class which prototype will be extended.\n * @param {Object} [...mixins] Objects from which to get properties.\n */\nexport default function mix( baseClass, ...mixins ) {\n\tmixins.forEach( mixin => {\n\t\tObject.getOwnPropertyNames( mixin ).concat( Object.getOwnPropertySymbols( mixin ) )\n\t\t\t.forEach( key => {\n\t\t\t\tif ( key in baseClass.prototype ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst sourceDescriptor = Object.getOwnPropertyDescriptor( mixin, key );\n\t\t\t\tsourceDescriptor.enumerable = false;\n\n\t\t\t\tObject.defineProperty( baseClass.prototype, key, sourceDescriptor );\n\t\t\t} );\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/collection\n */\n\nimport EmitterMixin from './emittermixin';\nimport CKEditorError from './ckeditorerror';\nimport uid from './uid';\nimport isIterable from './isiterable';\nimport mix from './mix';\n\n/**\n * Collections are ordered sets of objects. Items in the collection can be retrieved by their indexes\n * in the collection (like in an array) or by their ids.\n *\n * If an object without an `id` property is being added to the collection, the `id` property will be generated\n * automatically. Note that the automatically generated id is unique only within this single collection instance.\n *\n * By default an item in the collection is identified by its `id` property. The name of the identifier can be\n * configured through the constructor of the collection.\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class Collection {\n\t/**\n\t * Creates a new Collection instance.\n\t *\n\t * You can provide an iterable of initial items the collection will be created with:\n\t *\n\t *\t\tconst collection = new Collection( [ { id: 'John' }, { id: 'Mike' } ] );\n\t *\n\t *\t\tconsole.log( collection.get( 0 ) ); // -> { id: 'John' }\n\t *\t\tconsole.log( collection.get( 1 ) ); // -> { id: 'Mike' }\n\t *\t\tconsole.log( collection.get( 'Mike' ) ); // -> { id: 'Mike' }\n\t *\n\t * Or you can first create a collection and then add new items using the {@link #add} method:\n\t *\n\t *\t\tconst collection = new Collection();\n\t *\n\t *\t\tcollection.add( { id: 'John' } );\n\t *\t\tconsole.log( collection.get( 0 ) ); // -> { id: 'John' }\n\t *\n\t * Whatever option you choose, you can always pass a configuration object as the last argument\n\t * of the constructor:\n\t *\n\t *\t\tconst emptyCollection = new Collection( { idProperty: 'name' } );\n\t *\t\temptyCollection.add( { name: 'John' } );\n\t *\t\tconsole.log( collection.get( 'John' ) ); // -> { name: 'John' }\n\t *\n\t *\t\tconst nonEmptyCollection = new Collection( [ { name: 'John' } ], { idProperty: 'name' } );\n\t *\t\tnonEmptyCollection.add( { name: 'George' } );\n\t *\t\tconsole.log( collection.get( 'George' ) ); // -> { name: 'George' }\n\t *\t\tconsole.log( collection.get( 'John' ) ); // -> { name: 'John' }\n\t *\n\t * @param {Iterable.<Object>|Object} initialItemsOrOptions The initial items of the collection or\n\t * the options object.\n\t * @param {Object} [options={}] The options object, when the first argument is an array of initial items.\n\t * @param {String} [options.idProperty='id'] The name of the property which is used to identify an item.\n\t * Items that do not have such a property will be assigned one when added to the collection.\n\t */\n\tconstructor( initialItemsOrOptions = {}, options = {} ) {\n\t\tconst hasInitialItems = isIterable( initialItemsOrOptions );\n\n\t\tif ( !hasInitialItems ) {\n\t\t\toptions = initialItemsOrOptions;\n\t\t}\n\n\t\t/**\n\t\t * The internal list of items in the collection.\n\t\t *\n\t\t * @private\n\t\t * @member {Object[]}\n\t\t */\n\t\tthis._items = [];\n\n\t\t/**\n\t\t * The internal map of items in the collection.\n\t\t *\n\t\t * @private\n\t\t * @member {Map}\n\t\t */\n\t\tthis._itemMap = new Map();\n\n\t\t/**\n\t\t * The name of the property which is considered to identify an item.\n\t\t *\n\t\t * @private\n\t\t * @member {String}\n\t\t */\n\t\tthis._idProperty = options.idProperty || 'id';\n\n\t\t/**\n\t\t * A helper mapping external items of a bound collection ({@link #bindTo})\n\t\t * and actual items of this collection. It provides information\n\t\t * necessary to properly remove items bound to another collection.\n\t\t *\n\t\t * See {@link #_bindToInternalToExternalMap}.\n\t\t *\n\t\t * @protected\n\t\t * @member {WeakMap}\n\t\t */\n\t\tthis._bindToExternalToInternalMap = new WeakMap();\n\n\t\t/**\n\t\t * A helper mapping items of this collection to external items of a bound collection\n\t\t * ({@link #bindTo}). It provides information necessary to manage the bindings, e.g.\n\t\t * to avoid loops in two–way bindings.\n\t\t *\n\t\t * See {@link #_bindToExternalToInternalMap}.\n\t\t *\n\t\t * @protected\n\t\t * @member {WeakMap}\n\t\t */\n\t\tthis._bindToInternalToExternalMap = new WeakMap();\n\n\t\t/**\n\t\t * Stores indexes of skipped items from bound external collection.\n\t\t *\n\t\t * @private\n\t\t * @member {Array}\n\t\t */\n\t\tthis._skippedIndexesFromExternal = [];\n\n\t\t// Set the initial content of the collection (if provided in the constructor).\n\t\tif ( hasInitialItems ) {\n\t\t\tfor ( const item of initialItemsOrOptions ) {\n\t\t\t\tthis._items.push( item );\n\t\t\t\tthis._itemMap.set( this._getItemIdBeforeAdding( item ), item );\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * A collection instance this collection is bound to as a result\n\t\t * of calling {@link #bindTo} method.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:utils/collection~Collection} #_bindToCollection\n\t\t */\n\t}\n\n\t/**\n\t * The number of items available in the collection.\n\t *\n\t * @member {Number} #length\n\t */\n\tget length() {\n\t\treturn this._items.length;\n\t}\n\n\t/**\n\t * Returns the first item from the collection or null when collection is empty.\n\t *\n\t * @returns {Object|null} The first item or `null` if collection is empty.\n\t */\n\tget first() {\n\t\treturn this._items[ 0 ] || null;\n\t}\n\n\t/**\n\t * Returns the last item from the collection or null when collection is empty.\n\t *\n\t * @returns {Object|null} The last item or `null` if collection is empty.\n\t */\n\tget last() {\n\t\treturn this._items[ this.length - 1 ] || null;\n\t}\n\n\t/**\n\t * Adds an item into the collection.\n\t *\n\t * If the item does not have an id, then it will be automatically generated and set on the item.\n\t *\n\t * @chainable\n\t * @param {Object} item\n\t * @param {Number} [index] The position of the item in the collection. The item\n\t * is pushed to the collection when `index` not specified.\n\t * @fires add\n\t * @fires change\n\t */\n\tadd( item, index ) {\n\t\treturn this.addMany( [ item ], index );\n\t}\n\n\t/**\n\t * Adds multiple items into the collection.\n\t *\n\t * Any item not containing an id will get an automatically generated one.\n\t *\n\t * @chainable\n\t * @param {Iterable.<Object>} item\n\t * @param {Number} [index] The position of the insertion. Items will be appended if no `index` is specified.\n\t * @fires add\n\t * @fires change\n\t */\n\taddMany( items, index ) {\n\t\tif ( index === undefined ) {\n\t\t\tindex = this._items.length;\n\t\t} else if ( index > this._items.length || index < 0 ) {\n\t\t\t/**\n\t\t\t * The `index` passed to {@link module:utils/collection~Collection#addMany `Collection#addMany()`}\n\t\t\t * is invalid. It must be a number between 0 and the collection's length.\n\t\t\t *\n\t\t\t * @error collection-add-item-invalid-index\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'collection-add-item-invalid-index', this );\n\t\t}\n\n\t\tfor ( let offset = 0; offset < items.length; offset++ ) {\n\t\t\tconst item = items[ offset ];\n\t\t\tconst itemId = this._getItemIdBeforeAdding( item );\n\t\t\tconst currentItemIndex = index + offset;\n\n\t\t\tthis._items.splice( currentItemIndex, 0, item );\n\t\t\tthis._itemMap.set( itemId, item );\n\n\t\t\tthis.fire( 'add', item, currentItemIndex );\n\t\t}\n\n\t\tthis.fire( 'change', {\n\t\t\tadded: items,\n\t\t\tremoved: [],\n\t\t\tindex\n\t\t} );\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets an item by its ID or index.\n\t *\n\t * @param {String|Number} idOrIndex The item ID or index in the collection.\n\t * @returns {Object|null} The requested item or `null` if such item does not exist.\n\t */\n\tget( idOrIndex ) {\n\t\tlet item;\n\n\t\tif ( typeof idOrIndex == 'string' ) {\n\t\t\titem = this._itemMap.get( idOrIndex );\n\t\t} else if ( typeof idOrIndex == 'number' ) {\n\t\t\titem = this._items[ idOrIndex ];\n\t\t} else {\n\t\t\t/**\n\t\t\t * An index or ID must be given.\n\t\t\t *\n\t\t\t * @error collection-get-invalid-arg\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'collection-get-invalid-arg', this );\n\t\t}\n\n\t\treturn item || null;\n\t}\n\n\t/**\n\t * Returns a Boolean indicating whether the collection contains an item.\n\t *\n\t * @param {Object|String} itemOrId The item or its ID in the collection.\n\t * @returns {Boolean} `true` if the collection contains the item, `false` otherwise.\n\t */\n\thas( itemOrId ) {\n\t\tif ( typeof itemOrId == 'string' ) {\n\t\t\treturn this._itemMap.has( itemOrId );\n\t\t} else { // Object\n\t\t\tconst idProperty = this._idProperty;\n\t\t\tconst id = itemOrId[ idProperty ];\n\n\t\t\treturn this._itemMap.has( id );\n\t\t}\n\t}\n\n\t/**\n\t * Gets an index of an item in the collection.\n\t * When an item is not defined in the collection, the index will equal -1.\n\t *\n\t * @param {Object|String} itemOrId The item or its ID in the collection.\n\t * @returns {Number} The index of a given item.\n\t */\n\tgetIndex( itemOrId ) {\n\t\tlet item;\n\n\t\tif ( typeof itemOrId == 'string' ) {\n\t\t\titem = this._itemMap.get( itemOrId );\n\t\t} else {\n\t\t\titem = itemOrId;\n\t\t}\n\n\t\treturn this._items.indexOf( item );\n\t}\n\n\t/**\n\t * Removes an item from the collection.\n\t *\n\t * @param {Object|Number|String} subject The item to remove, its ID or index in the collection.\n\t * @returns {Object} The removed item.\n\t * @fires remove\n\t * @fires change\n\t */\n\tremove( subject ) {\n\t\tconst [ item, index ] = this._remove( subject );\n\n\t\tthis.fire( 'change', {\n\t\t\tadded: [],\n\t\t\tremoved: [ item ],\n\t\t\tindex\n\t\t} );\n\n\t\treturn item;\n\t}\n\n\t/**\n\t * Executes the callback for each item in the collection and composes an array or values returned by this callback.\n\t *\n\t * @param {Function} callback\n\t * @param {Object} callback.item\n\t * @param {Number} callback.index\n\t * @param {Object} ctx Context in which the `callback` will be called.\n\t * @returns {Array} The result of mapping.\n\t */\n\tmap( callback, ctx ) {\n\t\treturn this._items.map( callback, ctx );\n\t}\n\n\t/**\n\t * Finds the first item in the collection for which the `callback` returns a true value.\n\t *\n\t * @param {Function} callback\n\t * @param {Object} callback.item\n\t * @param {Number} callback.index\n\t * @param {Object} ctx Context in which the `callback` will be called.\n\t * @returns {Object} The item for which `callback` returned a true value.\n\t */\n\tfind( callback, ctx ) {\n\t\treturn this._items.find( callback, ctx );\n\t}\n\n\t/**\n\t * Returns an array with items for which the `callback` returned a true value.\n\t *\n\t * @param {Function} callback\n\t * @param {Object} callback.item\n\t * @param {Number} callback.index\n\t * @param {Object} ctx Context in which the `callback` will be called.\n\t * @returns {Object[]} The array with matching items.\n\t */\n\tfilter( callback, ctx ) {\n\t\treturn this._items.filter( callback, ctx );\n\t}\n\n\t/**\n\t * Removes all items from the collection and destroys the binding created using\n\t * {@link #bindTo}.\n\t *\n\t * @fires remove\n\t * @fires change\n\t */\n\tclear() {\n\t\tif ( this._bindToCollection ) {\n\t\t\tthis.stopListening( this._bindToCollection );\n\t\t\tthis._bindToCollection = null;\n\t\t}\n\n\t\tconst removedItems = Array.from( this._items );\n\n\t\twhile ( this.length ) {\n\t\t\tthis._remove( 0 );\n\t\t}\n\n\t\tthis.fire( 'change', {\n\t\t\tadded: [],\n\t\t\tremoved: removedItems,\n\t\t\tindex: 0\n\t\t} );\n\t}\n\n\t/**\n\t * Binds and synchronizes the collection with another one.\n\t *\n\t * The binding can be a simple factory:\n\t *\n\t *\t\tclass FactoryClass {\n\t *\t\t\tconstructor( data ) {\n\t *\t\t\t\tthis.label = data.label;\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t *\t\tconst source = new Collection( { idProperty: 'label' } );\n\t *\t\tconst target = new Collection();\n\t *\n\t *\t\ttarget.bindTo( source ).as( FactoryClass );\n\t *\n\t *\t\tsource.add( { label: 'foo' } );\n\t *\t\tsource.add( { label: 'bar' } );\n\t *\n\t *\t\tconsole.log( target.length ); // 2\n\t *\t\tconsole.log( target.get( 1 ).label ); // 'bar'\n\t *\n\t *\t\tsource.remove( 0 );\n\t *\t\tconsole.log( target.length ); // 1\n\t *\t\tconsole.log( target.get( 0 ).label ); // 'bar'\n\t *\n\t * or the factory driven by a custom callback:\n\t *\n\t *\t\tclass FooClass {\n\t *\t\t\tconstructor( data ) {\n\t *\t\t\t\tthis.label = data.label;\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t *\t\tclass BarClass {\n\t *\t\t\tconstructor( data ) {\n\t *\t\t\t\tthis.label = data.label;\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t *\t\tconst source = new Collection( { idProperty: 'label' } );\n\t *\t\tconst target = new Collection();\n\t *\n\t *\t\ttarget.bindTo( source ).using( ( item ) => {\n\t *\t\t\tif ( item.label == 'foo' ) {\n\t *\t\t\t\treturn new FooClass( item );\n\t *\t\t\t} else {\n\t *\t\t\t\treturn new BarClass( item );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\tsource.add( { label: 'foo' } );\n\t *\t\tsource.add( { label: 'bar' } );\n\t *\n\t *\t\tconsole.log( target.length ); // 2\n\t *\t\tconsole.log( target.get( 0 ) instanceof FooClass ); // true\n\t *\t\tconsole.log( target.get( 1 ) instanceof BarClass ); // true\n\t *\n\t * or the factory out of property name:\n\t *\n\t *\t\tconst source = new Collection( { idProperty: 'label' } );\n\t *\t\tconst target = new Collection();\n\t *\n\t *\t\ttarget.bindTo( source ).using( 'label' );\n\t *\n\t *\t\tsource.add( { label: { value: 'foo' } } );\n\t *\t\tsource.add( { label: { value: 'bar' } } );\n\t *\n\t *\t\tconsole.log( target.length ); // 2\n\t *\t\tconsole.log( target.get( 0 ).value ); // 'foo'\n\t *\t\tconsole.log( target.get( 1 ).value ); // 'bar'\n\t *\n\t * It's possible to skip specified items by returning falsy value:\n\t *\n\t *\t\tconst source = new Collection();\n\t *\t\tconst target = new Collection();\n\t *\n\t *\t\ttarget.bindTo( source ).using( item => {\n\t *\t\t\tif ( item.hidden ) {\n\t *\t\t\t\treturn null;\n\t *\t\t\t}\n\t *\n\t *\t\t\treturn item;\n\t *\t\t} );\n\t *\n\t *\t\tsource.add( { hidden: true } );\n\t *\t\tsource.add( { hidden: false } );\n\t *\n\t *\t\tconsole.log( source.length ); // 2\n\t *\t\tconsole.log( target.length ); // 1\n\t *\n\t * **Note**: {@link #clear} can be used to break the binding.\n\t *\n\t * @param {module:utils/collection~Collection} externalCollection A collection to be bound.\n\t * @returns {Object}\n\t * @returns {module:utils/collection~CollectionBindToChain} The binding chain object.\n\t */\n\tbindTo( externalCollection ) {\n\t\tif ( this._bindToCollection ) {\n\t\t\t/**\n\t\t\t * The collection cannot be bound more than once.\n\t\t\t *\n\t\t\t * @error collection-bind-to-rebind\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'collection-bind-to-rebind', this );\n\t\t}\n\n\t\tthis._bindToCollection = externalCollection;\n\n\t\treturn {\n\t\t\tas: Class => {\n\t\t\t\tthis._setUpBindToBinding( item => new Class( item ) );\n\t\t\t},\n\n\t\t\tusing: callbackOrProperty => {\n\t\t\t\tif ( typeof callbackOrProperty == 'function' ) {\n\t\t\t\t\tthis._setUpBindToBinding( item => callbackOrProperty( item ) );\n\t\t\t\t} else {\n\t\t\t\t\tthis._setUpBindToBinding( item => item[ callbackOrProperty ] );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Finalizes and activates a binding initiated by {#bindTo}.\n\t *\n\t * @protected\n\t * @param {Function} factory A function which produces collection items.\n\t */\n\t_setUpBindToBinding( factory ) {\n\t\tconst externalCollection = this._bindToCollection;\n\n\t\t// Adds the item to the collection once a change has been done to the external collection.\n\t\t//\n\t\t// @private\n\t\tconst addItem = ( evt, externalItem, index ) => {\n\t\t\tconst isExternalBoundToThis = externalCollection._bindToCollection == this;\n\t\t\tconst externalItemBound = externalCollection._bindToInternalToExternalMap.get( externalItem );\n\n\t\t\t// If an external collection is bound to this collection, which makes it a 2–way binding,\n\t\t\t// and the particular external collection item is already bound, don't add it here.\n\t\t\t// The external item has been created **out of this collection's item** and (re)adding it will\n\t\t\t// cause a loop.\n\t\t\tif ( isExternalBoundToThis && externalItemBound ) {\n\t\t\t\tthis._bindToExternalToInternalMap.set( externalItem, externalItemBound );\n\t\t\t\tthis._bindToInternalToExternalMap.set( externalItemBound, externalItem );\n\t\t\t} else {\n\t\t\t\tconst item = factory( externalItem );\n\n\t\t\t\t// When there is no item we need to remember skipped index first and then we can skip this item.\n\t\t\t\tif ( !item ) {\n\t\t\t\t\tthis._skippedIndexesFromExternal.push( index );\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Lets try to put item at the same index as index in external collection\n\t\t\t\t// but when there are a skipped items in one or both collections we need to recalculate this index.\n\t\t\t\tlet finalIndex = index;\n\n\t\t\t\t// When we try to insert item after some skipped items from external collection we need\n\t\t\t\t// to include this skipped items and decrease index.\n\t\t\t\t//\n\t\t\t\t// For the following example:\n\t\t\t\t// external -> [ 'A', 'B - skipped for internal', 'C - skipped for internal' ]\n\t\t\t\t// internal -> [ A ]\n\t\t\t\t//\n\t\t\t\t// Another item is been added at the end of external collection:\n\t\t\t\t// external.add( 'D' )\n\t\t\t\t// external -> [ 'A', 'B - skipped for internal', 'C - skipped for internal', 'D' ]\n\t\t\t\t//\n\t\t\t\t// We can't just add 'D' to internal at the same index as index in external because\n\t\t\t\t// this will produce empty indexes what is invalid:\n\t\t\t\t// internal -> [ 'A', empty, empty, 'D' ]\n\t\t\t\t//\n\t\t\t\t// So we need to include skipped items and decrease index\n\t\t\t\t// internal -> [ 'A', 'D' ]\n\t\t\t\tfor ( const skipped of this._skippedIndexesFromExternal ) {\n\t\t\t\t\tif ( index > skipped ) {\n\t\t\t\t\t\tfinalIndex--;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// We need to take into consideration that external collection could skip some items from\n\t\t\t\t// internal collection.\n\t\t\t\t//\n\t\t\t\t// For the following example:\n\t\t\t\t// internal -> [ 'A', 'B - skipped for external', 'C - skipped for external' ]\n\t\t\t\t// external -> [ A ]\n\t\t\t\t//\n\t\t\t\t// Another item is been added at the end of external collection:\n\t\t\t\t// external.add( 'D' )\n\t\t\t\t// external -> [ 'A', 'D' ]\n\t\t\t\t//\n\t\t\t\t// We need to include skipped items and place new item after them:\n\t\t\t\t// internal -> [ 'A', 'B - skipped for external', 'C - skipped for external', 'D' ]\n\t\t\t\tfor ( const skipped of externalCollection._skippedIndexesFromExternal ) {\n\t\t\t\t\tif ( finalIndex >= skipped ) {\n\t\t\t\t\t\tfinalIndex++;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthis._bindToExternalToInternalMap.set( externalItem, item );\n\t\t\t\tthis._bindToInternalToExternalMap.set( item, externalItem );\n\t\t\t\tthis.add( item, finalIndex );\n\n\t\t\t\t// After adding new element to internal collection we need update indexes\n\t\t\t\t// of skipped items in external collection.\n\t\t\t\tfor ( let i = 0; i < externalCollection._skippedIndexesFromExternal.length; i++ ) {\n\t\t\t\t\tif ( finalIndex <= externalCollection._skippedIndexesFromExternal[ i ] ) {\n\t\t\t\t\t\texternalCollection._skippedIndexesFromExternal[ i ]++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t// Load the initial content of the collection.\n\t\tfor ( const externalItem of externalCollection ) {\n\t\t\taddItem( null, externalItem, externalCollection.getIndex( externalItem ) );\n\t\t}\n\n\t\t// Synchronize the with collection as new items are added.\n\t\tthis.listenTo( externalCollection, 'add', addItem );\n\n\t\t// Synchronize the with collection as new items are removed.\n\t\tthis.listenTo( externalCollection, 'remove', ( evt, externalItem, index ) => {\n\t\t\tconst item = this._bindToExternalToInternalMap.get( externalItem );\n\n\t\t\tif ( item ) {\n\t\t\t\tthis.remove( item );\n\t\t\t}\n\n\t\t\t// After removing element from external collection we need update/remove indexes\n\t\t\t// of skipped items in internal collection.\n\t\t\tthis._skippedIndexesFromExternal = this._skippedIndexesFromExternal.reduce( ( result, skipped ) => {\n\t\t\t\tif ( index < skipped ) {\n\t\t\t\t\tresult.push( skipped - 1 );\n\t\t\t\t}\n\n\t\t\t\tif ( index > skipped ) {\n\t\t\t\t\tresult.push( skipped );\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t}, [] );\n\t\t} );\n\t}\n\n\t/**\n\t * Returns an unique id property for a given `item`.\n\t *\n\t * The method will generate new id and assign it to the `item` if it doesn't have any.\n\t *\n\t * @private\n\t * @param {Object} item Item to be added.\n\t * @returns {String}\n\t */\n\t_getItemIdBeforeAdding( item ) {\n\t\tconst idProperty = this._idProperty;\n\t\tlet itemId;\n\n\t\tif ( ( idProperty in item ) ) {\n\t\t\titemId = item[ idProperty ];\n\n\t\t\tif ( typeof itemId != 'string' ) {\n\t\t\t\t/**\n\t\t\t\t * This item's ID should be a string.\n\t\t\t\t *\n\t\t\t\t * @error collection-add-invalid-id\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'collection-add-invalid-id', this );\n\t\t\t}\n\n\t\t\tif ( this.get( itemId ) ) {\n\t\t\t\t/**\n\t\t\t\t * This item already exists in the collection.\n\t\t\t\t *\n\t\t\t\t * @error collection-add-item-already-exists\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'collection-add-item-already-exists', this );\n\t\t\t}\n\t\t} else {\n\t\t\titem[ idProperty ] = itemId = uid();\n\t\t}\n\n\t\treturn itemId;\n\t}\n\n\t/**\n\t * Core {@link #remove} method implementation shared in other functions.\n\t *\n\t * In contrast this method **does not** fire the {@link #event:change} event.\n\t *\n\t * @private\n\t * @param {Object} subject The item to remove, its id or index in the collection.\n\t * @returns {Array} Returns an array with the removed item and its index.\n\t * @fires remove\n\t */\n\t_remove( subject ) {\n\t\tlet index, id, item;\n\t\tlet itemDoesNotExist = false;\n\t\tconst idProperty = this._idProperty;\n\n\t\tif ( typeof subject == 'string' ) {\n\t\t\tid = subject;\n\t\t\titem = this._itemMap.get( id );\n\t\t\titemDoesNotExist = !item;\n\n\t\t\tif ( item ) {\n\t\t\t\tindex = this._items.indexOf( item );\n\t\t\t}\n\t\t} else if ( typeof subject == 'number' ) {\n\t\t\tindex = subject;\n\t\t\titem = this._items[ index ];\n\t\t\titemDoesNotExist = !item;\n\n\t\t\tif ( item ) {\n\t\t\t\tid = item[ idProperty ];\n\t\t\t}\n\t\t} else {\n\t\t\titem = subject;\n\t\t\tid = item[ idProperty ];\n\t\t\tindex = this._items.indexOf( item );\n\t\t\titemDoesNotExist = ( index == -1 || !this._itemMap.get( id ) );\n\t\t}\n\n\t\tif ( itemDoesNotExist ) {\n\t\t\t/**\n\t\t\t * Item not found.\n\t\t\t *\n\t\t\t * @error collection-remove-404\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'collection-remove-404', this );\n\t\t}\n\n\t\tthis._items.splice( index, 1 );\n\t\tthis._itemMap.delete( id );\n\n\t\tconst externalItem = this._bindToInternalToExternalMap.get( item );\n\t\tthis._bindToInternalToExternalMap.delete( item );\n\t\tthis._bindToExternalToInternalMap.delete( externalItem );\n\n\t\tthis.fire( 'remove', item, index );\n\n\t\treturn [ item, index ];\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._items[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Fired when an item is added to the collection.\n\t *\n\t * @event add\n\t * @param {Object} item The added item.\n\t */\n\n\t/**\n\t * Fired when the collection was changed due to adding or removing items.\n\t *\n\t * @event change\n\t * @param {Iterable.<Object>} added A list of added items.\n\t * @param {Iterable.<Object>} removed A list of removed items.\n\t * @param {Number} index An index where the addition or removal occurred.\n\t */\n\n\t/**\n\t * Fired when an item is removed from the collection.\n\t *\n\t * @event remove\n\t * @param {Object} item The removed item.\n\t * @param {Number} index Index from which item was removed.\n\t */\n}\n\nmix( Collection, EmitterMixin );\n\n/**\n * An object returned by the {@link module:utils/collection~Collection#bindTo `bindTo()`} method\n * providing functions that specify the type of the binding.\n *\n * See the {@link module:utils/collection~Collection#bindTo `bindTo()`} documentation for examples.\n *\n * @interface module:utils/collection~CollectionBindToChain\n */\n\n/**\n * Creates a callback or a property binding.\n *\n * @method #using\n * @param {Function|String} callbackOrProperty  When the function is passed, it should return\n * the collection items. When the string is provided, the property value is used to create the bound collection items.\n */\n\n/**\n * Creates the class factory binding in which items of the source collection are passed to\n * the constructor of the specified class.\n *\n * @method #as\n * @param {Function} Class The class constructor used to create instances in the factory.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module core/plugincollection\n */\n\nimport CKEditorError, { logError } from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Manages a list of CKEditor plugins, including loading, resolving dependencies and initialization.\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class PluginCollection {\n\t/**\n\t * Creates an instance of the plugin collection class.\n\t * Allows loading and initializing plugins and their dependencies.\n\t * Allows providing a list of already loaded plugins. These plugins will not be destroyed along with this collection.\n\t *\n\t * @param {module:core/editor/editor~Editor|module:core/context~Context} context\n\t * @param {Array.<Function>} [availablePlugins] Plugins (constructors) which the collection will be able to use\n\t * when {@link module:core/plugincollection~PluginCollection#init} is used with the plugin names (strings, instead of constructors).\n\t * Usually, the editor will pass its built-in plugins to the collection so they can later be\n\t * used in `config.plugins` or `config.removePlugins` by names.\n\t * @param {Iterable.<Array>} contextPlugins A list of already initialized plugins represented by a\n\t * `[ PluginConstructor, pluginInstance ]` pair.\n\t */\n\tconstructor( context, availablePlugins = [], contextPlugins = [] ) {\n\t\t/**\n\t\t * @protected\n\t\t * @type {module:core/editor/editor~Editor|module:core/context~Context}\n\t\t */\n\t\tthis._context = context;\n\n\t\t/**\n\t\t * @protected\n\t\t * @type {Map}\n\t\t */\n\t\tthis._plugins = new Map();\n\n\t\t/**\n\t\t * A map of plugin constructors that can be retrieved by their names.\n\t\t *\n\t\t * @protected\n\t\t * @type {Map.<String|Function,Function>}\n\t\t */\n\t\tthis._availablePlugins = new Map();\n\n\t\tfor ( const PluginConstructor of availablePlugins ) {\n\t\t\tif ( PluginConstructor.pluginName ) {\n\t\t\t\tthis._availablePlugins.set( PluginConstructor.pluginName, PluginConstructor );\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Map of {@link module:core/contextplugin~ContextPlugin context plugins} which can be retrieved by their constructors or instances.\n\t\t *\n\t\t * @protected\n\t\t * @type {Map<Function,Function>}\n\t\t */\n\t\tthis._contextPlugins = new Map();\n\n\t\tfor ( const [ PluginConstructor, pluginInstance ] of contextPlugins ) {\n\t\t\tthis._contextPlugins.set( PluginConstructor, pluginInstance );\n\t\t\tthis._contextPlugins.set( pluginInstance, PluginConstructor );\n\n\t\t\t// To make it possible to require a plugin by its name.\n\t\t\tif ( PluginConstructor.pluginName ) {\n\t\t\t\tthis._availablePlugins.set( PluginConstructor.pluginName, PluginConstructor );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Returns `[ PluginConstructor, pluginInstance ]` pairs.\n\t *\n\t * @returns {Iterable.<Array>}\n\t */\n\t* [ Symbol.iterator ]() {\n\t\tfor ( const entry of this._plugins ) {\n\t\t\tif ( typeof entry[ 0 ] == 'function' ) {\n\t\t\t\tyield entry;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Gets the plugin instance by its constructor or name.\n\t *\n\t *\t\t// Check if 'Clipboard' plugin was loaded.\n\t *\t\tif ( editor.plugins.has( 'Clipboard' ) ) {\n\t *\t\t\t// Get clipboard plugin instance\n\t *\t\t\tconst clipboard = editor.plugins.get( 'Clipboard' );\n\t *\n\t *\t\t\tthis.listenTo( clipboard, 'inputTransformation', ( evt, data ) => {\n\t *\t\t\t\t// Do something on clipboard input.\n\t *\t\t\t} );\n\t *\t\t}\n\t *\n\t * **Note**: This method will throw an error if a plugin is not loaded. Use `{@link #has editor.plugins.has()}`\n\t * to check if a plugin is available.\n\t *\n\t * @param {Function|String} key The plugin constructor or {@link module:core/plugin~PluginInterface.pluginName name}.\n\t * @returns {module:core/plugin~PluginInterface}\n\t */\n\tget( key ) {\n\t\tconst plugin = this._plugins.get( key );\n\n\t\tif ( !plugin ) {\n\t\t\tlet pluginName = key;\n\n\t\t\tif ( typeof key == 'function' ) {\n\t\t\t\tpluginName = key.pluginName || key.name;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * The plugin is not loaded and could not be obtained.\n\t\t\t *\n\t\t\t * Plugin classes (constructors) need to be provided to the editor and must be loaded before they can be obtained from\n\t\t\t * the plugin collection.\n\t\t\t * This is usually done in CKEditor 5 builds by setting the {@link module:core/editor/editor~Editor.builtinPlugins}\n\t\t\t * property.\n\t\t\t *\n\t\t\t * **Note**: You can use `{@link module:core/plugincollection~PluginCollection#has editor.plugins.has()}`\n\t\t\t * to check if a plugin was loaded.\n\t\t\t *\n\t\t\t * @error plugincollection-plugin-not-loaded\n\t\t\t * @param {String} plugin The name of the plugin which is not loaded.\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'plugincollection-plugin-not-loaded', this._context, { plugin: pluginName } );\n\t\t}\n\n\t\treturn plugin;\n\t}\n\n\t/**\n\t * Checks if a plugin is loaded.\n\t *\n\t *\t\t// Check if the 'Clipboard' plugin was loaded.\n\t *\t\tif ( editor.plugins.has( 'Clipboard' ) ) {\n\t *\t\t\t// Now use the clipboard plugin instance:\n\t *\t\t\tconst clipboard = editor.plugins.get( 'Clipboard' );\n\t *\n\t *\t\t\t// ...\n\t *\t\t}\n\t *\n\t * @param {Function|String} key The plugin constructor or {@link module:core/plugin~PluginInterface.pluginName name}.\n\t * @returns {Boolean}\n\t */\n\thas( key ) {\n\t\treturn this._plugins.has( key );\n\t}\n\n\t/**\n\t * Initializes a set of plugins and adds them to the collection.\n\t *\n\t * @param {Array.<Function|String>} plugins An array of {@link module:core/plugin~PluginInterface plugin constructors}\n\t * or {@link module:core/plugin~PluginInterface.pluginName plugin names}. The second option (names) works only if\n\t * `availablePlugins` were passed to the {@link #constructor}.\n\t * @param {Array.<String|Function>} [removePlugins] Names of the plugins or plugin constructors\n\t * that should not be loaded (despite being specified in the `plugins` array).\n\t * @returns {Promise.<module:core/plugin~LoadedPlugins>} A promise which gets resolved once all plugins are loaded\n\t * and available in the collection.\n\t */\n\tinit( plugins, removePlugins = [] ) {\n\t\tconst that = this;\n\t\tconst context = this._context;\n\t\tconst loading = new Set();\n\t\tconst loaded = [];\n\n\t\tconst pluginConstructors = mapToAvailableConstructors( plugins );\n\t\tconst removePluginConstructors = mapToAvailableConstructors( removePlugins );\n\t\tconst missingPlugins = getMissingPluginNames( plugins );\n\n\t\tif ( missingPlugins ) {\n\t\t\t/**\n\t\t\t * Some plugins are not available and could not be loaded.\n\t\t\t *\n\t\t\t * Plugin classes (constructors) need to be provided to the editor before they can be loaded by name.\n\t\t\t * This is usually done in CKEditor 5 builds by setting the {@link module:core/editor/editor~Editor.builtinPlugins}\n\t\t\t * property.\n\t\t\t *\n\t\t\t * **If you see this warning when using one of the {@glink builds/index CKEditor 5 Builds}**, it means\n\t\t\t * that you try to enable a plugin which was not included in that build. This may be due to a typo\n\t\t\t * in the plugin name or simply because that plugin is not a part of this build. In the latter scenario,\n\t\t\t * read more about {@glink builds/guides/development/custom-builds custom builds}.\n\t\t\t *\n\t\t\t * **If you see this warning when using one of the editor creators directly** (not a build), then it means\n\t\t\t * that you tried loading plugins by name. However, unlike CKEditor 4, CKEditor 5 does not implement a \"plugin loader\".\n\t\t\t * This means that CKEditor 5 does not know where to load the plugin modules from. Therefore, you need to\n\t\t\t * provide each plugin through a reference (as a constructor function). Check out the examples in\n\t\t\t * {@glink builds/guides/integration/advanced-setup#scenario-2-building-from-source \"Building from source\"}.\n\t\t\t *\n\t\t\t * @error plugincollection-plugin-not-found\n\t\t\t * @param {Array.<String>} plugins The name of the plugins which could not be loaded.\n\t\t\t */\n\t\t\tconst errorId = 'plugincollection-plugin-not-found';\n\n\t\t\t// Log the error, so it's more visible on the console. Hopefully, for a better DX.\n\t\t\tlogError( errorId, { plugins: missingPlugins } );\n\n\t\t\treturn Promise.reject( new CKEditorError( errorId, context, { plugins: missingPlugins } ) );\n\t\t}\n\n\t\treturn Promise.all( pluginConstructors.map( loadPlugin ) )\n\t\t\t.then( () => initPlugins( loaded, 'init' ) )\n\t\t\t.then( () => initPlugins( loaded, 'afterInit' ) )\n\t\t\t.then( () => loaded );\n\n\t\tfunction loadPlugin( PluginConstructor ) {\n\t\t\tif ( removePluginConstructors.includes( PluginConstructor ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// The plugin is already loaded or being loaded - do nothing.\n\t\t\tif ( that._plugins.has( PluginConstructor ) || loading.has( PluginConstructor ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treturn instantiatePlugin( PluginConstructor )\n\t\t\t\t.catch( err => {\n\t\t\t\t\t/**\n\t\t\t\t\t * It was not possible to load the plugin.\n\t\t\t\t\t *\n\t\t\t\t\t * This is a generic error logged to the console when a JavaScript error is thrown during the initialization\n\t\t\t\t\t * of one of the plugins.\n\t\t\t\t\t *\n\t\t\t\t\t * If you correctly handled the promise returned by the editor's `create()` method (as shown below),\n\t\t\t\t\t * you will find the original error logged to the console, too:\n\t\t\t\t\t *\n\t\t\t\t\t *\t\tClassicEditor.create( document.getElementById( 'editor' ) )\n\t\t\t\t\t *\t\t\t.then( editor => {\n\t\t\t\t\t *\t\t\t\t// ...\n\t\t\t\t\t * \t\t\t} )\n\t\t\t\t\t *\t\t\t.catch( error => {\n\t\t\t\t\t *\t\t\t\tconsole.error( error );\n\t\t\t\t\t *\t\t\t} );\n\t\t\t\t\t *\n\t\t\t\t\t * @error plugincollection-load\n\t\t\t\t\t * @param {String} plugin The name of the plugin that could not be loaded.\n\t\t\t\t\t */\n\t\t\t\t\tlogError( 'plugincollection-load', { plugin: PluginConstructor } );\n\n\t\t\t\t\tthrow err;\n\t\t\t\t} );\n\t\t}\n\n\t\tfunction initPlugins( loadedPlugins, method ) {\n\t\t\treturn loadedPlugins.reduce( ( promise, plugin ) => {\n\t\t\t\tif ( !plugin[ method ] ) {\n\t\t\t\t\treturn promise;\n\t\t\t\t}\n\n\t\t\t\tif ( that._contextPlugins.has( plugin ) ) {\n\t\t\t\t\treturn promise;\n\t\t\t\t}\n\n\t\t\t\treturn promise.then( plugin[ method ].bind( plugin ) );\n\t\t\t}, Promise.resolve() );\n\t\t}\n\n\t\tfunction instantiatePlugin( PluginConstructor ) {\n\t\t\treturn new Promise( resolve => {\n\t\t\t\tloading.add( PluginConstructor );\n\n\t\t\t\tif ( PluginConstructor.requires ) {\n\t\t\t\t\tPluginConstructor.requires.forEach( RequiredPluginConstructorOrName => {\n\t\t\t\t\t\tconst RequiredPluginConstructor = getPluginConstructor( RequiredPluginConstructorOrName );\n\n\t\t\t\t\t\tif ( PluginConstructor.isContextPlugin && !RequiredPluginConstructor.isContextPlugin ) {\n\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t * If a plugin is a context plugin, all plugins it requires should also be context plugins\n\t\t\t\t\t\t\t * instead of plugins. In other words, if one plugin can be used in the context,\n\t\t\t\t\t\t\t * all its requirements should also be ready to be used in the context. Note that the context\n\t\t\t\t\t\t\t * provides only a part of the API provided by the editor. If one plugin needs a full\n\t\t\t\t\t\t\t * editor API, all plugins which require it are considered as plugins that need a full\n\t\t\t\t\t\t\t * editor API.\n\t\t\t\t\t\t\t *\n\t\t\t\t\t\t\t * @error plugincollection-context-required\n\t\t\t\t\t\t\t * @param {String} plugin The name of the required plugin.\n\t\t\t\t\t\t\t * @param {String} requiredBy The name of the parent plugin.\n\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t\t\t\t'plugincollection-context-required',\n\t\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t\t{ plugin: RequiredPluginConstructor.name, requiredBy: PluginConstructor.name }\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( removePlugins.includes( RequiredPluginConstructor ) ) {\n\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t * Cannot load a plugin because one of its dependencies is listed in the `removePlugins` option.\n\t\t\t\t\t\t\t *\n\t\t\t\t\t\t\t * @error plugincollection-required\n\t\t\t\t\t\t\t * @param {String} plugin The name of the required plugin.\n\t\t\t\t\t\t\t * @param {String} requiredBy The name of the parent plugin.\n\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t\t\t\t'plugincollection-required',\n\t\t\t\t\t\t\t\tcontext,\n\t\t\t\t\t\t\t\t{ plugin: RequiredPluginConstructor.name, requiredBy: PluginConstructor.name }\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tloadPlugin( RequiredPluginConstructor );\n\t\t\t\t\t} );\n\t\t\t\t}\n\n\t\t\t\tconst plugin = that._contextPlugins.get( PluginConstructor ) || new PluginConstructor( context );\n\t\t\t\tthat._add( PluginConstructor, plugin );\n\t\t\t\tloaded.push( plugin );\n\n\t\t\t\tresolve();\n\t\t\t} );\n\t\t}\n\n\t\tfunction getPluginConstructor( PluginConstructorOrName ) {\n\t\t\tif ( typeof PluginConstructorOrName == 'function' ) {\n\t\t\t\treturn PluginConstructorOrName;\n\t\t\t}\n\n\t\t\treturn that._availablePlugins.get( PluginConstructorOrName );\n\t\t}\n\n\t\tfunction getMissingPluginNames( plugins ) {\n\t\t\tconst missingPlugins = [];\n\n\t\t\tfor ( const pluginNameOrConstructor of plugins ) {\n\t\t\t\tif ( !getPluginConstructor( pluginNameOrConstructor ) ) {\n\t\t\t\t\tmissingPlugins.push( pluginNameOrConstructor );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn missingPlugins.length ? missingPlugins : null;\n\t\t}\n\n\t\tfunction mapToAvailableConstructors( plugins ) {\n\t\t\treturn plugins\n\t\t\t\t.map( pluginNameOrConstructor => getPluginConstructor( pluginNameOrConstructor ) )\n\t\t\t\t.filter( PluginConstructor => !!PluginConstructor );\n\t\t}\n\t}\n\n\t/**\n\t * Destroys all loaded plugins.\n\t *\n\t * @returns {Promise}\n\t */\n\tdestroy() {\n\t\tconst promises = [];\n\n\t\tfor ( const [ , pluginInstance ] of this ) {\n\t\t\tif ( typeof pluginInstance.destroy == 'function' && !this._contextPlugins.has( pluginInstance ) ) {\n\t\t\t\tpromises.push( pluginInstance.destroy() );\n\t\t\t}\n\t\t}\n\n\t\treturn Promise.all( promises );\n\t}\n\n\t/**\n\t * Adds the plugin to the collection. Exposed mainly for testing purposes.\n\t *\n\t * @protected\n\t * @param {Function} PluginConstructor The plugin constructor.\n\t * @param {module:core/plugin~PluginInterface} plugin The instance of the plugin.\n\t */\n\t_add( PluginConstructor, plugin ) {\n\t\tthis._plugins.set( PluginConstructor, plugin );\n\n\t\tconst pluginName = PluginConstructor.pluginName;\n\n\t\tif ( !pluginName ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this._plugins.has( pluginName ) ) {\n\t\t\t/**\n\t\t\t * Two plugins with the same {@link module:core/plugin~PluginInterface.pluginName} were loaded.\n\t\t\t * This will lead to runtime conflicts between these plugins.\n\t\t\t *\n\t\t\t * In practice, this warning usually means that new plugins were added to an existing CKEditor 5 build.\n\t\t\t * Plugins should always be added to a source version of the editor (`@ckeditor/ckeditor5-editor-*`),\n\t\t\t * not to an editor imported from one of the `@ckeditor/ckeditor5-build-*` packages.\n\t\t\t *\n\t\t\t * Check your import paths and the list of plugins passed to\n\t\t\t * {@link module:core/editor/editor~Editor.create `Editor.create()`}\n\t\t\t * or specified in {@link module:core/editor/editor~Editor.builtinPlugins `Editor.builtinPlugins`}.\n\t\t\t *\n\t\t\t * The second option is that your `node_modules/` directory contains duplicated versions of the same\n\t\t\t * CKEditor 5 packages. Normally, on clean installations, npm deduplicates packages in `node_modules/`, so\n\t\t\t * it may be enough to call `rm -rf node_modules && npm i`. However, if you installed conflicting versions\n\t\t\t * of some packages, their dependencies may need to be installed in more than one version which may lead to this\n\t\t\t * warning.\n\t\t\t *\n\t\t\t * Technically speaking, this error occurs because after adding a plugin to an existing editor build\n\t\t\t * the dependencies of this plugin are being duplicated.\n\t\t\t * They are already built into that editor build and now get added for the second time as dependencies\n\t\t\t * of the plugin you are installing.\n\t\t\t *\n\t\t\t * Read more about {@glink builds/guides/integration/installing-plugins installing plugins}.\n\t\t\t *\n\t\t\t * @error plugincollection-plugin-name-conflict\n\t\t\t * @param {String} pluginName The duplicated plugin name.\n\t\t\t * @param {Function} plugin1 The first plugin constructor.\n\t\t\t * @param {Function} plugin2 The second plugin constructor.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'plugincollection-plugin-name-conflict',\n\t\t\t\tnull,\n\t\t\t\t{ pluginName, plugin1: this._plugins.get( pluginName ).constructor, plugin2: PluginConstructor }\n\t\t\t);\n\t\t}\n\n\t\tthis._plugins.set( pluginName, plugin );\n\t}\n}\n\nmix( PluginCollection, EmitterMixin );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/toarray\n */\n\n/**\n * Transforms any value to an array. If the provided value is already an array, it is returned unchanged.\n *\n * @param {*} data Value to transform to an array.\n * @returns {Array} Array created from data.\n */\nexport default function toArray( data ) {\n\treturn Array.isArray( data ) ? data : [ data ];\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* globals window */\n\n/**\n * @module utils/translation-service\n */\n\nimport CKEditorError from './ckeditorerror';\n\n/* istanbul ignore else */\nif ( !window.CKEDITOR_TRANSLATIONS ) {\n\twindow.CKEDITOR_TRANSLATIONS = {};\n}\n\n/**\n * Adds translations to existing ones or overrides the existing translations. These translations will later\n * be available for the {@link module:utils/locale~Locale#t `t()`} function.\n *\n * The `translations` is an object which consists of `messageId: translation` pairs. Note that the message ID can be\n * either constructed from the message string or from the message ID if it was passed\n * (this happens rarely and mostly for short messages or messages with placeholders).\n * Since the editor displays only the message string, the message ID can be found either in the source code or in the\n * built translations for another language.\n *\n *\t\tadd( 'pl', {\n *\t\t\t'Cancel': 'Anuluj',\n *\t\t\t'IMAGE': 'obraz', // Note that the `IMAGE` comes from the message ID, while the string can be `image`.\n *\t\t} );\n *\n * If the message is supposed to support various plural forms, make sure to provide an array with the singular form and all plural forms:\n *\n *\t\tadd( 'pl', {\n *\t \t\t'Add space': [ 'Dodaj spację', 'Dodaj %0 spacje', 'Dodaj %0 spacji' ]\n * \t\t} );\n *\n * You should also specify the third argument (the `getPluralForm()` function) that will be used to determine the plural form if no\n * language file was loaded for that language. All language files coming from CKEditor 5 sources will have this option set, so\n * these plural form rules will be reused by other translations added to the registered languages. The `getPluralForm()` function\n * can return either a Boolean or a number.\n *\n * \t\tadd( 'en', {\n *\t \t\t// ... Translations.\n * \t\t}, n => n !== 1 );\n * \t\tadd( 'pl', {\n *\t \t\t// ... Translations.\n * \t\t}, n => n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && ( n % 100 < 10 || n % 100 >= 20 ) ? 1 : 2 );\n *\n * All translations extend the global `window.CKEDITOR_TRANSLATIONS` object. An example of this object can be found below:\n *\n * \t\t{\n * \t\t\tpl: {\n *\t\t\t\tdictionary: {\n *\t\t\t\t\t'Cancel': 'Anuluj',\n *\t\t\t\t\t'Add space': [ 'Dodaj spację', 'Dodaj %0 spacje', 'Dodaj %0 spacji' ]\n *\t\t\t\t},\n *\t\t\t\t// A function that returns the plural form index.\n *\t\t\t\tgetPluralForm: n => n !==1\n *\t\t\t}\n *\t\t\t// Other languages.\n *\t\t}\n *\n * If you cannot import this function from this module (e.g. because you use a CKEditor 5 build), you can\n * still add translations by extending the global `window.CKEDITOR_TRANSLATIONS` object by using a function like\n * the one below:\n *\n *\t\tfunction addTranslations( language, translations, getPluralForm ) {\n *\t\t\tif ( !window.CKEDITOR_TRANSLATIONS ) {\n *\t\t\t\twindow.CKEDITOR_TRANSLATIONS = {};\n *\t\t\t}\n\n *\t\t\tif ( !window.CKEDITOR_TRANSLATIONS[ language ] ) {\n *\t\t\t\twindow.CKEDITOR_TRANSLATIONS[ language ] = {};\n *\t\t\t}\n *\n *\t\t\tconst languageTranslations = window.CKEDITOR_TRANSLATIONS[ language ];\n *\n * \t\t\tlanguageTranslations.dictionary = languageTranslations.dictionary || {};\n * \t\t\tlanguageTranslations.getPluralForm = getPluralForm || languageTranslations.getPluralForm;\n *\n *\t\t\t// Extend the dictionary for the given language.\n *\t\t\tObject.assign( languageTranslations.dictionary, translations );\n *\t\t}\n *\n * @param {String} language Target language.\n * @param {Object.<String,*>} translations An object with translations which will be added to the dictionary.\n * For each message ID the value should be either a translation or an array of translations if the message\n * should support plural forms.\n * @param {Function} getPluralForm A function that returns the plural form index (a number).\n */\nexport function add( language, translations, getPluralForm ) {\n\tif ( !window.CKEDITOR_TRANSLATIONS[ language ] ) {\n\t\twindow.CKEDITOR_TRANSLATIONS[ language ] = {};\n\t}\n\n\tconst languageTranslations = window.CKEDITOR_TRANSLATIONS[ language ];\n\n\tlanguageTranslations.dictionary = languageTranslations.dictionary || {};\n\tlanguageTranslations.getPluralForm = getPluralForm || languageTranslations.getPluralForm;\n\n\tObject.assign( languageTranslations.dictionary, translations );\n}\n\n/**\n * **Note:** This method is internal, use {@link module:utils/locale~Locale#t the `t()` function} instead to translate\n * the editor UI parts.\n *\n * This function is responsible for translating messages to the specified language. It uses translations added perviously\n * by {@link module:utils/translation-service~add} (a translations dictionary and the `getPluralForm()` function\n * to provide accurate translations of plural forms).\n *\n * When no translation is defined in the dictionary or the dictionary does not exist, this function returns\n * the original message string or the message plural depending on the number of elements.\n *\n *\t\ttranslate( 'pl', { string: 'Cancel' } ); // 'Cancel'\n *\n * The third optional argument is the number of elements, based on which the single form or one of the plural forms\n * should be picked when the message is supposed to support various plural forms.\n *\n * \t\ttranslate( 'en', { string: 'Add a space', plural: 'Add %0 spaces' }, 1 ); // 'Add a space'\n * \t\ttranslate( 'en', { string: 'Add a space', plural: 'Add %0 spaces' }, 3 ); // 'Add %0 spaces'\n *\n * The message should provide an ID using the `id` property when the message strings are not unique and their\n * translations should be different.\n *\n *\t\ttranslate( 'en', { string: 'image', id: 'ADD_IMAGE' } );\n *\t\ttranslate( 'en', { string: 'image', id: 'AN_IMAGE' } );\n *\n * @protected\n * @param {String} language Target language.\n * @param {module:utils/translation-service~Message|String} message A message that will be translated.\n * @param {Number} [quantity] The number of elements for which a plural form should be picked from the target language dictionary.\n * @returns {String} Translated sentence.\n */\nexport function _translate( language, message, quantity = 1 ) {\n\tif ( typeof quantity !== 'number' ) {\n\t\t/**\n\t\t * An incorrect value was passed to the translation function. This was probably caused\n\t\t * by an incorrect message interpolation of a plural form. Note that for messages supporting plural forms\n\t\t * the second argument of the `t()` function should always be a number or an array with a number as the first element.\n\t\t *\n\t\t * @error translation-service-quantity-not-a-number\n\t\t */\n\t\tthrow new CKEditorError( 'translation-service-quantity-not-a-number', null, { quantity } );\n\t}\n\n\tconst numberOfLanguages = getNumberOfLanguages();\n\n\tif ( numberOfLanguages === 1 ) {\n\t\t// Override the language to the only supported one.\n\t\t// This can't be done in the `Locale` class, because the translations comes after the `Locale` class initialization.\n\t\tlanguage = Object.keys( window.CKEDITOR_TRANSLATIONS )[ 0 ];\n\t}\n\n\tconst messageId = message.id || message.string;\n\n\tif ( numberOfLanguages === 0 || !hasTranslation( language, messageId ) ) {\n\t\tif ( quantity !== 1 ) {\n\t\t\t// Return the default plural form that was passed in the `message.plural` parameter.\n\t\t\treturn message.plural;\n\t\t}\n\n\t\treturn message.string;\n\t}\n\n\tconst dictionary = window.CKEDITOR_TRANSLATIONS[ language ].dictionary;\n\tconst getPluralForm = window.CKEDITOR_TRANSLATIONS[ language ].getPluralForm || ( n => n === 1 ? 0 : 1 );\n\n\tif ( typeof dictionary[ messageId ] === 'string' ) {\n\t\treturn dictionary[ messageId ];\n\t}\n\n\tconst pluralFormIndex = Number( getPluralForm( quantity ) );\n\n\t// Note: The `translate` function is not responsible for replacing `%0, %1, ...` with values.\n\treturn dictionary[ messageId ][ pluralFormIndex ];\n}\n\n/**\n * Clears dictionaries for test purposes.\n *\n * @protected\n */\nexport function _clear() {\n\twindow.CKEDITOR_TRANSLATIONS = {};\n}\n\n// Checks whether the dictionary exists and translation in that dictionary exists.\nfunction hasTranslation( language, messageId ) {\n\treturn (\n\t\t!!window.CKEDITOR_TRANSLATIONS[ language ] &&\n\t\t!!window.CKEDITOR_TRANSLATIONS[ language ].dictionary[ messageId ]\n\t);\n}\n\nfunction getNumberOfLanguages() {\n\treturn Object.keys( window.CKEDITOR_TRANSLATIONS ).length;\n}\n\n/**\n * The internationalization message interface. A message that implements this interface can be passed to the `t()` function\n * to be translated to the target UI language.\n *\n * @typedef {Object} module:utils/translation-service~Message\n *\n * @property {String} string The message string to translate. Acts as a default translation if the translation for a given language\n * is not defined. When the message is supposed to support plural forms, the string should be the English singular form of the message.\n * @property {String} [id] The message ID. If passed, the message ID is taken from this property instead of the `message.string`.\n * This property is useful when various messages share the same message string, for example, the `editor` string in `in the editor`\n * and `my editor` sentences.\n * @property {String} [plural] The plural form of the message. This property should be skipped when a message is not supposed\n * to support plural forms. Otherwise it should always be set to a string with the English plural form of the message.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/locale\n */\n\n/* globals console */\n\nimport toArray from './toarray';\nimport { _translate } from './translation-service';\n\nconst RTL_LANGUAGE_CODES = [ 'ar', 'fa', 'he', 'ku', 'ug' ];\n\n/**\n * Represents the localization services.\n */\nexport default class Locale {\n\t/**\n\t * Creates a new instance of the locale class. Learn more about\n\t * {@glink features/ui-language configuring the language of the editor}.\n\t *\n\t * @param {Object} [options] Locale configuration.\n\t * @param {String} [options.uiLanguage='en'] The editor UI language code in the\n\t * [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format. See {@link #uiLanguage}.\n\t * @param {String} [options.contentLanguage] The editor content language code in the\n\t * [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format. If not specified, the same as `options.language`.\n\t * See {@link #contentLanguage}.\n\t */\n\tconstructor( options = {} ) {\n\t\t/**\n\t\t * The editor UI language code in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format.\n\t\t *\n\t\t * If the {@link #contentLanguage content language} was not specified in the `Locale` constructor,\n\t\t * it also defines the language of the content.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.uiLanguage = options.uiLanguage || 'en';\n\n\t\t/**\n\t\t * The editor content language code in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format.\n\t\t *\n\t\t * Usually the same as the {@link #uiLanguage editor language}, it can be customized by passing an optional\n\t\t * argument to the `Locale` constructor.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.contentLanguage = options.contentLanguage || this.uiLanguage;\n\n\t\t/**\n\t\t * Text direction of the {@link #uiLanguage editor UI language}. Either `'ltr'` or `'rtl'`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.uiLanguageDirection = getLanguageDirection( this.uiLanguage );\n\n\t\t/**\n\t\t * Text direction of the {@link #contentLanguage editor content language}.\n\t\t *\n\t\t * If the content language was passed directly to the `Locale` constructor, this property represents the\n\t\t * direction of that language.\n\t\t *\n\t\t * If the {@link #contentLanguage editor content language} was derived from the {@link #uiLanguage editor language},\n\t\t * the content language direction is the same as the {@link #uiLanguageDirection UI language direction}.\n\t\t *\n\t\t * The value is either `'ltr'` or `'rtl'`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.contentLanguageDirection = getLanguageDirection( this.contentLanguage );\n\n\t\t/**\n\t\t * Translates the given message to the {@link #uiLanguage}. This method is also available in\n\t\t * {@link module:core/editor/editor~Editor#t `Editor`} and {@link module:ui/view~View#t `View`}.\n\t\t *\n\t\t * This method's context is statically bound to the `Locale` instance and **should always be called as a function**:\n\t\t *\n\t\t *\t\tconst t = locale.t;\n\t\t *\t\tt( 'Label' );\n\t\t *\n\t\t * The message can be either a string or an object implementing the {@link module:utils/translation-service~Message} interface.\n\t\t *\n\t\t * The message may contain placeholders (`%<index>`) for value(s) that are passed as a `values` parameter.\n\t\t * For an array of values, the `%<index>` will be changed to an element of that array at the given index.\n\t\t * For a single value passed as the second argument, only the `%0` placeholders will be changed to the provided value.\n\t\t *\n\t\t *\t\tt( 'Created file \"%0\" in %1ms.', [ fileName, timeTaken ] );\n\t\t * \t\tt( 'Created file \"%0\", fileName );\n\t\t *\n\t\t * The message supports plural forms. To specify the plural form, use the `plural` property. Singular or plural form\n\t\t * will be chosen depending on the first value from the passed `values`. The value of the `plural` property is used\n\t\t * as a default plural translation when the translation for the target language is missing.\n\t\t *\n\t\t *\t\tt( { string: 'Add a space', plural: 'Add %0 spaces' }, 1 ); // 'Add a space' for the English language.\n\t\t *\t\tt( { string: 'Add a space', plural: 'Add %0 spaces' }, 5 ); // 'Add 5 spaces' for the English language.\n\t\t *\t\tt( { string: '%1 a space', plural: '%1 %0 spaces' }, [ 2, 'Add' ] ); // 'Add 2 spaces' for the English language.\n\t\t *\n\t\t * \t\tt( { string: 'Add a space', plural: 'Add %0 spaces' }, 1 ); // 'Dodaj spację' for the Polish language.\n\t\t *\t\tt( { string: 'Add a space', plural: 'Add %0 spaces' }, 5 ); // 'Dodaj 5 spacji' for the Polish language.\n\t\t *\t\tt( { string: '%1 a space', plural: '%1 %0 spaces' }, [ 2, 'Add' ] ); // 'Dodaj 2 spacje' for the Polish language.\n\t\t *\n\t\t *  * The message should provide an ID using the `id` property when the message strings are not unique and their\n\t\t * translations should be different.\n\t\t *\n\t\t *\t\ttranslate( 'en', { string: 'image', id: 'ADD_IMAGE' } );\n\t\t *\t\ttranslate( 'en', { string: 'image', id: 'AN_IMAGE' } );\n\t\t *\n\t\t * @method #t\n\t\t * @param {String|module:utils/translation-service~Message} message A message that will be localized (translated).\n\t\t * @param {String|Number|Array.<String|Number>} [values] A value or an array of values that will fill message placeholders.\n\t\t * For messages supporting plural forms the first value will determine the plural form.\n\t\t * @returns {String}\n\t\t */\n\t\tthis.t = ( message, values ) => this._t( message, values );\n\t}\n\n\t/**\n\t * The editor UI language code in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format.\n\t *\n\t * **Note**: This property was deprecated. Please use {@link #uiLanguage} and {@link #contentLanguage}\n\t * properties instead.\n\t *\n\t * @deprecated\n\t * @member {String}\n\t */\n\tget language() {\n\t\t/**\n\t\t * The {@link module:utils/locale~Locale#language `Locale#language`} property was deprecated and will\n\t\t * be removed in the near future. Please use the {@link #uiLanguage} and {@link #contentLanguage} properties instead.\n\t\t *\n\t\t * @error locale-deprecated-language-property\n\t\t */\n\t\tconsole.warn(\n\t\t\t'locale-deprecated-language-property: ' +\n\t\t\t'The Locale#language property has been deprecated and will be removed in the near future. ' +\n\t\t\t'Please use #uiLanguage and #contentLanguage properties instead.' );\n\n\t\treturn this.uiLanguage;\n\t}\n\n\t/**\n\t * An unbound version of the {@link #t} method.\n\t *\n\t * @private\n\t * @param {String|module:utils/translation-service~Message} message\n\t * @param {Number|String|Array.<Number|String>} [values]\n\t * @returns {String}\n\t */\n\t_t( message, values = [] ) {\n\t\tvalues = toArray( values );\n\n\t\tif ( typeof message === 'string' ) {\n\t\t\tmessage = { string: message };\n\t\t}\n\n\t\tconst hasPluralForm = !!message.plural;\n\t\tconst quantity = hasPluralForm ? values[ 0 ] : 1;\n\n\t\tconst translatedString = _translate( this.uiLanguage, message, quantity );\n\n\t\treturn interpolateString( translatedString, values );\n\t}\n}\n\n// Fills the `%0, %1, ...` string placeholders with values.\nfunction interpolateString( string, values ) {\n\treturn string.replace( /%(\\d+)/g, ( match, index ) => {\n\t\treturn ( index < values.length ) ? values[ index ] : match;\n\t} );\n}\n\n// Helps determine whether a language is LTR or RTL.\n//\n// @param {String} language The ISO 639-1 language code.\n// @returns {String} 'ltr' or 'rtl\nfunction getLanguageDirection( languageCode ) {\n\treturn RTL_LANGUAGE_CODES.includes( languageCode ) ? 'rtl' : 'ltr';\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module core/context\n */\n\nimport Config from '@ckeditor/ckeditor5-utils/src/config';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport PluginCollection from './plugincollection';\nimport Locale from '@ckeditor/ckeditor5-utils/src/locale';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Provides a common, higher-level environment for solutions that use multiple {@link module:core/editor/editor~Editor editors}\n * or plugins that work outside the editor. Use it instead of {@link module:core/editor/editor~Editor.create `Editor.create()`}\n * in advanced application integrations.\n *\n * All configuration options passed to a context will be used as default options for editor instances initialized in that context.\n *\n * {@link module:core/contextplugin~ContextPlugin Context plugins} passed to a context instance will be shared among all\n * editor instances initialized in this context. These will be the same plugin instances for all the editors.\n *\n * **Note:** The context can only be initialized with {@link module:core/contextplugin~ContextPlugin context plugins}\n * (e.g. [comments](https://ckeditor.com/collaboration/comments/)). Regular {@link module:core/plugin~Plugin plugins} require an\n * editor instance to work and cannot be added to a context.\n *\n * **Note:** You can add a context plugin to an editor instance, though.\n *\n * If you are using multiple editor instances on one page and use any context plugins, create a context to share the configuration and\n * plugins among these editors. Some plugins will use the information about all existing editors to better integrate between them.\n *\n * If you are using plugins that do not require an editor to work (e.g. [comments](https://ckeditor.com/collaboration/comments/)),\n * enable and configure them using the context.\n *\n * If you are using only a single editor on each page, use {@link module:core/editor/editor~Editor.create `Editor.create()`} instead.\n * In such case, a context instance will be created by the editor instance in a transparent way.\n *\n * See {@link module:core/context~Context.create `Context.create()`} for usage examples.\n */\nexport default class Context {\n\t/**\n\t * Creates a context instance with a given configuration.\n\t *\n\t * Usually not to be used directly. See the static {@link module:core/context~Context.create `create()`} method.\n\t *\n\t * @param {Object} [config={}] The context configuration.\n\t */\n\tconstructor( config ) {\n\t\t/**\n\t\t * Stores all the configurations specific to this context instance.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:utils/config~Config}\n\t\t */\n\t\tthis.config = new Config( config, this.constructor.defaultConfig );\n\n\t\tconst availablePlugins = this.constructor.builtinPlugins;\n\n\t\tthis.config.define( 'plugins', availablePlugins );\n\n\t\t/**\n\t\t * The plugins loaded and in use by this context instance.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:core/plugincollection~PluginCollection}\n\t\t */\n\t\tthis.plugins = new PluginCollection( this, availablePlugins );\n\n\t\tconst languageConfig = this.config.get( 'language' ) || {};\n\n\t\t/**\n\t\t * @readonly\n\t\t * @type {module:utils/locale~Locale}\n\t\t */\n\t\tthis.locale = new Locale( {\n\t\t\tuiLanguage: typeof languageConfig === 'string' ? languageConfig : languageConfig.ui,\n\t\t\tcontentLanguage: this.config.get( 'language.content' )\n\t\t} );\n\n\t\t/**\n\t\t * Shorthand for {@link module:utils/locale~Locale#t}.\n\t\t *\n\t\t * @see module:utils/locale~Locale#t\n\t\t * @method #t\n\t\t */\n\t\tthis.t = this.locale.t;\n\n\t\t/**\n\t\t * A list of editors that this context instance is injected to.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:utils/collection~Collection}\n\t\t */\n\t\tthis.editors = new Collection();\n\n\t\t/**\n\t\t * Reference to the editor which created the context.\n\t\t * Null when the context was created outside of the editor.\n\t\t *\n\t\t * It is used to destroy the context when removing the editor that has created the context.\n\t\t *\n\t\t * @private\n\t\t * @type {module:core/editor/editor~Editor|null}\n\t\t */\n\t\tthis._contextOwner = null;\n\t}\n\n\t/**\n\t * Loads and initializes plugins specified in the configuration.\n\t *\n\t * @returns {Promise.<module:core/plugin~LoadedPlugins>} A promise which resolves\n\t * once the initialization is completed, providing an array of loaded plugins.\n\t */\n\tinitPlugins() {\n\t\tconst plugins = this.config.get( 'plugins' ) || [];\n\n\t\tfor ( const Plugin of plugins ) {\n\t\t\tif ( typeof Plugin != 'function' ) {\n\t\t\t\t/**\n\t\t\t\t * Only a constructor function is allowed as a {@link module:core/contextplugin~ContextPlugin context plugin}.\n\t\t\t\t *\n\t\t\t\t * @error context-initplugins-constructor-only\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'context-initplugins-constructor-only',\n\t\t\t\t\tnull,\n\t\t\t\t\t{ Plugin }\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif ( Plugin.isContextPlugin !== true ) {\n\t\t\t\t/**\n\t\t\t\t * Only a plugin marked as a {@link module:core/contextplugin~ContextPlugin.isContextPlugin context plugin}\n\t\t\t\t * is allowed to be used with a context.\n\t\t\t\t *\n\t\t\t\t * @error context-initplugins-invalid-plugin\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'context-initplugins-invalid-plugin',\n\t\t\t\t\tnull,\n\t\t\t\t\t{ Plugin }\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn this.plugins.init( plugins );\n\t}\n\n\t/**\n\t * Destroys the context instance and all editors used with the context,\n\t * releasing all resources used by the context.\n\t *\n\t * @returns {Promise} A promise that resolves once the context instance is fully destroyed.\n\t */\n\tdestroy() {\n\t\treturn Promise.all( Array.from( this.editors, editor => editor.destroy() ) )\n\t\t\t.then( () => this.plugins.destroy() );\n\t}\n\n\t/**\n\t * Adds a reference to the editor which is used with this context.\n\t *\n\t * When the given editor has created the context, the reference to this editor will be stored\n\t * as a {@link ~Context#_contextOwner}.\n\t *\n\t * This method should only be used by the editor.\n\t *\n\t * @protected\n\t * @param {module:core/editor/editor~Editor} editor\n\t * @param {Boolean} isContextOwner Stores the given editor as a context owner.\n\t */\n\t_addEditor( editor, isContextOwner ) {\n\t\tif ( this._contextOwner ) {\n\t\t\t/**\n\t\t\t * Cannot add multiple editors to the context which is created by the editor.\n\t\t\t *\n\t\t\t * @error context-addeditor-private-context\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'context-addeditor-private-context' );\n\t\t}\n\n\t\tthis.editors.add( editor );\n\n\t\tif ( isContextOwner ) {\n\t\t\tthis._contextOwner = editor;\n\t\t}\n\t}\n\n\t/**\n\t * Removes a reference to the editor which was used with this context.\n\t * When the context was created by the given editor, the context will be destroyed.\n\t *\n\t * This method should only be used by the editor.\n\t *\n\t * @protected\n\t * @param {module:core/editor/editor~Editor} editor\n\t * @return {Promise} A promise that resolves once the editor is removed from the context or when the context was destroyed.\n\t */\n\t_removeEditor( editor ) {\n\t\tif ( this.editors.has( editor ) ) {\n\t\t\tthis.editors.remove( editor );\n\t\t}\n\n\t\tif ( this._contextOwner === editor ) {\n\t\t\treturn this.destroy();\n\t\t}\n\n\t\treturn Promise.resolve();\n\t}\n\n\t/**\n\t * Returns the context configuration which will be copied to the editors created using this context.\n\t *\n\t * The configuration returned by this method has the plugins configuration removed &mdash; plugins are shared with all editors\n\t * through another mechanism.\n\t *\n\t * This method should only be used by the editor.\n\t *\n\t * @protected\n\t * @returns {Object} Configuration as a plain object.\n\t */\n\t_getEditorConfig() {\n\t\tconst result = {};\n\n\t\tfor ( const name of this.config.names() ) {\n\t\t\tif ( ![ 'plugins', 'removePlugins', 'extraPlugins' ].includes( name ) ) {\n\t\t\t\tresult[ name ] = this.config.get( name );\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Creates and initializes a new context instance.\n\t *\n\t *\t\tconst commonConfig = { ... }; // Configuration for all the plugins and editors.\n\t *\t\tconst editorPlugins = [ ... ]; // Regular plugins here.\n\t *\n\t *\t\tContext\n\t *\t\t\t.create( {\n\t *\t\t\t\t// Only context plugins here.\n\t *\t\t\t\tplugins: [ ... ],\n\t *\n\t *\t\t\t\t// Configure the language for all the editors (it cannot be overwritten).\n\t *\t\t\t\tlanguage: { ... },\n\t *\n\t *\t\t\t\t// Configuration for context plugins.\n\t *\t\t\t\tcomments: { ... },\n\t *\t\t\t\t...\n\t *\n\t *\t\t\t\t// Default configuration for editor plugins.\n\t *\t\t\t\ttoolbar: { ... },\n\t *\t\t\t\timage: { ... },\n\t *\t\t\t\t...\n\t *\t\t\t} )\n\t *\t\t\t.then( context => {\n\t *\t\t\t\tconst promises = [];\n\t *\n\t *\t\t\t\tpromises.push( ClassicEditor.create(\n\t *\t\t\t\t\tdocument.getElementById( 'editor1' ),\n\t *\t\t\t\t\t{\n\t *\t\t\t\t\t\teditorPlugins,\n\t *\t\t\t\t\t\tcontext\n\t *\t\t\t\t\t}\n\t *\t\t\t\t) );\n\t *\n\t *\t\t\t\tpromises.push( ClassicEditor.create(\n\t *\t\t\t\t\tdocument.getElementById( 'editor2' ),\n\t *\t\t\t\t\t{\n\t *\t\t\t\t\t\teditorPlugins,\n\t *\t\t\t\t\t\tcontext,\n\t *\t\t\t\t\t\ttoolbar: { ... } // You can overwrite the configuration of the context.\n\t *\t\t\t\t\t}\n\t *\t\t\t\t) );\n\t *\n\t *\t\t\t\treturn Promise.all( promises );\n\t *\t\t\t} );\n\t *\n\t * @param {Object} [config] The context configuration.\n\t * @returns {Promise} A promise resolved once the context is ready. The promise resolves with the created context instance.\n\t */\n\tstatic create( config ) {\n\t\treturn new Promise( resolve => {\n\t\t\tconst context = new this( config );\n\n\t\t\tresolve( context.initPlugins().then( () => context ) );\n\t\t} );\n\t}\n}\n\n/**\n * An array of plugins built into the `Context` class.\n *\n * It is used in CKEditor 5 builds featuring `Context` to provide a list of context plugins which are later automatically initialized\n * during the context initialization.\n *\n * They will be automatically initialized by `Context` unless `config.plugins` is passed.\n *\n *\t\t// Build some context plugins into the Context class first.\n *\t\tContext.builtinPlugins = [ FooPlugin, BarPlugin ];\n *\n *\t\t// Normally, you need to define config.plugins, but since Context.builtinPlugins was\n *\t\t// defined, now you can call create() without any configuration.\n *\t\tContext\n *\t\t\t.create()\n *\t\t\t.then( context => {\n *\t\t\t\tcontext.plugins.get( FooPlugin ); // -> An instance of the Foo plugin.\n *\t\t\t\tcontext.plugins.get( BarPlugin ); // -> An instance of the Bar plugin.\n *\t\t\t} );\n *\n * See also {@link module:core/context~Context.defaultConfig `Context.defaultConfig`}\n * and {@link module:core/editor/editor~Editor.builtinPlugins `Editor.builtinPlugins`}.\n *\n * @static\n * @member {Array.<Function>} module:core/context~Context.builtinPlugins\n */\n\n/**\n * The default configuration which is built into the `Context` class.\n *\n * It is used in CKEditor 5 builds featuring `Context` to provide the default configuration options which are later used during the\n * context initialization.\n *\n *\t\tContext.defaultConfig = {\n *\t\t\tfoo: 1,\n *\t\t\tbar: 2\n *\t\t};\n *\n *\t\tContext\n *\t\t\t.create()\n *\t\t\t.then( context => {\n *\t\t\t\tcontext.config.get( 'foo' ); // -> 1\n *\t\t\t\tcontext.config.get( 'bar' ); // -> 2\n *\t\t\t} );\n *\n *\t\t// The default options can be overridden by the configuration passed to create().\n *\t\tContext\n *\t\t\t.create( { bar: 3 } )\n *\t\t\t.then( context => {\n *\t\t\t\tcontext.config.get( 'foo' ); // -> 1\n *\t\t\t\tcontext.config.get( 'bar' ); // -> 3\n *\t\t\t} );\n *\n * See also {@link module:core/context~Context.builtinPlugins `Context.builtinPlugins`}\n * and {@link module:core/editor/editor~Editor.defaultConfig `Editor.defaultConfig`}.\n *\n * @static\n * @member {Object} module:core/context~Context.defaultConfig\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/comparearrays\n */\n\n/**\n * Compares how given arrays relate to each other. One array can be: same as another array, prefix of another array\n * or completely different. If arrays are different, first index at which they differ is returned. Otherwise,\n * a flag specifying the relation is returned. Flags are negative numbers, so whenever a number >= 0 is returned\n * it means that arrays differ.\n *\n *\t\tcompareArrays( [ 0, 2 ], [ 0, 2 ] );\t\t// 'same'\n *\t\tcompareArrays( [ 0, 2 ], [ 0, 2, 1 ] );\t\t// 'prefix'\n *\t\tcompareArrays( [ 0, 2 ], [ 0 ] );\t\t\t// 'extension'\n *\t\tcompareArrays( [ 0, 2 ], [ 1, 2 ] );\t\t// 0\n *\t\tcompareArrays( [ 0, 2 ], [ 0, 1 ] );\t\t// 1\n *\n * @param {Array} a Array that is compared.\n * @param {Array} b Array to compare with.\n * @returns {module:utils/comparearrays~ArrayRelation} How array `a` is related to `b`.\n */\nexport default function compareArrays( a, b ) {\n\tconst minLen = Math.min( a.length, b.length );\n\n\tfor ( let i = 0; i < minLen; i++ ) {\n\t\tif ( a[ i ] != b[ i ] ) {\n\t\t\t// The arrays are different.\n\t\t\treturn i;\n\t\t}\n\t}\n\n\t// Both arrays were same at all points.\n\tif ( a.length == b.length ) {\n\t\t// If their length is also same, they are the same.\n\t\treturn 'same';\n\t} else if ( a.length < b.length ) {\n\t\t// Compared array is shorter so it is a prefix of the other array.\n\t\treturn 'prefix';\n\t} else {\n\t\t// Compared array is longer so it is an extension of the other array.\n\t\treturn 'extension';\n\t}\n}\n\n/**\n * @typedef {'extension'|'same'|'prefix'} module:utils/comparearrays~ArrayRelation\n */\n","import baseClone from './_baseClone.js';\n\n/** Used to compose bitmasks for cloning. */\nvar CLONE_SYMBOLS_FLAG = 4;\n\n/**\n * Creates a shallow clone of `value`.\n *\n * **Note:** This method is loosely based on the\n * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm)\n * and supports cloning arrays, array buffers, booleans, date objects, maps,\n * numbers, `Object` objects, regexes, sets, strings, symbols, and typed\n * arrays. The own enumerable properties of `arguments` objects are cloned\n * as plain objects. An empty object is returned for uncloneable values such\n * as error objects, functions, DOM nodes, and WeakMaps.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to clone.\n * @returns {*} Returns the cloned value.\n * @see _.cloneDeep\n * @example\n *\n * var objects = [{ 'a': 1 }, { 'b': 2 }];\n *\n * var shallow = _.clone(objects);\n * console.log(shallow[0] === objects[0]);\n * // => true\n */\nfunction clone(value) {\n  return baseClone(value, CLONE_SYMBOLS_FLAG);\n}\n\nexport default clone;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/node\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\nimport { clone } from 'lodash-es';\n\n// To check if component is loaded more than once.\nimport '@ckeditor/ckeditor5-utils/src/version';\n\n/**\n * Abstract view node class.\n *\n * This is an abstract class. Its constructor should not be used directly.\n * Use the {@link module:engine/view/downcastwriter~DowncastWriter} or {@link module:engine/view/upcastwriter~UpcastWriter}\n * to create new instances of view nodes.\n *\n * @abstract\n */\nexport default class Node {\n\t/**\n\t * Creates a tree view node.\n\t *\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document instance to which this node belongs.\n\t */\n\tconstructor( document ) {\n\t\t/**\n\t\t * The document instance to which this node belongs.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = document;\n\n\t\t/**\n\t\t * Parent element. Null by default. Set by {@link module:engine/view/element~Element#_insertChild}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment|null}\n\t\t */\n\t\tthis.parent = null;\n\t}\n\n\t/**\n\t * Index of the node in the parent element or null if the node has no parent.\n\t *\n\t * Accessing this property throws an error if this node's parent element does not contain it.\n\t * This means that view tree got broken.\n\t *\n\t * @readonly\n\t * @type {Number|null}\n\t */\n\tget index() {\n\t\tlet pos;\n\n\t\tif ( !this.parent ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// No parent or child doesn't exist in parent's children.\n\t\tif ( ( pos = this.parent.getChildIndex( this ) ) == -1 ) {\n\t\t\t/**\n\t\t\t * The node's parent does not contain this node. It means that the document tree is corrupted.\n\t\t\t *\n\t\t\t * @error view-node-not-found-in-parent\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-node-not-found-in-parent', this );\n\t\t}\n\n\t\treturn pos;\n\t}\n\n\t/**\n\t * Node's next sibling, or `null` if it is the last child.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|null}\n\t */\n\tget nextSibling() {\n\t\tconst index = this.index;\n\n\t\treturn ( index !== null && this.parent.getChild( index + 1 ) ) || null;\n\t}\n\n\t/**\n\t * Node's previous sibling, or `null` if it is the first child.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|null}\n\t */\n\tget previousSibling() {\n\t\tconst index = this.index;\n\n\t\treturn ( index !== null && this.parent.getChild( index - 1 ) ) || null;\n\t}\n\n\t/**\n\t * Top-most ancestor of the node. If the node has no parent it is the root itself.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\tlet root = this; // eslint-disable-line consistent-this\n\n\t\twhile ( root.parent ) {\n\t\t\troot = root.parent;\n\t\t}\n\n\t\treturn root;\n\t}\n\n\t/**\n\t * Returns true if the node is in a tree rooted in the document (is a descendant of one of its roots).\n\t *\n\t * @returns {Boolean}\n\t */\n\tisAttached() {\n\t\treturn this.root.is( 'rootElement' );\n\t}\n\n\t/**\n\t * Gets a path to the node. The path is an array containing indices of consecutive ancestors of this node,\n\t * beginning from {@link module:engine/view/node~Node#root root}, down to this node's index.\n\t *\n\t *\t\tconst abc = downcastWriter.createText( 'abc' );\n\t *\t\tconst foo = downcastWriter.createText( 'foo' );\n\t *\t\tconst h1 = downcastWriter.createElement( 'h1', null, downcastWriter.createText( 'header' ) );\n\t *\t\tconst p = downcastWriter.createElement( 'p', null, [ abc, foo ] );\n\t *\t\tconst div = downcastWriter.createElement( 'div', null, [ h1, p ] );\n\t *\t\tfoo.getPath(); // Returns [ 1, 3 ]. `foo` is in `p` which is in `div`. `p` starts at offset 1, while `foo` at 3.\n\t *\t\th1.getPath(); // Returns [ 0 ].\n\t *\t\tdiv.getPath(); // Returns [].\n\t *\n\t * @returns {Array.<Number>} The path.\n\t */\n\tgetPath() {\n\t\tconst path = [];\n\t\tlet node = this; // eslint-disable-line consistent-this\n\n\t\twhile ( node.parent ) {\n\t\t\tpath.unshift( node.index );\n\t\t\tnode = node.parent;\n\t\t}\n\n\t\treturn path;\n\t}\n\n\t/**\n\t * Returns ancestors array of this node.\n\t *\n\t * @param {Object} options Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` this node will be also included in parent's array.\n\t * @param {Boolean} [options.parentFirst=false] When set to `true`, array will be sorted from node's parent to root element,\n\t * otherwise root element will be the first item in the array.\n\t * @returns {Array} Array with ancestors.\n\t */\n\tgetAncestors( options = { includeSelf: false, parentFirst: false } ) {\n\t\tconst ancestors = [];\n\t\tlet parent = options.includeSelf ? this : this.parent;\n\n\t\twhile ( parent ) {\n\t\t\tancestors[ options.parentFirst ? 'push' : 'unshift' ]( parent );\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn ancestors;\n\t}\n\n\t/**\n\t * Returns a {@link module:engine/view/element~Element} or {@link module:engine/view/documentfragment~DocumentFragment}\n\t * which is a common ancestor of both nodes.\n\t *\n\t * @param {module:engine/view/node~Node} node The second node.\n\t * @param {Object} options Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` both nodes will be considered \"ancestors\" too.\n\t * Which means that if e.g. node A is inside B, then their common ancestor will be B.\n\t * @returns {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor( node, options = {} ) {\n\t\tconst ancestorsA = this.getAncestors( options );\n\t\tconst ancestorsB = node.getAncestors( options );\n\n\t\tlet i = 0;\n\n\t\twhile ( ancestorsA[ i ] == ancestorsB[ i ] && ancestorsA[ i ] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i === 0 ? null : ancestorsA[ i - 1 ];\n\t}\n\n\t/**\n\t * Returns whether this node is before given node. `false` is returned if nodes are in different trees (for example,\n\t * in different {@link module:engine/view/documentfragment~DocumentFragment}s).\n\t *\n\t * @param {module:engine/view/node~Node} node Node to compare with.\n\t * @returns {Boolean}\n\t */\n\tisBefore( node ) {\n\t\t// Given node is not before this node if they are same.\n\t\tif ( this == node ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Return `false` if it is impossible to compare nodes.\n\t\tif ( this.root !== node.root ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst thisPath = this.getPath();\n\t\tconst nodePath = node.getPath();\n\n\t\tconst result = compareArrays( thisPath, nodePath );\n\n\t\tswitch ( result ) {\n\t\t\tcase 'prefix':\n\t\t\t\treturn true;\n\n\t\t\tcase 'extension':\n\t\t\t\treturn false;\n\n\t\t\tdefault:\n\t\t\t\treturn thisPath[ result ] < nodePath[ result ];\n\t\t}\n\t}\n\n\t/**\n\t * Returns whether this node is after given node. `false` is returned if nodes are in different trees (for example,\n\t * in different {@link module:engine/view/documentfragment~DocumentFragment}s).\n\t *\n\t * @param {module:engine/view/node~Node} node Node to compare with.\n\t * @returns {Boolean}\n\t */\n\tisAfter( node ) {\n\t\t// Given node is not before this node if they are same.\n\t\tif ( this == node ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Return `false` if it is impossible to compare nodes.\n\t\tif ( this.root !== node.root ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// In other cases, just check if the `node` is before, and return the opposite.\n\t\treturn !this.isBefore( node );\n\t}\n\n\t/**\n\t * Removes node from parent.\n\t *\n\t * @protected\n\t */\n\t_remove() {\n\t\tthis.parent._removeChildren( this.index );\n\t}\n\n\t/**\n\t * @protected\n\t * @param {module:engine/view/document~ChangeType} type Type of the change.\n\t * @param {module:engine/view/node~Node} node Changed node.\n\t * @fires change\n\t */\n\t_fireChange( type, node ) {\n\t\tthis.fire( 'change:' + type, node );\n\n\t\tif ( this.parent ) {\n\t\t\tthis.parent._fireChange( type, node );\n\t\t}\n\t}\n\n\t/**\n\t * Custom toJSON method to solve child-parent circular dependencies.\n\t *\n\t * @returns {Object} Clone of this object with the parent property removed.\n\t */\n\ttoJSON() {\n\t\tconst json = clone( this );\n\n\t\t// Due to circular references we need to remove parent reference.\n\t\tdelete json.parent;\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t * This method is useful when processing view objects that are of unknown type. For example, a function\n\t * may return a {@link module:engine/view/documentfragment~DocumentFragment} or a {@link module:engine/view/node~Node}\n\t * that can be either a text node or an element. This method can be used to check what kind of object is returned.\n\t *\n\t *\t\tsomeObject.is( 'element' ); // -> true if this is an element\n\t *\t\tsomeObject.is( 'node' ); // -> true if this is a node (a text node or an element)\n\t *\t\tsomeObject.is( 'documentFragment' ); // -> true if this is a document fragment\n\t *\n\t * Since this method is also available on a range of model objects, you can prefix the type of the object with\n\t * `model:` or `view:` to check, for example, if this is the model's or view's element:\n\t *\n\t *\t\tviewElement.is( 'view:element' ); // -> true\n\t *\t\tviewElement.is( 'model:element' ); // -> false\n\t *\n\t * By using this method it is also possible to check a name of an element:\n\t *\n\t *\t\timgElement.is( 'element', 'img' ); // -> true\n\t *\t\timgElement.is( 'view:element', 'img' ); // -> same as above, but more precise\n\t *\n\t * The list of view objects which implement the `is()` method:\n\t *\n\t * * {@link module:engine/view/attributeelement~AttributeElement#is `AttributeElement#is()`}\n\t * * {@link module:engine/view/containerelement~ContainerElement#is `ContainerElement#is()`}\n\t * * {@link module:engine/view/documentfragment~DocumentFragment#is `DocumentFragment#is()`}\n\t * * {@link module:engine/view/documentselection~DocumentSelection#is `DocumentSelection#is()`}\n\t * * {@link module:engine/view/editableelement~EditableElement#is `EditableElement#is()`}\n\t * * {@link module:engine/view/element~Element#is `Element#is()`}\n\t * * {@link module:engine/view/emptyelement~EmptyElement#is `EmptyElement#is()`}\n\t * * {@link module:engine/view/node~Node#is `Node#is()`}\n\t * * {@link module:engine/view/position~Position#is `Position#is()`}\n\t * * {@link module:engine/view/range~Range#is `Range#is()`}\n\t * * {@link module:engine/view/rooteditableelement~RootEditableElement#is `RootEditableElement#is()`}\n\t * * {@link module:engine/view/selection~Selection#is `Selection#is()`}\n\t * * {@link module:engine/view/text~Text#is `Text#is()`}\n\t * * {@link module:engine/view/textproxy~TextProxy#is `TextProxy#is()`}\n\t * * {@link module:engine/view/uielement~UIElement#is `UIElement#is()`}\n\t *\n\t * @method #is\n\t * @param {String} type Type to check.\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'node' || type === 'view:node';\n\t}\n\n\t/**\n\t * Clones this node.\n\t *\n\t * @protected\n\t * @method #_clone\n\t * @returns {module:engine/view/node~Node} Clone of this node.\n\t */\n\n\t/**\n\t * Checks if provided node is similar to this node.\n\t *\n\t * @method #isSimilar\n\t * @returns {Boolean} True if nodes are similar.\n\t */\n}\n\n/**\n * Fired when list of {@link module:engine/view/element~Element elements} children changes.\n *\n * Change event is bubbled – it is fired on all ancestors.\n *\n * @event change:children\n * @param {module:engine/view/node~Node} changedNode\n */\n\n/**\n * Fired when list of {@link module:engine/view/element~Element elements} attributes changes.\n *\n * Change event is bubbled – it is fired on all ancestors.\n *\n * @event change:attributes\n * @param {module:engine/view/node~Node} changedNode\n */\n\n/**\n * Fired when {@link module:engine/view/text~Text text nodes} data changes.\n *\n * Change event is bubbled – it is fired on all ancestors.\n *\n * @event change:text\n * @param {module:engine/view/node~Node} changedNode\n */\n\n/**\n * @event change\n */\n\nmix( Node, EmitterMixin );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/text\n */\n\nimport Node from './node';\n\n/**\n * Tree view text node.\n *\n * The constructor of this class should not be used directly. To create a new text node instance\n * use the {@link module:engine/view/downcastwriter~DowncastWriter#createText `DowncastWriter#createText()`}\n * method when working on data downcasted from the model or the\n * {@link module:engine/view/upcastwriter~UpcastWriter#createText `UpcastWriter#createText()`}\n * method when working on non-semantic views.\n *\n * @extends module:engine/view/node~Node\n */\nexport default class Text extends Node {\n\t/**\n\t * Creates a tree view text node.\n\t *\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document instance to which this text node belongs.\n\t * @param {String} data The text's data.\n\t */\n\tconstructor( document, data ) {\n\t\tsuper( document );\n\n\t\t/**\n\t\t * The text content.\n\t\t *\n\t\t * Setting the data fires the {@link module:engine/view/node~Node#event:change:text change event}.\n\t\t *\n\t\t * @protected\n\t\t * @member {String} module:engine/view/text~Text#_textData\n\t\t */\n\t\tthis._textData = data;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\ttext.is( '$text' ); // -> true\n\t *\t\ttext.is( 'node' ); // -> true\n\t *\t\ttext.is( 'view:$text' ); // -> true\n\t *\t\ttext.is( 'view:node' ); // -> true\n\t *\n\t *\t\ttext.is( 'model:$text' ); // -> false\n\t *\t\ttext.is( 'element' ); // -> false\n\t *\t\ttext.is( 'range' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * **Note:** Until version 20.0.0 this method wasn't accepting `'$text'` type. The legacy `'text'` type is still\n\t * accepted for backward compatibility.\n\t *\n\t * @param {String} type Type to check.\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === '$text' || type === 'view:$text' ||\n\t\t\t// This are legacy values kept for backward compatibility.\n\t\t\ttype === 'text' || type === 'view:text' ||\n\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\ttype === 'node' || type === 'view:node';\n\t}\n\n\t/**\n\t * The text content.\n\t *\n\t * @readonly\n\t * @type {String}\n\t */\n\tget data() {\n\t\treturn this._textData;\n\t}\n\n\t/**\n\t * The `_data` property is controlled by a getter and a setter.\n\t *\n\t * The getter is required when using the addition assignment operator on protected property:\n\t *\n\t *\t\tconst foo = downcastWriter.createText( 'foo' );\n\t *\t\tconst bar = downcastWriter.createText( 'bar' );\n\t *\n\t *\t\tfoo._data += bar.data;   // executes: `foo._data = foo._data + bar.data`\n\t *\t\tconsole.log( foo.data ); // prints: 'foobar'\n\t *\n\t * If the protected getter didn't exist, `foo._data` will return `undefined` and result of the merge will be invalid.\n\t *\n\t * The setter sets data and fires the {@link module:engine/view/node~Node#event:change:text change event}.\n\t *\n\t * @protected\n\t * @type {String}\n\t */\n\tget _data() {\n\t\treturn this.data;\n\t}\n\n\tset _data( data ) {\n\t\tthis._fireChange( 'text', this );\n\n\t\tthis._textData = data;\n\t}\n\n\t/**\n\t * Checks if this text node is similar to other text node.\n\t * Both nodes should have the same data to be considered as similar.\n\t *\n\t * @param {module:engine/view/text~Text} otherNode Node to check if it is same as this node.\n\t * @returns {Boolean}\n\t */\n\tisSimilar( otherNode ) {\n\t\tif ( !( otherNode instanceof Text ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this === otherNode || this.data === otherNode.data;\n\t}\n\n\t/**\n\t * Clones this node.\n\t *\n\t * @protected\n\t * @returns {module:engine/view/text~Text} Text node that is a clone of this node.\n\t */\n\t_clone() {\n\t\treturn new Text( this.document, this.data );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `#${ this.data }`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ViewText: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logExtended() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ViewText: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/textproxy\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * TextProxy is a wrapper for substring of {@link module:engine/view/text~Text}. Instance of this class is created by\n * {@link module:engine/view/treewalker~TreeWalker} when only a part of {@link module:engine/view/text~Text} needs to be returned.\n *\n * `TextProxy` has an API similar to {@link module:engine/view/text~Text Text} and allows to do most of the common tasks performed\n * on view nodes.\n *\n * **Note:** Some `TextProxy` instances may represent whole text node, not just a part of it.\n * See {@link module:engine/view/textproxy~TextProxy#isPartial}.\n *\n * **Note:** `TextProxy` is a readonly interface.\n *\n * **Note:** `TextProxy` instances are created on the fly basing on the current state of parent {@link module:engine/view/text~Text}.\n * Because of this it is highly unrecommended to store references to `TextProxy instances because they might get\n * invalidated due to operations on Document. Also TextProxy is not a {@link module:engine/view/node~Node} so it can not be\n * inserted as a child of {@link module:engine/view/element~Element}.\n *\n * `TextProxy` instances are created by {@link module:engine/view/treewalker~TreeWalker view tree walker}. You should not need to create\n * an instance of this class by your own.\n */\nexport default class TextProxy {\n\t/**\n\t * Creates a text proxy.\n\t *\n\t * @protected\n\t * @param {module:engine/view/text~Text} textNode Text node which part is represented by this text proxy.\n\t * @param {Number} offsetInText Offset in {@link module:engine/view/textproxy~TextProxy#textNode text node}\n\t * from which the text proxy starts.\n\t * @param {Number} length Text proxy length, that is how many text node's characters, starting from `offsetInText` it represents.\n\t * @constructor\n\t */\n\tconstructor( textNode, offsetInText, length ) {\n\t\t/**\n\t\t * Reference to the {@link module:engine/view/text~Text} element which TextProxy is a substring.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/text~Text} module:engine/view/textproxy~TextProxy#textNode\n\t\t */\n\t\tthis.textNode = textNode;\n\n\t\tif ( offsetInText < 0 || offsetInText > textNode.data.length ) {\n\t\t\t/**\n\t\t\t * Given offsetInText value is incorrect.\n\t\t\t *\n\t\t\t * @error view-textproxy-wrong-offsetintext\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-textproxy-wrong-offsetintext', this );\n\t\t}\n\n\t\tif ( length < 0 || offsetInText + length > textNode.data.length ) {\n\t\t\t/**\n\t\t\t * Given length value is incorrect.\n\t\t\t *\n\t\t\t * @error view-textproxy-wrong-length\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-textproxy-wrong-length', this );\n\t\t}\n\n\t\t/**\n\t\t * Text data represented by this text proxy.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} module:engine/view/textproxy~TextProxy#data\n\t\t */\n\t\tthis.data = textNode.data.substring( offsetInText, offsetInText + length );\n\n\t\t/**\n\t\t * Offset in the `textNode` where this `TextProxy` instance starts.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} module:engine/view/textproxy~TextProxy#offsetInText\n\t\t */\n\t\tthis.offsetInText = offsetInText;\n\t}\n\n\t/**\n\t * Offset size of this node.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget offsetSize() {\n\t\treturn this.data.length;\n\t}\n\n\t/**\n\t * Flag indicating whether `TextProxy` instance covers only part of the original {@link module:engine/view/text~Text text node}\n\t * (`true`) or the whole text node (`false`).\n\t *\n\t * This is `false` when text proxy starts at the very beginning of {@link module:engine/view/textproxy~TextProxy#textNode textNode}\n\t * ({@link module:engine/view/textproxy~TextProxy#offsetInText offsetInText} equals `0`) and text proxy sizes is equal to\n\t * text node size.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isPartial() {\n\t\treturn this.data.length !== this.textNode.data.length;\n\t}\n\n\t/**\n\t * Parent of this text proxy, which is same as parent of text node represented by this text proxy.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment|null}\n\t */\n\tget parent() {\n\t\treturn this.textNode.parent;\n\t}\n\n\t/**\n\t * Root of this text proxy, which is same as root of text node represented by this text proxy.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this.textNode.root;\n\t}\n\n\t/**\n\t * {@link module:engine/view/document~Document View document} that owns this text proxy, or `null` if the text proxy is inside\n\t * {@link module:engine/view/documentfragment~DocumentFragment document fragment}.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/document~Document|null}\n\t */\n\tget document() {\n\t\treturn this.textNode.document;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\ttextProxy.is( '$textProxy' ); // -> true\n\t *\t\ttextProxy.is( 'view:$textProxy' ); // -> true\n\t *\n\t *\t\ttextProxy.is( 'model:$textProxy' ); // -> false\n\t *\t\ttextProxy.is( 'element' ); // -> false\n\t *\t\ttextProxy.is( 'range' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * **Note:** Until version 20.0.0 this method wasn't accepting `'$textProxy'` type. The legacy `'textProxy'` type is still\n\t * accepted for backward compatibility.\n\t *\n\t * @param {String} type Type to check.\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === '$textProxy' || type === 'view:$textProxy' ||\n\t\t\t// This are legacy values kept for backward compatibility.\n\t\t\ttype === 'textProxy' || type === 'view:textProxy';\n\t}\n\n\t/**\n\t * Returns ancestors array of this text proxy.\n\t *\n\t * @param {Object} options Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` {#textNode} will be also included in parent's array.\n\t * @param {Boolean} [options.parentFirst=false] When set to `true`, array will be sorted from text proxy parent to\n\t * root element, otherwise root element will be the first item in the array.\n\t * @returns {Array} Array with ancestors.\n\t */\n\tgetAncestors( options = { includeSelf: false, parentFirst: false } ) {\n\t\tconst ancestors = [];\n\t\tlet parent = options.includeSelf ? this.textNode : this.parent;\n\n\t\twhile ( parent !== null ) {\n\t\t\tancestors[ options.parentFirst ? 'push' : 'unshift' ]( parent );\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn ancestors;\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `#${ this.data }`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ViewTextProxy: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logExtended() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ViewTextProxy: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/tomap\n */\n\nimport objectToMap from './objecttomap';\nimport isIterable from './isiterable';\n\n/**\n * Transforms object or iterable to map. Iterable needs to be in the format acceptable by the `Map` constructor.\n *\n *\t\tmap = toMap( { 'foo': 1, 'bar': 2 } );\n *\t\tmap = toMap( [ [ 'foo', 1 ], [ 'bar', 2 ] ] );\n *\t\tmap = toMap( anotherMap );\n *\n * @param {Object|Iterable} data Object or iterable to transform.\n * @returns {Map} Map created from data.\n */\nexport default function toMap( data ) {\n\tif ( isIterable( data ) ) {\n\t\treturn new Map( data );\n\t} else {\n\t\treturn objectToMap( data );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/objecttomap\n */\n\n/**\n * Transforms object to map.\n *\n *\t\tconst map = objectToMap( { 'foo': 1, 'bar': 2 } );\n *\t\tmap.get( 'foo' ); // 1\n *\n * **Note**: For mixed data (`Object` or `Iterable`) there's a dedicated {@link module:utils/tomap~toMap} function.\n *\n * @param {Object} obj Object to transform.\n * @returns {Map} Map created from object.\n */\nexport default function objectToMap( obj ) {\n\tconst map = new Map();\n\n\tfor ( const key in obj ) {\n\t\tmap.set( key, obj[ key ] );\n\t}\n\n\treturn map;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/matcher\n */\n\n/**\n * View matcher class.\n * Instance of this class can be used to find {@link module:engine/view/element~Element elements} that match given pattern.\n */\nexport default class Matcher {\n\t/**\n\t * Creates new instance of Matcher.\n\t *\n\t * @param {String|RegExp|Object} [pattern] Match patterns. See {@link module:engine/view/matcher~Matcher#add add method} for\n\t * more information.\n\t */\n\tconstructor( ...pattern ) {\n\t\t/**\n\t\t * @private\n\t\t * @type {Array<String|RegExp|Object>}\n\t\t */\n\t\tthis._patterns = [];\n\n\t\tthis.add( ...pattern );\n\t}\n\n\t/**\n\t * Adds pattern or patterns to matcher instance.\n\t *\n\t *\t\t// String.\n\t *\t\tmatcher.add( 'div' );\n\t *\n\t *\t\t// Regular expression.\n\t *\t\tmatcher.add( /^\\w/ );\n\t *\n\t *\t\t// Single class.\n\t *\t\tmatcher.add( {\n\t *\t\t\tclasses: 'foobar'\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/view/matcher~MatcherPattern} for more examples.\n\t *\n\t * Multiple patterns can be added in one call:\n\t *\n\t * \t\tmatcher.add( 'div', { classes: 'foobar' } );\n\t *\n\t * @param {Object|String|RegExp|Function} pattern Object describing pattern details. If string or regular expression\n\t * is provided it will be used to match element's name. Pattern can be also provided in a form\n\t * of a function - then this function will be called with each {@link module:engine/view/element~Element element} as a parameter.\n\t * Function's return value will be stored under `match` key of the object returned from\n\t * {@link module:engine/view/matcher~Matcher#match match} or {@link module:engine/view/matcher~Matcher#matchAll matchAll} methods.\n\t * @param {String|RegExp} [pattern.name] Name or regular expression to match element's name.\n\t * @param {Object} [pattern.attributes] Object with key-value pairs representing attributes to match. Each object key\n\t * represents attribute name. Value under that key can be either:\n\t * * `true` - then attribute is just required (can be empty),\n\t * * a string - then attribute has to be equal, or\n\t * * a regular expression - then attribute has to match the expression.\n\t * @param {String|RegExp|Array} [pattern.classes] Class name or array of class names to match. Each name can be\n\t * provided in a form of string or regular expression.\n\t * @param {Object} [pattern.styles] Object with key-value pairs representing styles to match. Each object key\n\t * represents style name. Value under that key can be either a string or a regular expression and it will be used\n\t * to match style value.\n\t */\n\tadd( ...pattern ) {\n\t\tfor ( let item of pattern ) {\n\t\t\t// String or RegExp pattern is used as element's name.\n\t\t\tif ( typeof item == 'string' || item instanceof RegExp ) {\n\t\t\t\titem = { name: item };\n\t\t\t}\n\n\t\t\t// Single class name/RegExp can be provided.\n\t\t\tif ( item.classes && ( typeof item.classes == 'string' || item.classes instanceof RegExp ) ) {\n\t\t\t\titem.classes = [ item.classes ];\n\t\t\t}\n\n\t\t\tthis._patterns.push( item );\n\t\t}\n\t}\n\n\t/**\n\t * Matches elements for currently stored patterns. Returns match information about first found\n\t * {@link module:engine/view/element~Element element}, otherwise returns `null`.\n\t *\n\t * Example of returned object:\n\t *\n\t *\t\t{\n\t *\t\t\telement: <instance of found element>,\n\t *\t\t\tpattern: <pattern used to match found element>,\n\t *\t\t\tmatch: {\n\t *\t\t\t\tname: true,\n\t *\t\t\t\tattributes: [ 'title', 'href' ],\n\t *\t\t\t\tclasses: [ 'foo' ],\n\t *\t\t\t\tstyles: [ 'color', 'position' ]\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t * @see module:engine/view/matcher~Matcher#add\n\t * @see module:engine/view/matcher~Matcher#matchAll\n\t * @param {...module:engine/view/element~Element} element View element to match against stored patterns.\n\t * @returns {Object|null} result\n\t * @returns {module:engine/view/element~Element} result.element Matched view element.\n\t * @returns {Object|String|RegExp|Function} result.pattern Pattern that was used to find matched element.\n\t * @returns {Object} result.match Object representing matched element parts.\n\t * @returns {Boolean} [result.match.name] True if name of the element was matched.\n\t * @returns {Array} [result.match.attributes] Array with matched attribute names.\n\t * @returns {Array} [result.match.classes] Array with matched class names.\n\t * @returns {Array} [result.match.styles] Array with matched style names.\n\t */\n\tmatch( ...element ) {\n\t\tfor ( const singleElement of element ) {\n\t\t\tfor ( const pattern of this._patterns ) {\n\t\t\t\tconst match = isElementMatching( singleElement, pattern );\n\n\t\t\t\tif ( match ) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\telement: singleElement,\n\t\t\t\t\t\tpattern,\n\t\t\t\t\t\tmatch\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Matches elements for currently stored patterns. Returns array of match information with all found\n\t * {@link module:engine/view/element~Element elements}. If no element is found - returns `null`.\n\t *\n\t * @see module:engine/view/matcher~Matcher#add\n\t * @see module:engine/view/matcher~Matcher#match\n\t * @param {...module:engine/view/element~Element} element View element to match against stored patterns.\n\t * @returns {Array.<Object>|null} Array with match information about found elements or `null`. For more information\n\t * see {@link module:engine/view/matcher~Matcher#match match method} description.\n\t */\n\tmatchAll( ...element ) {\n\t\tconst results = [];\n\n\t\tfor ( const singleElement of element ) {\n\t\t\tfor ( const pattern of this._patterns ) {\n\t\t\t\tconst match = isElementMatching( singleElement, pattern );\n\n\t\t\t\tif ( match ) {\n\t\t\t\t\tresults.push( {\n\t\t\t\t\t\telement: singleElement,\n\t\t\t\t\t\tpattern,\n\t\t\t\t\t\tmatch\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn results.length > 0 ? results : null;\n\t}\n\n\t/**\n\t * Returns the name of the element to match if there is exactly one pattern added to the matcher instance\n\t * and it matches element name defined by `string` (not `RegExp`). Otherwise, returns `null`.\n\t *\n\t * @returns {String|null} Element name trying to match.\n\t */\n\tgetElementName() {\n\t\tif ( this._patterns.length !== 1 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst pattern = this._patterns[ 0 ];\n\t\tconst name = pattern.name;\n\n\t\treturn ( typeof pattern != 'function' && name && !( name instanceof RegExp ) ) ? name : null;\n\t}\n}\n\n// Returns match information if {@link module:engine/view/element~Element element} is matching provided pattern.\n// If element cannot be matched to provided pattern - returns `null`.\n//\n// @param {module:engine/view/element~Element} element\n// @param {Object|String|RegExp|Function} pattern\n// @returns {Object|null} Returns object with match information or null if element is not matching.\nfunction isElementMatching( element, pattern ) {\n\t// If pattern is provided as function - return result of that function;\n\tif ( typeof pattern == 'function' ) {\n\t\treturn pattern( element );\n\t}\n\n\tconst match = {};\n\t// Check element's name.\n\tif ( pattern.name ) {\n\t\tmatch.name = matchName( pattern.name, element.name );\n\n\t\tif ( !match.name ) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t// Check element's attributes.\n\tif ( pattern.attributes ) {\n\t\tmatch.attributes = matchAttributes( pattern.attributes, element );\n\n\t\tif ( !match.attributes ) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t// Check element's classes.\n\tif ( pattern.classes ) {\n\t\tmatch.classes = matchClasses( pattern.classes, element );\n\n\t\tif ( !match.classes ) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t// Check element's styles.\n\tif ( pattern.styles ) {\n\t\tmatch.styles = matchStyles( pattern.styles, element );\n\n\t\tif ( !match.styles ) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn match;\n}\n\n// Checks if name can be matched by provided pattern.\n//\n// @param {String|RegExp} pattern\n// @param {String} name\n// @returns {Boolean} Returns `true` if name can be matched, `false` otherwise.\nfunction matchName( pattern, name ) {\n\t// If pattern is provided as RegExp - test against this regexp.\n\tif ( pattern instanceof RegExp ) {\n\t\treturn pattern.test( name );\n\t}\n\n\treturn pattern === name;\n}\n\n// Checks if attributes of provided element can be matched against provided patterns.\n//\n// @param {Object} patterns Object with information about attributes to match. Each key of the object will be\n// used as attribute name. Value of each key can be a string or regular expression to match against attribute value.\n// @param {module:engine/view/element~Element} element Element which attributes will be tested.\n// @returns {Array|null} Returns array with matched attribute names or `null` if no attributes were matched.\nfunction matchAttributes( patterns, element ) {\n\tconst match = [];\n\n\tfor ( const name in patterns ) {\n\t\tconst pattern = patterns[ name ];\n\n\t\tif ( element.hasAttribute( name ) ) {\n\t\t\tconst attribute = element.getAttribute( name );\n\n\t\t\tif ( pattern === true ) {\n\t\t\t\tmatch.push( name );\n\t\t\t} else if ( pattern instanceof RegExp ) {\n\t\t\t\tif ( pattern.test( attribute ) ) {\n\t\t\t\t\tmatch.push( name );\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t} else if ( attribute === pattern ) {\n\t\t\t\tmatch.push( name );\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\treturn match;\n}\n\n// Checks if classes of provided element can be matched against provided patterns.\n//\n// @param {Array.<String|RegExp>} patterns Array of strings or regular expressions to match against element's classes.\n// @param {module:engine/view/element~Element} element Element which classes will be tested.\n// @returns {Array|null} Returns array with matched class names or `null` if no classes were matched.\nfunction matchClasses( patterns, element ) {\n\tconst match = [];\n\n\tfor ( const pattern of patterns ) {\n\t\tif ( pattern instanceof RegExp ) {\n\t\t\tconst classes = element.getClassNames();\n\n\t\t\tfor ( const name of classes ) {\n\t\t\t\tif ( pattern.test( name ) ) {\n\t\t\t\t\tmatch.push( name );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( match.length === 0 ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t} else if ( element.hasClass( pattern ) ) {\n\t\t\tmatch.push( pattern );\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\treturn match;\n}\n\n// Checks if styles of provided element can be matched against provided patterns.\n//\n// @param {Object} patterns Object with information about styles to match. Each key of the object will be\n// used as style name. Value of each key can be a string or regular expression to match against style value.\n// @param {module:engine/view/element~Element} element Element which styles will be tested.\n// @returns {Array|null} Returns array with matched style names or `null` if no styles were matched.\nfunction matchStyles( patterns, element ) {\n\tconst match = [];\n\n\tfor ( const name in patterns ) {\n\t\tconst pattern = patterns[ name ];\n\n\t\tif ( element.hasStyle( name ) ) {\n\t\t\tconst style = element.getStyle( name );\n\n\t\t\tif ( pattern instanceof RegExp ) {\n\t\t\t\tif ( pattern.test( style ) ) {\n\t\t\t\t\tmatch.push( name );\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t} else if ( style === pattern ) {\n\t\t\t\tmatch.push( name );\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\treturn match;\n}\n\n/**\n * An entity that is a valid pattern recognized by a matcher. `MatcherPattern` is used by {@link ~Matcher} to recognize\n * if a view element fits in a group of view elements described by the pattern.\n *\n * `MatcherPattern` can be given as a `String`, a `RegExp`, an `Object` or a `Function`.\n *\n * If `MatcherPattern` is given as a `String` or `RegExp`, it will match any view element that has a matching name:\n *\n *\t\t// Match any element with name equal to 'div'.\n *\t\tconst pattern = 'div';\n *\n *\t\t// Match any element which name starts on 'p'.\n *\t\tconst pattern = /^p/;\n *\n * If `MatcherPattern` is given as an `Object`, all the object's properties will be matched with view element properties.\n *\n *\t\t// Match view element's name.\n *\t\tconst pattern = { name: /^p/ };\n *\n *\t\t// Match view element which has matching attributes.\n *\t\tconst pattern = {\n *\t\t\tattributes: {\n *\t\t\t\ttitle: 'foobar',\t// Attribute title should equal 'foobar'.\n *\t\t\t\tfoo: /^\\w+/,\t\t// Attribute foo should match /^\\w+/ regexp.\n *\t\t\t\tbar: true\t\t\t// Attribute bar should be set (can be empty).\n *\t\t\t}\n *\t\t};\n *\n *\t\t// Match view element which has given class.\n *\t\tconst pattern = {\n *\t\t\tclasses: 'foobar'\n *\t\t};\n *\n *\t\t// Match view element class using regular expression.\n *\t\tconst pattern = {\n *\t\t\tclasses: /foo.../\n *\t\t};\n *\n *\t\t// Multiple classes to match.\n *\t\tconst pattern = {\n *\t\t\tclasses: [ 'baz', 'bar', /foo.../ ]\n *\t\t};\n *\n *\t\t// Match view element which has given styles.\n *\t\tconst pattern = {\n *\t\t\tstyles: {\n *\t\t\t\tposition: 'absolute',\n *\t\t\t\tcolor: /^\\w*blue$/\n *\t\t\t}\n *\t\t};\n *\n *\t\t// Pattern with multiple properties.\n *\t\tconst pattern = {\n *\t\t\tname: 'span',\n *\t\t\tstyles: {\n *\t\t\t\t'font-weight': 'bold'\n *\t\t\t},\n *\t\t\tclasses: 'highlighted'\n *\t\t};\n *\n * If `MatcherPattern` is given as a `Function`, the function takes a view element as a first and only parameter and\n * the function should decide whether that element matches. If so, it should return what part of the view element has been matched.\n * Otherwise, the function should return `null`. The returned result will be included in `match` property of the object\n * returned by {@link ~Matcher#match} call.\n *\n *\t\t// Match an empty <div> element.\n *\t\tconst pattern = element => {\n *\t\t\tif ( element.name == 'div' && element.childCount > 0 ) {\n *\t\t\t\t// Return which part of the element was matched.\n *\t\t\t\treturn { name: true };\n *\t\t\t}\n *\n *\t\t\treturn null;\n *\t\t};\n *\n *\t\t// Match a <p> element with big font (\"heading-like\" element).\n *\t\tconst pattern = element => {\n *\t\t\tif ( element.name == 'p' ) {\n *\t\t\t\tconst fontSize = element.getStyle( 'font-size' );\n *\t\t\t\tconst size = fontSize.match( /(\\d+)/px );\n *\n *\t\t\t\tif ( size && Number( size[ 1 ] ) > 26 ) {\n *\t\t\t\t\treturn { name: true, attribute: [ 'font-size' ] };\n *\t\t\t\t}\n *\t\t\t}\n *\n *\t\t\treturn null;\n *\t\t};\n *\n * `MatcherPattern` is defined in a way that it is a superset of {@link module:engine/view/elementdefinition~ElementDefinition},\n * that is, every `ElementDefinition` also can be used as a `MatcherPattern`.\n *\n * @typedef {String|RegExp|Object|Function} module:engine/view/matcher~MatcherPattern\n *\n * @property {String|RegExp} [name] View element name to match.\n * @property {String|RegExp|Array.<String|RegExp>} [classes] View element's class name(s) to match.\n * @property {Object} [styles] Object with key-value pairs representing styles to match.\n * Each object key represents style name. Value can be given as `String` or `RegExp`.\n * @property {Object} [attributes] Object with key-value pairs representing attributes to match.\n * Each object key represents attribute name. Value can be given as `String` or `RegExp`.\n */\n","import baseGetTag from './_baseGetTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar 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 */\nfunction isSymbol(value) {\n  return typeof value == 'symbol' ||\n    (isObjectLike(value) && baseGetTag(value) == symbolTag);\n}\n\nexport default isSymbol;\n","import isArray from './isArray.js';\nimport isSymbol from './isSymbol.js';\n\n/** Used to match property names within property paths. */\nvar 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 */\nfunction isKey(value, object) {\n  if (isArray(value)) {\n    return false;\n  }\n  var type = typeof value;\n  if (type == 'number' || type == 'symbol' || type == 'boolean' ||\n      value == null || isSymbol(value)) {\n    return true;\n  }\n  return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||\n    (object != null && value in Object(object));\n}\n\nexport default isKey;\n","import MapCache from './_MapCache.js';\n\n/** Error message constants. */\nvar 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 */\nfunction 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`.\nmemoize.Cache = MapCache;\n\nexport default memoize;\n","import memoize from './memoize.js';\n\n/** Used as the maximum memoize cache size. */\nvar 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 */\nfunction memoizeCapped(func) {\n  var result = memoize(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\nexport default memoizeCapped;\n","import memoizeCapped from './_memoizeCapped.js';\n\n/** Used to match property names within property paths. */\nvar rePropName = /[^.[\\]]+|\\[(?:(-?\\d+(?:\\.\\d+)?)|([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2)\\]|(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))/g;\n\n/** Used to match backslashes in property paths. */\nvar 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 */\nvar 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\nexport default stringToPath;\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 */\nfunction 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\nexport default arrayMap;\n","import Symbol from './_Symbol.js';\nimport arrayMap from './_arrayMap.js';\nimport isArray from './isArray.js';\nimport isSymbol from './isSymbol.js';\n\n/** Used as references for various `Number` constants. */\nvar INFINITY = 1 / 0;\n\n/** Used to convert symbols to primitives and strings. */\nvar 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 */\nfunction 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(value)) {\n    // Recursively convert values (susceptible to call stack limits).\n    return arrayMap(value, baseToString) + '';\n  }\n  if (isSymbol(value)) {\n    return symbolToString ? symbolToString.call(value) : '';\n  }\n  var result = (value + '');\n  return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;\n}\n\nexport default baseToString;\n","import baseToString from './_baseToString.js';\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 */\nfunction toString(value) {\n  return value == null ? '' : baseToString(value);\n}\n\nexport default toString;\n","import isArray from './isArray.js';\nimport isKey from './_isKey.js';\nimport stringToPath from './_stringToPath.js';\nimport toString from './toString.js';\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 */\nfunction castPath(value, object) {\n  if (isArray(value)) {\n    return value;\n  }\n  return isKey(value, object) ? [value] : stringToPath(toString(value));\n}\n\nexport default castPath;\n","/**\n * Gets the last element of `array`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Array\n * @param {Array} array The array to query.\n * @returns {*} Returns the last element of `array`.\n * @example\n *\n * _.last([1, 2, 3]);\n * // => 3\n */\nfunction last(array) {\n  var length = array == null ? 0 : array.length;\n  return length ? array[length - 1] : undefined;\n}\n\nexport default last;\n","import isSymbol from './isSymbol.js';\n\n/** Used as references for various `Number` constants. */\nvar 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 */\nfunction toKey(value) {\n  if (typeof value == 'string' || isSymbol(value)) {\n    return value;\n  }\n  var result = (value + '');\n  return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;\n}\n\nexport default toKey;\n","import castPath from './_castPath.js';\nimport toKey from './_toKey.js';\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 */\nfunction 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\nexport default baseGet;\n","/**\n * The base implementation of `_.slice` without an iteratee call guard.\n *\n * @private\n * @param {Array} array The array to slice.\n * @param {number} [start=0] The start position.\n * @param {number} [end=array.length] The end position.\n * @returns {Array} Returns the slice of `array`.\n */\nfunction baseSlice(array, start, end) {\n  var index = -1,\n      length = array.length;\n\n  if (start < 0) {\n    start = -start > length ? 0 : (length + start);\n  }\n  end = end > length ? length : end;\n  if (end < 0) {\n    end += length;\n  }\n  length = start > end ? 0 : ((end - start) >>> 0);\n  start >>>= 0;\n\n  var result = Array(length);\n  while (++index < length) {\n    result[index] = array[index + start];\n  }\n  return result;\n}\n\nexport default baseSlice;\n","import baseGet from './_baseGet.js';\nimport baseSlice from './_baseSlice.js';\n\n/**\n * Gets the parent value at `path` of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Array} path The path to get the parent value of.\n * @returns {*} Returns the parent value.\n */\nfunction parent(object, path) {\n  return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1));\n}\n\nexport default parent;\n","import castPath from './_castPath.js';\nimport last from './last.js';\nimport parent from './_parent.js';\nimport toKey from './_toKey.js';\n\n/**\n * The base implementation of `_.unset`.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {Array|string} path The property path to unset.\n * @returns {boolean} Returns `true` if the property is deleted, else `false`.\n */\nfunction baseUnset(object, path) {\n  path = castPath(path, object);\n  object = parent(object, path);\n  return object == null || delete object[toKey(last(path))];\n}\n\nexport default baseUnset;\n","import baseUnset from './_baseUnset.js';\n\n/**\n * Removes the property at `path` of `object`.\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Object\n * @param {Object} object The object to modify.\n * @param {Array|string} path The path of the property to unset.\n * @returns {boolean} Returns `true` if the property is deleted, else `false`.\n * @example\n *\n * var object = { 'a': [{ 'b': { 'c': 7 } }] };\n * _.unset(object, 'a[0].b.c');\n * // => true\n *\n * console.log(object);\n * // => { 'a': [{ 'b': {} }] };\n *\n * _.unset(object, ['a', '0', 'b', 'c']);\n * // => true\n *\n * console.log(object);\n * // => { 'a': [{ 'b': {} }] };\n */\nfunction unset(object, path) {\n  return object == null ? true : baseUnset(object, path);\n}\n\nexport default unset;\n","import baseGet from './_baseGet.js';\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 */\nfunction get(object, path, defaultValue) {\n  var result = object == null ? undefined : baseGet(object, path);\n  return result === undefined ? defaultValue : result;\n}\n\nexport default get;\n","import baseAssignValue from './_baseAssignValue.js';\nimport eq from './eq.js';\n\n/**\n * This function is like `assignValue` except that it doesn't assign\n * `undefined` values.\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 */\nfunction assignMergeValue(object, key, value) {\n  if ((value !== undefined && !eq(object[key], value)) ||\n      (value === undefined && !(key in object))) {\n    baseAssignValue(object, key, value);\n  }\n}\n\nexport default assignMergeValue;\n","/**\n * Creates a base function for methods like `_.forIn` and `_.forOwn`.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n  return function(object, iteratee, keysFunc) {\n    var index = -1,\n        iterable = Object(object),\n        props = keysFunc(object),\n        length = props.length;\n\n    while (length--) {\n      var key = props[fromRight ? length : ++index];\n      if (iteratee(iterable[key], key, iterable) === false) {\n        break;\n      }\n    }\n    return object;\n  };\n}\n\nexport default createBaseFor;\n","import createBaseFor from './_createBaseFor.js';\n\n/**\n * The base implementation of `baseForOwn` which iterates over `object`\n * properties returned by `keysFunc` and invokes `iteratee` for each property.\n * Iteratee functions may exit iteration early by explicitly returning `false`.\n *\n * @private\n * @param {Object} object The object to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @param {Function} keysFunc The function to get the keys of `object`.\n * @returns {Object} Returns `object`.\n */\nvar baseFor = createBaseFor();\n\nexport default baseFor;\n","import isArrayLike from './isArrayLike.js';\nimport isObjectLike from './isObjectLike.js';\n\n/**\n * This method is like `_.isArrayLike` except that it also checks if `value`\n * is an 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 an array-like object,\n *  else `false`.\n * @example\n *\n * _.isArrayLikeObject([1, 2, 3]);\n * // => true\n *\n * _.isArrayLikeObject(document.body.children);\n * // => true\n *\n * _.isArrayLikeObject('abc');\n * // => false\n *\n * _.isArrayLikeObject(_.noop);\n * // => false\n */\nfunction isArrayLikeObject(value) {\n  return isObjectLike(value) && isArrayLike(value);\n}\n\nexport default isArrayLikeObject;\n","/**\n * Gets the value at `key`, unless `key` is \"__proto__\" or \"constructor\".\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 */\nfunction safeGet(object, key) {\n  if (key === 'constructor' && typeof object[key] === 'function') {\n    return;\n  }\n\n  if (key == '__proto__') {\n    return;\n  }\n\n  return object[key];\n}\n\nexport default safeGet;\n","import copyObject from './_copyObject.js';\nimport keysIn from './keysIn.js';\n\n/**\n * Converts `value` to a plain object flattening inherited enumerable string\n * keyed properties of `value` to own properties of the plain object.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Lang\n * @param {*} value The value to convert.\n * @returns {Object} Returns the converted plain object.\n * @example\n *\n * function Foo() {\n *   this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.assign({ 'a': 1 }, new Foo);\n * // => { 'a': 1, 'b': 2 }\n *\n * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));\n * // => { 'a': 1, 'b': 2, 'c': 3 }\n */\nfunction toPlainObject(value) {\n  return copyObject(value, keysIn(value));\n}\n\nexport default toPlainObject;\n","import assignMergeValue from './_assignMergeValue.js';\nimport cloneBuffer from './_cloneBuffer.js';\nimport cloneTypedArray from './_cloneTypedArray.js';\nimport copyArray from './_copyArray.js';\nimport initCloneObject from './_initCloneObject.js';\nimport isArguments from './isArguments.js';\nimport isArray from './isArray.js';\nimport isArrayLikeObject from './isArrayLikeObject.js';\nimport isBuffer from './isBuffer.js';\nimport isFunction from './isFunction.js';\nimport isObject from './isObject.js';\nimport isPlainObject from './isPlainObject.js';\nimport isTypedArray from './isTypedArray.js';\nimport safeGet from './_safeGet.js';\nimport toPlainObject from './toPlainObject.js';\n\n/**\n * A specialized version of `baseMerge` for arrays and objects which performs\n * deep merges and tracks traversed objects enabling objects with circular\n * references to be merged.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @param {string} key The key of the value to merge.\n * @param {number} srcIndex The index of `source`.\n * @param {Function} mergeFunc The function to merge values.\n * @param {Function} [customizer] The function to customize assigned values.\n * @param {Object} [stack] Tracks traversed source values and their merged\n *  counterparts.\n */\nfunction baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {\n  var objValue = safeGet(object, key),\n      srcValue = safeGet(source, key),\n      stacked = stack.get(srcValue);\n\n  if (stacked) {\n    assignMergeValue(object, key, stacked);\n    return;\n  }\n  var newValue = customizer\n    ? customizer(objValue, srcValue, (key + ''), object, source, stack)\n    : undefined;\n\n  var isCommon = newValue === undefined;\n\n  if (isCommon) {\n    var isArr = isArray(srcValue),\n        isBuff = !isArr && isBuffer(srcValue),\n        isTyped = !isArr && !isBuff && isTypedArray(srcValue);\n\n    newValue = srcValue;\n    if (isArr || isBuff || isTyped) {\n      if (isArray(objValue)) {\n        newValue = objValue;\n      }\n      else if (isArrayLikeObject(objValue)) {\n        newValue = copyArray(objValue);\n      }\n      else if (isBuff) {\n        isCommon = false;\n        newValue = cloneBuffer(srcValue, true);\n      }\n      else if (isTyped) {\n        isCommon = false;\n        newValue = cloneTypedArray(srcValue, true);\n      }\n      else {\n        newValue = [];\n      }\n    }\n    else if (isPlainObject(srcValue) || isArguments(srcValue)) {\n      newValue = objValue;\n      if (isArguments(objValue)) {\n        newValue = toPlainObject(objValue);\n      }\n      else if (!isObject(objValue) || isFunction(objValue)) {\n        newValue = initCloneObject(srcValue);\n      }\n    }\n    else {\n      isCommon = false;\n    }\n  }\n  if (isCommon) {\n    // Recursively merge objects and arrays (susceptible to call stack limits).\n    stack.set(srcValue, newValue);\n    mergeFunc(newValue, srcValue, srcIndex, customizer, stack);\n    stack['delete'](srcValue);\n  }\n  assignMergeValue(object, key, newValue);\n}\n\nexport default baseMergeDeep;\n","import Stack from './_Stack.js';\nimport assignMergeValue from './_assignMergeValue.js';\nimport baseFor from './_baseFor.js';\nimport baseMergeDeep from './_baseMergeDeep.js';\nimport isObject from './isObject.js';\nimport keysIn from './keysIn.js';\nimport safeGet from './_safeGet.js';\n\n/**\n * The base implementation of `_.merge` without support for multiple sources.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @param {number} srcIndex The index of `source`.\n * @param {Function} [customizer] The function to customize merged values.\n * @param {Object} [stack] Tracks traversed source values and their merged\n *  counterparts.\n */\nfunction baseMerge(object, source, srcIndex, customizer, stack) {\n  if (object === source) {\n    return;\n  }\n  baseFor(source, function(srcValue, key) {\n    stack || (stack = new Stack);\n    if (isObject(srcValue)) {\n      baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);\n    }\n    else {\n      var newValue = customizer\n        ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack)\n        : undefined;\n\n      if (newValue === undefined) {\n        newValue = srcValue;\n      }\n      assignMergeValue(object, key, newValue);\n    }\n  }, keysIn);\n}\n\nexport default baseMerge;\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n  return value;\n}\n\nexport default identity;\n","/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n  switch (args.length) {\n    case 0: return func.call(thisArg);\n    case 1: return func.call(thisArg, args[0]);\n    case 2: return func.call(thisArg, args[0], args[1]);\n    case 3: return func.call(thisArg, args[0], args[1], args[2]);\n  }\n  return func.apply(thisArg, args);\n}\n\nexport default apply;\n","import apply from './_apply.js';\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeMax = Math.max;\n\n/**\n * A specialized version of `baseRest` which transforms the rest array.\n *\n * @private\n * @param {Function} func The function to apply a rest parameter to.\n * @param {number} [start=func.length-1] The start position of the rest parameter.\n * @param {Function} transform The rest array transform.\n * @returns {Function} Returns the new function.\n */\nfunction overRest(func, start, transform) {\n  start = nativeMax(start === undefined ? (func.length - 1) : start, 0);\n  return function() {\n    var args = arguments,\n        index = -1,\n        length = nativeMax(args.length - start, 0),\n        array = Array(length);\n\n    while (++index < length) {\n      array[index] = args[start + index];\n    }\n    index = -1;\n    var otherArgs = Array(start + 1);\n    while (++index < start) {\n      otherArgs[index] = args[index];\n    }\n    otherArgs[start] = transform(array);\n    return apply(func, this, otherArgs);\n  };\n}\n\nexport default overRest;\n","/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n  return function() {\n    return value;\n  };\n}\n\nexport default constant;\n","import constant from './constant.js';\nimport defineProperty from './_defineProperty.js';\nimport identity from './identity.js';\n\n/**\n * The base implementation of `setToString` without support for hot loop shorting.\n *\n * @private\n * @param {Function} func The function to modify.\n * @param {Function} string The `toString` result.\n * @returns {Function} Returns `func`.\n */\nvar baseSetToString = !defineProperty ? identity : function(func, string) {\n  return defineProperty(func, 'toString', {\n    'configurable': true,\n    'enumerable': false,\n    'value': constant(string),\n    'writable': true\n  });\n};\n\nexport default baseSetToString;\n","/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n    HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n  var count = 0,\n      lastCalled = 0;\n\n  return function() {\n    var stamp = nativeNow(),\n        remaining = HOT_SPAN - (stamp - lastCalled);\n\n    lastCalled = stamp;\n    if (remaining > 0) {\n      if (++count >= HOT_COUNT) {\n        return arguments[0];\n      }\n    } else {\n      count = 0;\n    }\n    return func.apply(undefined, arguments);\n  };\n}\n\nexport default shortOut;\n","import baseSetToString from './_baseSetToString.js';\nimport shortOut from './_shortOut.js';\n\n/**\n * Sets the `toString` method of `func` to return `string`.\n *\n * @private\n * @param {Function} func The function to modify.\n * @param {Function} string The `toString` result.\n * @returns {Function} Returns `func`.\n */\nvar setToString = shortOut(baseSetToString);\n\nexport default setToString;\n","import identity from './identity.js';\nimport overRest from './_overRest.js';\nimport setToString from './_setToString.js';\n\n/**\n * The base implementation of `_.rest` which doesn't validate or coerce arguments.\n *\n * @private\n * @param {Function} func The function to apply a rest parameter to.\n * @param {number} [start=func.length-1] The start position of the rest parameter.\n * @returns {Function} Returns the new function.\n */\nfunction baseRest(func, start) {\n  return setToString(overRest(func, start, identity), func + '');\n}\n\nexport default baseRest;\n","import eq from './eq.js';\nimport isArrayLike from './isArrayLike.js';\nimport isIndex from './_isIndex.js';\nimport isObject from './isObject.js';\n\n/**\n * Checks if the given arguments are from an iteratee call.\n *\n * @private\n * @param {*} value The potential iteratee value argument.\n * @param {*} index The potential iteratee index or key argument.\n * @param {*} object The potential iteratee object argument.\n * @returns {boolean} Returns `true` if the arguments are from an iteratee call,\n *  else `false`.\n */\nfunction isIterateeCall(value, index, object) {\n  if (!isObject(object)) {\n    return false;\n  }\n  var type = typeof index;\n  if (type == 'number'\n        ? (isArrayLike(object) && isIndex(index, object.length))\n        : (type == 'string' && index in object)\n      ) {\n    return eq(object[index], value);\n  }\n  return false;\n}\n\nexport default isIterateeCall;\n","import baseRest from './_baseRest.js';\nimport isIterateeCall from './_isIterateeCall.js';\n\n/**\n * Creates a function like `_.assign`.\n *\n * @private\n * @param {Function} assigner The function to assign values.\n * @returns {Function} Returns the new assigner function.\n */\nfunction createAssigner(assigner) {\n  return baseRest(function(object, sources) {\n    var index = -1,\n        length = sources.length,\n        customizer = length > 1 ? sources[length - 1] : undefined,\n        guard = length > 2 ? sources[2] : undefined;\n\n    customizer = (assigner.length > 3 && typeof customizer == 'function')\n      ? (length--, customizer)\n      : undefined;\n\n    if (guard && isIterateeCall(sources[0], sources[1], guard)) {\n      customizer = length < 3 ? undefined : customizer;\n      length = 1;\n    }\n    object = Object(object);\n    while (++index < length) {\n      var source = sources[index];\n      if (source) {\n        assigner(object, source, index, customizer);\n      }\n    }\n    return object;\n  });\n}\n\nexport default createAssigner;\n","import baseMerge from './_baseMerge.js';\nimport createAssigner from './_createAssigner.js';\n\n/**\n * This method is like `_.assign` except that it recursively merges own and\n * inherited enumerable string keyed properties of source objects into the\n * destination object. Source properties that resolve to `undefined` are\n * skipped if a destination value exists. Array and plain object properties\n * are merged recursively. Other objects and value types are overridden by\n * assignment. Source objects are applied from left to right. Subsequent\n * sources overwrite property assignments of previous sources.\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 0.5.0\n * @category Object\n * @param {Object} object The destination object.\n * @param {...Object} [sources] The source objects.\n * @returns {Object} Returns `object`.\n * @example\n *\n * var object = {\n *   'a': [{ 'b': 2 }, { 'd': 4 }]\n * };\n *\n * var other = {\n *   'a': [{ 'c': 3 }, { 'e': 5 }]\n * };\n *\n * _.merge(object, other);\n * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }\n */\nvar merge = createAssigner(function(object, source, srcIndex) {\n  baseMerge(object, source, srcIndex);\n});\n\nexport default merge;\n","import assignValue from './_assignValue.js';\nimport castPath from './_castPath.js';\nimport isIndex from './_isIndex.js';\nimport isObject from './isObject.js';\nimport toKey from './_toKey.js';\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 */\nfunction baseSet(object, path, value, customizer) {\n  if (!isObject(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 (index != lastIndex) {\n      var objValue = nested[key];\n      newValue = customizer ? customizer(objValue, key, nested) : undefined;\n      if (newValue === undefined) {\n        newValue = isObject(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\nexport default baseSet;\n","import baseSet from './_baseSet.js';\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 */\nfunction set(object, path, value) {\n  return object == null ? object : baseSet(object, path, value);\n}\n\nexport default set;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/stylesmap\n */\n\nimport { get, isObject, merge, set, unset } from 'lodash-es';\n\n/**\n * Styles map. Allows handling (adding, removing, retrieving) a set of style rules (usually, of an element).\n *\n * The styles map is capable of normalizing style names so e.g. the following operations are possible:\n */\nexport default class StylesMap {\n\t/**\n\t * Creates Styles instance.\n\t *\n\t * @param {module:engine/view/stylesmap~StylesProcessor} styleProcessor\n\t */\n\tconstructor( styleProcessor ) {\n\t\t/**\n\t\t * Keeps an internal representation of styles map. Normalized styles are kept as object tree to allow unified modification and\n\t\t * value access model using lodash's get, set, unset, etc methods.\n\t\t *\n\t\t * When no style processor rules are defined the it acts as simple key-value storage.\n\t\t *\n\t\t * @private\n\t\t * @type {Object}\n\t\t */\n\t\tthis._styles = {};\n\n\t\t/**\n\t\t * An instance of the {@link module:engine/view/stylesmap~StylesProcessor}.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/view/stylesmap~StylesProcessor}\n\t\t */\n\t\tthis._styleProcessor = styleProcessor;\n\t}\n\n\t/**\n\t * Returns true if style map has no styles set.\n\t *\n\t * @returns {Boolean}\n\t */\n\tget isEmpty() {\n\t\tconst entries = Object.entries( this._styles );\n\t\tconst from = Array.from( entries );\n\n\t\treturn !from.length;\n\t}\n\n\t/**\n\t * Number of styles defined.\n\t *\n\t * @type {Number}\n\t */\n\tget size() {\n\t\tif ( this.isEmpty ) {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn this.getStyleNames().length;\n\t}\n\n\t/**\n\t * Set styles map to a new value.\n\t *\n\t *\t\tstyles.setTo( 'border:1px solid blue;margin-top:1px;' );\n\t *\n\t * @param {String} inlineStyle\n\t */\n\tsetTo( inlineStyle ) {\n\t\tthis.clear();\n\n\t\tconst parsedStyles = Array.from( parseInlineStyles( inlineStyle ).entries() );\n\n\t\tfor ( const [ key, value ] of parsedStyles ) {\n\t\t\tthis._styleProcessor.toNormalizedForm( key, value, this._styles );\n\t\t}\n\t}\n\n\t/**\n\t * Checks if a given style is set.\n\t *\n\t *\t\tstyles.setTo( 'margin-left:1px;' );\n\t *\n\t *\t\tstyles.has( 'margin-left' );    // -> true\n\t *\t\tstyles.has( 'padding' );        // -> false\n\t *\n\t * **Note**: This check supports normalized style names.\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.data.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tstyles.setTo( 'margin:2px;' );\n\t *\n\t *\t\tstyles.has( 'margin' );         // -> true\n\t *\t\tstyles.has( 'margin-top' );     // -> true\n\t *\t\tstyles.has( 'margin-left' );    // -> true\n\t *\n\t *\t\tstyles.remove( 'margin-top' );\n\t *\n\t *\t\tstyles.has( 'margin' );         // -> false\n\t *\t\tstyles.has( 'margin-top' );     // -> false\n\t *\t\tstyles.has( 'margin-left' );    // -> true\n\t *\n\t * @param {String} name Style name.\n\t * @returns {Boolean}\n\t */\n\thas( name ) {\n\t\tif ( this.isEmpty ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst styles = this._styleProcessor.getReducedForm( name, this._styles );\n\n\t\tconst propertyDescriptor = styles.find( ( [ property ] ) => property === name );\n\n\t\t// Only return a value if it is set;\n\t\treturn Array.isArray( propertyDescriptor );\n\t}\n\n\t/**\n\t * Sets a given style.\n\t *\n\t * Can insert one by one:\n\t *\n\t *\t\tstyles.set( 'color', 'blue' );\n\t *\t\tstyles.set( 'margin-right', '1em' );\n\t *\n\t * or many styles at once:\n\t *\n\t *\t\tstyles.set( {\n\t *\t\t\tcolor: 'blue',\n\t *\t\t\t'margin-right': '1em'\n\t *\t\t} );\n\t *\n\t * ***Note**:* This method uses {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules\n\t * enabled style processor rules} to normalize passed values.\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.data.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tstyles.set( 'margin', '2px' );\n\t *\n\t * The above code will set margin to:\n\t *\n\t *\t\tstyles.getNormalized( 'margin' );\n\t *\t\t// -> { top: '2px', right: '2px', bottom: '2px', left: '2px' }\n\t *\n\t * Which makes it possible to retrieve a \"sub-value\":\n\t *\n\t *\t\tstyles.get( 'margin-left' );       // -> '2px'\n\t *\n\t * Or modify it:\n\t *\n\t *\t\tstyles.remove( 'margin-left' );\n\t *\n\t *\t\tstyles.getNormalized( 'margin' );  // -> { top: '1px', bottom: '1px', right: '1px' }\n\t *\t\tstyles.toString();                 // -> 'margin-bottom:1px;margin-right:1px;margin-top:1px;'\n\t *\n\t * This method also allows to set normalized values directly (if a particular styles processor rule was enabled):\n\t *\n\t *\t\tstyles.set( 'border-color', { top: 'blue' } );\n\t *\t\tstyles.set( 'margin', { right: '2em' } );\n\t *\n\t *\t\tstyles.toString();                 // -> 'border-color-top:blue;margin-right:2em;'\n\t *\n\t * @param {String|Object} nameOrObject Style property name or object with multiple properties.\n\t * @param {String|Object} valueOrObject Value to set.\n\t */\n\tset( nameOrObject, valueOrObject ) {\n\t\tif ( isObject( nameOrObject ) ) {\n\t\t\tfor ( const [ key, value ] of Object.entries( nameOrObject ) ) {\n\t\t\t\tthis._styleProcessor.toNormalizedForm( key, value, this._styles );\n\t\t\t}\n\t\t} else {\n\t\t\tthis._styleProcessor.toNormalizedForm( nameOrObject, valueOrObject, this._styles );\n\t\t}\n\t}\n\n\t/**\n\t * Removes given style.\n\t *\n\t *\t\tstyles.setTo( 'background:#f00;margin-right:2px;' );\n\t *\n\t *\t\tstyles.remove( 'background' );\n\t *\n\t *\t\tstyles.toString();   // -> 'margin-right:2px;'\n\t *\n\t * ***Note**:* This method uses {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules\n\t * enabled style processor rules} to normalize passed values.\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.data.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tstyles.setTo( 'margin:1px' );\n\t *\n\t *\t\tstyles.remove( 'margin-top' );\n\t *\t\tstyles.remove( 'margin-right' );\n\t *\n\t *\t\tstyles.toString(); // -> 'margin-bottom:1px;margin-left:1px;'\n\t *\n\t * @param {String} name Style name.\n\t */\n\tremove( name ) {\n\t\tconst path = toPath( name );\n\n\t\tunset( this._styles, path );\n\t\tdelete this._styles[ name ];\n\n\t\tthis._cleanEmptyObjectsOnPath( path );\n\t}\n\n\t/**\n\t * Returns a normalized style object or a single value.\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.data.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tconst styles = new Styles();\n\t *\t\tstyles.setTo( 'margin:1px 2px 3em;' );\n\t *\n\t *\t\tstyles.getNormalized( 'margin' );\n\t *\t\t// will log:\n\t *\t\t// {\n\t *\t\t//     top: '1px',\n\t *\t\t//     right: '2px',\n\t *\t\t//     bottom: '3em',\n\t *\t\t//     left: '2px'     // normalized value from margin shorthand\n\t *\t\t// }\n\t *\n\t *\t\tstyles.getNormalized( 'margin-left' ); // -> '2px'\n\t *\n\t * **Note**: This method will only return normalized styles if a style processor was defined.\n\t *\n\t * @param {String} name Style name.\n\t * @returns {Object|String|undefined}\n\t */\n\tgetNormalized( name ) {\n\t\treturn this._styleProcessor.getNormalized( name, this._styles );\n\t}\n\n\t/**\n\t * Returns a normalized style string. Styles are sorted by name.\n\t *\n\t *\t\tstyles.set( 'margin' , '1px' );\n\t *\t\tstyles.set( 'background', '#f00' );\n\t *\n\t *\t\tstyles.toString(); // -> 'background:#f00;margin:1px;'\n\t *\n\t * **Note**: This method supports normalized styles if defined.\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.data.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tstyles.set( 'margin' , '1px' );\n\t *\t\tstyles.set( 'background', '#f00' );\n\t *\t\tstyles.remove( 'margin-top' );\n\t *\t\tstyles.remove( 'margin-right' );\n\t *\n\t *\t\tstyles.toString(); // -> 'background:#f00;margin-bottom:1px;margin-left:1px;'\n\t *\n\t * @returns {String}\n\t */\n\ttoString() {\n\t\tif ( this.isEmpty ) {\n\t\t\treturn '';\n\t\t}\n\n\t\treturn this._getStylesEntries()\n\t\t\t.map( arr => arr.join( ':' ) )\n\t\t\t.sort()\n\t\t\t.join( ';' ) + ';';\n\t}\n\n\t/**\n\t * Returns property as a value string or undefined if property is not set.\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.data.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tconst styles = new Styles();\n\t *\t\tstyles.setTo( 'margin:1px;' );\n\t *\t\tstyles.set( 'margin-bottom', '3em' );\n\t *\n\t *\t\tstyles.getAsString( 'margin' ); // -> 'margin: 1px 1px 3em;'\n\t *\n\t * Note, however, that all sub-values must be set for the longhand property name to return a value:\n\t *\n\t *\t\tconst styles = new Styles();\n\t *\t\tstyles.setTo( 'margin:1px;' );\n\t *\t\tstyles.remove( 'margin-bottom' );\n\t *\n\t *\t\tstyles.getAsString( 'margin' ); // -> undefined\n\t *\n\t * In the above scenario, it is not possible to return a `margin` value, so `undefined` is returned.\n\t * Instead, you should use:\n\t *\n\t *\t\tconst styles = new Styles();\n\t *\t\tstyles.setTo( 'margin:1px;' );\n\t *\t\tstyles.remove( 'margin-bottom' );\n\t *\n\t *\t\tfor ( const styleName of styles.getStyleNames() ) {\n\t *\t\t\tconsole.log( styleName, styles.getAsString( styleName ) );\n\t *\t\t}\n\t *\t\t// 'margin-top', '1px'\n\t *\t\t// 'margin-right', '1px'\n\t *\t\t// 'margin-left', '1px'\n\t *\n\t * In general, it is recommend to iterate over style names like in the example above. This way, you will always get all\n\t * the currently set style values. So, if all the 4 margin values would be set\n\t * the for-of loop above would yield only `'margin'`, `'1px'`:\n\t *\n\t *\t\tconst styles = new Styles();\n\t *\t\tstyles.setTo( 'margin:1px;' );\n\t *\n\t *\t\tfor ( const styleName of styles.getStyleNames() ) {\n\t *\t\t\tconsole.log( styleName, styles.getAsString( styleName ) );\n\t *\t\t}\n\t *\t\t// 'margin', '1px'\n\t *\n\t * **Note**: To get a normalized version of a longhand property use the {@link #getNormalized `#getNormalized()`} method.\n\t *\n\t * @param {String} propertyName\n\t * @returns {String|undefined}\n\t */\n\tgetAsString( propertyName ) {\n\t\tif ( this.isEmpty ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this._styles[ propertyName ] && !isObject( this._styles[ propertyName ] ) ) {\n\t\t\t// Try return styles set directly - values that are not parsed.\n\t\t\treturn this._styles[ propertyName ];\n\t\t}\n\n\t\tconst styles = this._styleProcessor.getReducedForm( propertyName, this._styles );\n\n\t\tconst propertyDescriptor = styles.find( ( [ property ] ) => property === propertyName );\n\n\t\t// Only return a value if it is set;\n\t\tif ( Array.isArray( propertyDescriptor ) ) {\n\t\t\treturn propertyDescriptor[ 1 ];\n\t\t}\n\t}\n\n\t/**\n\t * Returns style property names as they would appear when using {@link #toString `#toString()`}.\n\t *\n\t * @returns {Array.<String>}\n\t */\n\tgetStyleNames() {\n\t\tif ( this.isEmpty ) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst entries = this._getStylesEntries();\n\n\t\treturn entries.map( ( [ key ] ) => key );\n\t}\n\n\t/**\n\t * Removes all styles.\n\t */\n\tclear() {\n\t\tthis._styles = {};\n\t}\n\n\t/**\n\t * Returns normalized styles entries for further processing.\n\t *\n\t * @private\n\t * @returns {Array.<module:engine/view/stylesmap~PropertyDescriptor>}\n\t */\n\t_getStylesEntries() {\n\t\tconst parsed = [];\n\n\t\tconst keys = Object.keys( this._styles );\n\n\t\tfor ( const key of keys ) {\n\t\t\tparsed.push( ...this._styleProcessor.getReducedForm( key, this._styles ) );\n\t\t}\n\n\t\treturn parsed;\n\t}\n\n\t/**\n\t * Removes empty objects upon removing an entry from internal object.\n\t *\n\t * @param {String} path\n\t * @private\n\t */\n\t_cleanEmptyObjectsOnPath( path ) {\n\t\tconst pathParts = path.split( '.' );\n\t\tconst isChildPath = pathParts.length > 1;\n\n\t\tif ( !isChildPath ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst parentPath = pathParts.splice( 0, pathParts.length - 1 ).join( '.' );\n\n\t\tconst parentObject = get( this._styles, parentPath );\n\n\t\tif ( !parentObject ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst isParentEmpty = !Array.from( Object.keys( parentObject ) ).length;\n\n\t\tif ( isParentEmpty ) {\n\t\t\tthis.remove( parentPath );\n\t\t}\n\t}\n}\n\n/**\n * Style processor is responsible for writing and reading a normalized styles object.\n */\nexport class StylesProcessor {\n\t/**\n\t * Creates StylesProcessor instance.\n\t *\n\t * @private\n\t */\n\tconstructor() {\n\t\tthis._normalizers = new Map();\n\t\tthis._extractors = new Map();\n\t\tthis._reducers = new Map();\n\t\tthis._consumables = new Map();\n\t}\n\n\t/**\n\t * Parse style string value to a normalized object and appends it to styles object.\n\t *\n\t *\t\tconst styles = {};\n\t *\n\t *\t\tstylesProcessor.toNormalizedForm( 'margin', '1px', styles );\n\t *\n\t *\t\t// styles will consist: { margin: { top: '1px', right: '1px', bottom: '1px', left: '1px; } }\n\t *\n\t * **Note**: To define normalizer callbacks use {@link #setNormalizer}.\n\t *\n\t * @param {String} name Name of style property.\n\t * @param {String} propertyValue Value of style property.\n\t * @param {Object} styles Object holding normalized styles.\n\t */\n\ttoNormalizedForm( name, propertyValue, styles ) {\n\t\tif ( isObject( propertyValue ) ) {\n\t\t\tappendStyleValue( styles, toPath( name ), propertyValue );\n\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this._normalizers.has( name ) ) {\n\t\t\tconst normalizer = this._normalizers.get( name );\n\n\t\t\tconst { path, value } = normalizer( propertyValue );\n\n\t\t\tappendStyleValue( styles, path, value );\n\t\t} else {\n\t\t\tappendStyleValue( styles, name, propertyValue );\n\t\t}\n\t}\n\n\t/**\n\t * Returns a normalized version of a style property.\n\t *\t\tconst styles = {\n\t *\t\t\tmargin: { top: '1px', right: '1px', bottom: '1px', left: '1px; },\n\t *\t\t\tbackground: { color: '#f00' }\n\t *\t\t};\n\t *\n\t *\t\tstylesProcessor.getNormalized( 'background' );\n\t *\t\t// will return: { color: '#f00' }\n\t *\n\t *\t\tstylesProcessor.getNormalized( 'margin-top' );\n\t *\t\t// will return: '1px'\n\t *\n\t * **Note**: In some cases extracting single value requires defining an extractor callback {@link #setExtractor}.\n\t *\n\t * @param {String} name Name of style property.\n\t * @param {Object} styles Object holding normalized styles.\n\t * @returns {*}\n\t */\n\tgetNormalized( name, styles ) {\n\t\tif ( !name ) {\n\t\t\treturn merge( {}, styles );\n\t\t}\n\n\t\t// Might be empty string.\n\t\tif ( styles[ name ] !== undefined ) {\n\t\t\treturn styles[ name ];\n\t\t}\n\n\t\tif ( this._extractors.has( name ) ) {\n\t\t\tconst extractor = this._extractors.get( name );\n\n\t\t\tif ( typeof extractor === 'string' ) {\n\t\t\t\treturn get( styles, extractor );\n\t\t\t}\n\n\t\t\tconst value = extractor( name, styles );\n\n\t\t\tif ( value ) {\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\n\t\treturn get( styles, toPath( name ) );\n\t}\n\n\t/**\n\t * Returns a reduced form of style property form normalized object.\n\t *\n\t * For default margin reducer, the below code:\n\t *\n\t *\t\tstylesProcessor.getReducedForm( 'margin', {\n\t *\t\t\tmargin: { top: '1px', right: '1px', bottom: '2px', left: '1px; }\n\t *\t\t} );\n\t *\n\t * will return:\n\t *\n\t *\t\t[\n\t *\t\t\t[ 'margin', '1px 1px 2px' ]\n\t *\t\t]\n\t *\n\t * because it might be represented as a shorthand 'margin' value. However if one of margin long hand values is missing it should return:\n\t *\n\t *\t\t[\n\t *\t\t\t[ 'margin-top', '1px' ],\n\t *\t\t\t[ 'margin-right', '1px' ],\n\t *\t\t\t[ 'margin-bottom', '2px' ]\n\t *\t\t\t// the 'left' value is missing - cannot use 'margin' shorthand.\n\t *\t\t]\n\t *\n\t * **Note**: To define reducer callbacks use {@link #setReducer}.\n\t *\n\t * @param {String} name\n\t * @param {String} name Name of style property.\n\t * @param {Object} styles Object holding normalized styles.\n\t * @returns {Array.<module:engine/view/stylesmap~PropertyDescriptor>}\n\t */\n\tgetReducedForm( name, styles ) {\n\t\tconst normalizedValue = this.getNormalized( name, styles );\n\n\t\t// Might be empty string.\n\t\tif ( normalizedValue === undefined ) {\n\t\t\treturn [];\n\t\t}\n\n\t\tif ( this._reducers.has( name ) ) {\n\t\t\tconst reducer = this._reducers.get( name );\n\n\t\t\treturn reducer( normalizedValue );\n\t\t}\n\n\t\treturn [ [ name, normalizedValue ] ];\n\t}\n\n\t/**\n\t * Returns related style names.\n\t *\n\t *\t\tstylesProcessor.getRelatedStyles( 'margin' );\n\t *\t\t// will return: [ 'margin-top', 'margin-right', 'margin-bottom', 'margin-left' ];\n\t *\n\t *\t\tstylesProcessor.getRelatedStyles( 'margin-top' );\n\t *\t\t// will return: [ 'margin' ];\n\t *\n\t * **Note**: To define new style relations load an existing style processor or use\n\t * {@link module:engine/view/stylesmap~StylesProcessor#setStyleRelation `StylesProcessor.setStyleRelation()`}.\n\t *\n\t * @param {String} name\n\t * @returns {Array.<String>}\n\t */\n\tgetRelatedStyles( name ) {\n\t\treturn this._consumables.get( name ) || [];\n\t}\n\n\t/**\n\t * Adds a normalizer method for a style property.\n\t *\n\t * A normalizer returns describing how the value should be normalized.\n\t *\n\t * For instance 'margin' style is a shorthand for four margin values:\n\t *\n\t * - 'margin-top'\n\t * - 'margin-right'\n\t * - 'margin-bottom'\n\t * - 'margin-left'\n\t *\n\t * and can be written in various ways if some values are equal to others. For instance `'margin: 1px 2em;'` is a shorthand for\n\t * `'margin-top: 1px;margin-right: 2em;margin-bottom: 1px;margin-left: 2em'`.\n\t *\n\t * A normalizer should parse various margin notations as a single object:\n\t *\n\t *\t\tconst styles = {\n\t *\t\t\tmargin: {\n\t *\t\t\t\ttop: '1px',\n\t *\t\t\t\tright: '2em',\n\t *\t\t\t\tbottom: '1px',\n\t *\t\t\t\tleft: '2em'\n\t *\t\t\t}\n\t *\t\t};\n\t *\n\t * Thus a normalizer for 'margin' style should return an object defining style path and value to store:\n\t *\n\t *\t\tconst returnValue = {\n\t *\t\t\tpath: 'margin',\n\t *\t\t\tvalue: {\n\t *\t\t\t\ttop: '1px',\n\t *\t\t\t\tright: '2em',\n\t *\t\t\t\tbottom: '1px',\n\t *\t\t\t\tleft: '2em'\n\t *\t\t\t}\n\t *\t\t};\n\t *\n\t * Additionally to fully support all margin notations there should be also defined 4 normalizers for longhand margin notations. Below\n\t * is an example for 'margin-top' style property normalizer:\n\t *\n\t *\t\tstylesProcessor.setNormalizer( 'margin-top', valueString => {\n\t *\t\t\treturn {\n\t *\t\t\t\tpath: 'margin.top',\n\t *\t\t\t\tvalue: valueString\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * @param {String} name\n\t * @param {Function} callback\n\t */\n\tsetNormalizer( name, callback ) {\n\t\tthis._normalizers.set( name, callback );\n\t}\n\n\t/**\n\t * Adds a extractor callback for a style property.\n\t *\n\t * Most normalized style values are stored as one level objects. It is assumed that `'margin-top'` style will be stored as:\n\t *\n\t *\t\tconst styles = {\n\t *\t\t\tmargin: {\n\t *\t\t\t\ttop: 'value'\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t * However, some styles can have conflicting notations and thus it might be harder to extract a style value from shorthand. For instance\n\t * the 'border-top-style' can be defined using `'border-top:solid'`, `'border-style:solid none none none'` or by `'border:solid'`\n\t * shorthands. The default border styles processors stores styles as:\n\t *\n\t *\t\tconst styles = {\n\t *\t\t\tborder: {\n\t *\t\t\t\tstyle: {\n\t *\t\t\t\t\ttop: 'solid'\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t * as it is better to modify border style independently from other values. On the other part the output of the border might be\n\t * desired as `border-top`, `border-left`, etc notation.\n\t *\n\t * In the above example a reducer should return a side border value that combines style, color and width:\n\t *\n\t *\t\tstyleProcessor.setExtractor( 'border-top', styles => {\n\t *\t\t\treturn {\n\t *\t\t\t\tcolor: styles.border.color.top,\n\t *\t\t\t\tstyle: styles.border.style.top,\n\t *\t\t\t\twidth: styles.border.width.top\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * @param {String} name\n\t * @param {Function|String} callbackOrPath Callback that return a requested value or path string for single values.\n\t */\n\tsetExtractor( name, callbackOrPath ) {\n\t\tthis._extractors.set( name, callbackOrPath );\n\t}\n\n\t/**\n\t * Adds a reducer callback for a style property.\n\t *\n\t * Reducer returns a minimal notation for given style name. For longhand properties it is not required to write a reducer as\n\t * by default the direct value from style path is taken.\n\t *\n\t * For shorthand styles a reducer should return minimal style notation either by returning single name-value tuple or multiple tuples\n\t * if a shorthand cannot be used. For instance for a margin shorthand a reducer might return:\n\t *\n\t *\t\tconst marginShortHandTuple = [\n\t *\t\t\t[ 'margin', '1px 1px 2px' ]\n\t *\t\t];\n\t *\n\t * or a longhand tuples for defined values:\n\t *\n\t *\t\t// Considering margin.bottom and margin.left are undefined.\n\t *\t\tconst marginLonghandsTuples = [\n\t *\t\t\t[ 'margin-top', '1px' ],\n\t *\t\t\t[ 'margin-right', '1px' ]\n\t *\t\t];\n\t *\n\t * A reducer obtains a normalized style value:\n\t *\n\t *\t\t// Simplified reducer that always outputs 4 values which are always present:\n\t *\t\tstylesProcessor.setReducer( 'margin', margin => {\n\t *\t\t\treturn [\n\t *\t\t\t\t[ 'margin', `${ margin.top } ${ margin.right } ${ margin.bottom } ${ margin.left }` ]\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t * @param {String} name\n\t * @param {Function} callback\n\t */\n\tsetReducer( name, callback ) {\n\t\tthis._reducers.set( name, callback );\n\t}\n\n\t/**\n\t * Defines a style shorthand relation to other style notations.\n\t *\n\t *\t\tstylesProcessor.setStyleRelation( 'margin', [\n\t *\t\t\t'margin-top',\n\t *\t\t\t'margin-right',\n\t *\t\t\t'margin-bottom',\n\t *\t\t\t'margin-left'\n\t *\t\t] );\n\t *\n\t * This enables expanding of style names for shorthands. For instance, if defined,\n\t * {@link module:engine/conversion/viewconsumable~ViewConsumable view consumable} items are automatically created\n\t * for long-hand margin style notation alongside the `'margin'` item.\n\t *\n\t * This means that when an element being converted has a style `margin`, a converter for `margin-left` will work just\n\t * fine since the view consumable will contain a consumable `margin-left` item (thanks to the relation) and\n\t * `element.getStyle( 'margin-left' )` will work as well assuming that the style processor was correctly configured.\n\t * However, once `margin-left` is consumed, `margin` will not be consumable anymore.\n\t *\n\t * @param {String} shorthandName\n\t * @param {Array.<String>} styleNames\n\t */\n\tsetStyleRelation( shorthandName, styleNames ) {\n\t\tthis._mapStyleNames( shorthandName, styleNames );\n\n\t\tfor ( const alsoName of styleNames ) {\n\t\t\tthis._mapStyleNames( alsoName, [ shorthandName ] );\n\t\t}\n\t}\n\n\t/**\n\t * Set two-way binding of style names.\n\t *\n\t * @param {String} name\n\t * @param {Array.<String>} styleNames\n\t * @private\n\t */\n\t_mapStyleNames( name, styleNames ) {\n\t\tif ( !this._consumables.has( name ) ) {\n\t\t\tthis._consumables.set( name, [] );\n\t\t}\n\n\t\tthis._consumables.get( name ).push( ...styleNames );\n\t}\n}\n\n// Parses inline styles and puts property - value pairs into styles map.\n//\n// @param {String} stylesString Styles to parse.\n// @returns {Map.<String, String>} stylesMap Map of parsed properties and values.\nfunction parseInlineStyles( stylesString ) {\n\t// `null` if no quote was found in input string or last found quote was a closing quote. See below.\n\tlet quoteType = null;\n\tlet propertyNameStart = 0;\n\tlet propertyValueStart = 0;\n\tlet propertyName = null;\n\n\tconst stylesMap = new Map();\n\n\t// Do not set anything if input string is empty.\n\tif ( stylesString === '' ) {\n\t\treturn stylesMap;\n\t}\n\n\t// Fix inline styles that do not end with `;` so they are compatible with algorithm below.\n\tif ( stylesString.charAt( stylesString.length - 1 ) != ';' ) {\n\t\tstylesString = stylesString + ';';\n\t}\n\n\t// Seek the whole string for \"special characters\".\n\tfor ( let i = 0; i < stylesString.length; i++ ) {\n\t\tconst char = stylesString.charAt( i );\n\n\t\tif ( quoteType === null ) {\n\t\t\t// No quote found yet or last found quote was a closing quote.\n\t\t\tswitch ( char ) {\n\t\t\t\tcase ':':\n\t\t\t\t\t// Most of time colon means that property name just ended.\n\t\t\t\t\t// Sometimes however `:` is found inside property value (for example in background image url).\n\t\t\t\t\tif ( !propertyName ) {\n\t\t\t\t\t\t// Treat this as end of property only if property name is not already saved.\n\t\t\t\t\t\t// Save property name.\n\t\t\t\t\t\tpropertyName = stylesString.substr( propertyNameStart, i - propertyNameStart );\n\t\t\t\t\t\t// Save this point as the start of property value.\n\t\t\t\t\t\tpropertyValueStart = i + 1;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '\"':\n\t\t\t\tcase '\\'':\n\t\t\t\t\t// Opening quote found (this is an opening quote, because `quoteType` is `null`).\n\t\t\t\t\tquoteType = char;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase ';': {\n\t\t\t\t\t// Property value just ended.\n\t\t\t\t\t// Use previously stored property value start to obtain property value.\n\t\t\t\t\tconst propertyValue = stylesString.substr( propertyValueStart, i - propertyValueStart );\n\n\t\t\t\t\tif ( propertyName ) {\n\t\t\t\t\t\t// Save parsed part.\n\t\t\t\t\t\tstylesMap.set( propertyName.trim(), propertyValue.trim() );\n\t\t\t\t\t}\n\n\t\t\t\t\tpropertyName = null;\n\n\t\t\t\t\t// Save this point as property name start. Property name starts immediately after previous property value ends.\n\t\t\t\t\tpropertyNameStart = i + 1;\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if ( char === quoteType ) {\n\t\t\t// If a quote char is found and it is a closing quote, mark this fact by `null`-ing `quoteType`.\n\t\t\tquoteType = null;\n\t\t}\n\t}\n\n\treturn stylesMap;\n}\n\n// Return lodash compatible path from style name.\nfunction toPath( name ) {\n\treturn name.replace( '-', '.' );\n}\n\n// Appends style definition to the styles object.\n//\n// @param {String} nameOrPath\n// @param {String|Object} valueOrObject\n// @private\nfunction appendStyleValue( stylesObject, nameOrPath, valueOrObject ) {\n\tlet valueToSet = valueOrObject;\n\n\tif ( isObject( valueOrObject ) ) {\n\t\tvalueToSet = merge( {}, get( stylesObject, nameOrPath ), valueOrObject );\n\t}\n\n\tset( stylesObject, nameOrPath, valueToSet );\n}\n\n/**\n * A CSS style property descriptor that contains tuplet of two strings:\n *\n * - first string describes property name\n * - second string describes property value\n *\n *\t\tconst marginDescriptor = [ 'margin', '2px 3em' ];\n *\t\tconst marginTopDescriptor = [ 'margin-top', '2px' ];\n *\n * @typedef {Array.<String, String>} module:engine/view/stylesmap~PropertyDescriptor\n */\n\n/**\n * An object describing values associated with the sides of a box, for instance margins, paddings,\n * border widths, border colors, etc.\n *\n *\t\tconst margin = {\n *\t\t\ttop: '1px',\n *\t\t\tright: '3px',\n *\t\t\tbottom: '3px',\n *\t\t\tleft: '7px'\n *\t\t};\n *\n *\t\tconst borderColor = {\n *\t\t\ttop: 'red',\n *\t\t\tright: 'blue',\n *\t\t\tbottom: 'blue',\n *\t\t\tleft: 'red'\n *\t\t};\n *\n * @typedef {Object} module:engine/view/stylesmap~BoxSides\n *\n * @property {String} top Top side value.\n * @property {String} right Right side value.\n * @property {String} bottom Bottom side value.\n * @property {String} left Left side value.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/element\n */\n\nimport Node from './node';\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport toMap from '@ckeditor/ckeditor5-utils/src/tomap';\nimport toArray from '@ckeditor/ckeditor5-utils/src/toarray';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\nimport Matcher from './matcher';\nimport StylesMap from './stylesmap';\n\n// @if CK_DEBUG_ENGINE // const { convertMapToTags } = require( '../dev-utils/utils' );\n\n/**\n * View element.\n *\n * The editing engine does not define a fixed semantics of its elements (it is \"DTD-free\").\n * This is why the type of the {@link module:engine/view/element~Element} need to\n * be defined by the feature developer. When creating an element you should use one of the following methods:\n *\n * * {@link module:engine/view/downcastwriter~DowncastWriter#createContainerElement `downcastWriter#createContainerElement()`}\n * in order to create a {@link module:engine/view/containerelement~ContainerElement},\n * * {@link module:engine/view/downcastwriter~DowncastWriter#createAttributeElement `downcastWriter#createAttributeElement()`}\n * in order to create a {@link module:engine/view/attributeelement~AttributeElement},\n * * {@link module:engine/view/downcastwriter~DowncastWriter#createEmptyElement `downcastWriter#createEmptyElement()`}\n * in order to create a {@link module:engine/view/emptyelement~EmptyElement}.\n * * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement `downcastWriter#createUIElement()`}\n * in order to create a {@link module:engine/view/uielement~UIElement}.\n * * {@link module:engine/view/downcastwriter~DowncastWriter#createEditableElement `downcastWriter#createEditableElement()`}\n * in order to create a {@link module:engine/view/editableelement~EditableElement}.\n *\n * Note that for view elements which are not created from the model, like elements from mutations, paste or\n * {@link module:engine/controller/datacontroller~DataController#set data.set} it is not possible to define the type of the element.\n * In such cases the {@link module:engine/view/upcastwriter~UpcastWriter#createElement `UpcastWriter#createElement()`} method\n * should be used to create generic view elements.\n *\n * @extends module:engine/view/node~Node\n */\nexport default class Element extends Node {\n\t/**\n\t * Creates a view element.\n\t *\n\t * Attributes can be passed in various formats:\n\t *\n\t *\t\tnew Element( viewDocument, 'div', { class: 'editor', contentEditable: 'true' } ); // object\n\t *\t\tnew Element( viewDocument, 'div', [ [ 'class', 'editor' ], [ 'contentEditable', 'true' ] ] ); // map-like iterator\n\t *\t\tnew Element( viewDocument, 'div', mapOfAttributes ); // map\n\t *\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document instance to which this element belongs.\n\t * @param {String} name Node name.\n\t * @param {Object|Iterable} [attrs] Collection of attributes.\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into created element.\n\t */\n\tconstructor( document, name, attrs, children ) {\n\t\tsuper( document );\n\n\t\t/**\n\t\t * Name of the element.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.name = name;\n\n\t\t/**\n\t\t * Map of attributes, where attributes names are keys and attributes values are values.\n\t\t *\n\t\t * @protected\n\t\t * @member {Map} #_attrs\n\t\t */\n\t\tthis._attrs = parseAttributes( attrs );\n\n\t\t/**\n\t\t * Array of child nodes.\n\t\t *\n\t\t * @protected\n\t\t * @member {Array.<module:engine/view/node~Node>}\n\t\t */\n\t\tthis._children = [];\n\n\t\tif ( children ) {\n\t\t\tthis._insertChild( 0, children );\n\t\t}\n\n\t\t/**\n\t\t * Set of classes associated with element instance.\n\t\t *\n\t\t * @protected\n\t\t * @member {Set}\n\t\t */\n\t\tthis._classes = new Set();\n\n\t\tif ( this._attrs.has( 'class' ) ) {\n\t\t\t// Remove class attribute and handle it by class set.\n\t\t\tconst classString = this._attrs.get( 'class' );\n\t\t\tparseClasses( this._classes, classString );\n\t\t\tthis._attrs.delete( 'class' );\n\t\t}\n\n\t\t/**\n\t\t * Normalized styles.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:engine/view/stylesmap~StylesMap} module:engine/view/element~Element#_styles\n\t\t */\n\t\tthis._styles = new StylesMap( this.document.stylesProcessor );\n\n\t\tif ( this._attrs.has( 'style' ) ) {\n\t\t\t// Remove style attribute and handle it by styles map.\n\t\t\tthis._styles.setTo( this._attrs.get( 'style' ) );\n\n\t\t\tthis._attrs.delete( 'style' );\n\t\t}\n\n\t\t/**\n\t\t * Map of custom properties.\n\t\t * Custom properties can be added to element instance, will be cloned but not rendered into DOM.\n\t\t *\n\t\t * @protected\n\t\t * @member {Map}\n\t\t */\n\t\tthis._customProperties = new Map();\n\t}\n\n\t/**\n\t * Number of element's children.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget childCount() {\n\t\treturn this._children.length;\n\t}\n\n\t/**\n\t * Is `true` if there are no nodes inside this element, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isEmpty() {\n\t\treturn this._children.length === 0;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\telement.is( 'element' ); // -> true\n\t *\t\telement.is( 'node' ); // -> true\n\t *\t\telement.is( 'view:element' ); // -> true\n\t *\t\telement.is( 'view:node' ); // -> true\n\t *\n\t *\t\telement.is( 'model:element' ); // -> false\n\t *\t\telement.is( 'documentSelection' ); // -> false\n\t *\n\t * Assuming that the object being checked is an element, you can also check its\n\t * {@link module:engine/view/element~Element#name name}:\n\t *\n\t *\t\telement.is( 'element', 'img' ); // -> true if this is an <img> element\n\t *\t\ttext.is( 'element', 'img' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'element' || type === 'view:element' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'node' || type === 'view:node';\n\t\t} else {\n\t\t\treturn name === this.name && ( type === 'element' || type === 'view:element' );\n\t\t}\n\t}\n\n\t/**\n\t * Gets child at the given index.\n\t *\n\t * @param {Number} index Index of child.\n\t * @returns {module:engine/view/node~Node} Child node.\n\t */\n\tgetChild( index ) {\n\t\treturn this._children[ index ];\n\t}\n\n\t/**\n\t * Gets index of the given child node. Returns `-1` if child node is not found.\n\t *\n\t * @param {module:engine/view/node~Node} node Child node.\n\t * @returns {Number} Index of the child node.\n\t */\n\tgetChildIndex( node ) {\n\t\treturn this._children.indexOf( node );\n\t}\n\n\t/**\n\t * Gets child nodes iterator.\n\t *\n\t * @returns {Iterable.<module:engine/view/node~Node>} Child nodes iterator.\n\t */\n\tgetChildren() {\n\t\treturn this._children[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Returns an iterator that contains the keys for attributes. Order of inserting attributes is not preserved.\n\t *\n\t * @returns {Iterable.<String>} Keys for attributes.\n\t */\n\t* getAttributeKeys() {\n\t\tif ( this._classes.size > 0 ) {\n\t\t\tyield 'class';\n\t\t}\n\n\t\tif ( !this._styles.isEmpty ) {\n\t\t\tyield 'style';\n\t\t}\n\n\t\tyield* this._attrs.keys();\n\t}\n\n\t/**\n\t * Returns iterator that iterates over this element's attributes.\n\t *\n\t * Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.\n\t * This format is accepted by native `Map` object and also can be passed in `Node` constructor.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\t* getAttributes() {\n\t\tyield* this._attrs.entries();\n\n\t\tif ( this._classes.size > 0 ) {\n\t\t\tyield [ 'class', this.getAttribute( 'class' ) ];\n\t\t}\n\n\t\tif ( !this._styles.isEmpty ) {\n\t\t\tyield [ 'style', this.getAttribute( 'style' ) ];\n\t\t}\n\t}\n\n\t/**\n\t * Gets attribute by key. If attribute is not present - returns undefined.\n\t *\n\t * @param {String} key Attribute key.\n\t * @returns {String|undefined} Attribute value.\n\t */\n\tgetAttribute( key ) {\n\t\tif ( key == 'class' ) {\n\t\t\tif ( this._classes.size > 0 ) {\n\t\t\t\treturn [ ...this._classes ].join( ' ' );\n\t\t\t}\n\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif ( key == 'style' ) {\n\t\t\tconst inlineStyle = this._styles.toString();\n\n\t\t\treturn inlineStyle == '' ? undefined : inlineStyle;\n\t\t}\n\n\t\treturn this._attrs.get( key );\n\t}\n\n\t/**\n\t * Returns a boolean indicating whether an attribute with the specified key exists in the element.\n\t *\n\t * @param {String} key Attribute key.\n\t * @returns {Boolean} `true` if attribute with the specified key exists in the element, false otherwise.\n\t */\n\thasAttribute( key ) {\n\t\tif ( key == 'class' ) {\n\t\t\treturn this._classes.size > 0;\n\t\t}\n\n\t\tif ( key == 'style' ) {\n\t\t\treturn !this._styles.isEmpty;\n\t\t}\n\n\t\treturn this._attrs.has( key );\n\t}\n\n\t/**\n\t * Checks if this element is similar to other element.\n\t * Both elements should have the same name and attributes to be considered as similar. Two similar elements\n\t * can contain different set of children nodes.\n\t *\n\t * @param {module:engine/view/element~Element} otherElement\n\t * @returns {Boolean}\n\t */\n\tisSimilar( otherElement ) {\n\t\tif ( !( otherElement instanceof Element ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// If exactly the same Element is provided - return true immediately.\n\t\tif ( this === otherElement ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Check element name.\n\t\tif ( this.name != otherElement.name ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check number of attributes, classes and styles.\n\t\tif ( this._attrs.size !== otherElement._attrs.size || this._classes.size !== otherElement._classes.size ||\n\t\t\tthis._styles.size !== otherElement._styles.size ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if attributes are the same.\n\t\tfor ( const [ key, value ] of this._attrs ) {\n\t\t\tif ( !otherElement._attrs.has( key ) || otherElement._attrs.get( key ) !== value ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Check if classes are the same.\n\t\tfor ( const className of this._classes ) {\n\t\t\tif ( !otherElement._classes.has( className ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Check if styles are the same.\n\t\tfor ( const property of this._styles.getStyleNames() ) {\n\t\t\tif (\n\t\t\t\t!otherElement._styles.has( property ) ||\n\t\t\t\totherElement._styles.getAsString( property ) !== this._styles.getAsString( property )\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns true if class is present.\n\t * If more then one class is provided - returns true only when all classes are present.\n\t *\n\t *\t\telement.hasClass( 'foo' ); // Returns true if 'foo' class is present.\n\t *\t\telement.hasClass( 'foo', 'bar' ); // Returns true if 'foo' and 'bar' classes are both present.\n\t *\n\t * @param {...String} className\n\t */\n\thasClass( ...className ) {\n\t\tfor ( const name of className ) {\n\t\t\tif ( !this._classes.has( name ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns iterator that contains all class names.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetClassNames() {\n\t\treturn this._classes.keys();\n\t}\n\n\t/**\n\t * Returns style value for the given property mae.\n\t * If the style does not exist `undefined` is returned.\n\t *\n\t * **Note**: This method can work with normalized style names if\n\t * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#getAsString `StylesMap#getAsString()`} for details.\n\t *\n\t * For an element with style set to `'margin:1px'`:\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.data.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tconst element = view.change( writer => {\n\t *\t\t\tconst element = writer.createElement();\n\t *\t\t\twriter.setStyle( 'margin', '1px' );\n\t *\t\t\twriter.setStyle( 'margin-bottom', '3em' );\n\t *\n\t *\t\t\treturn element;\n\t *\t\t} );\n\t *\n\t *\t\telement.getStyle( 'margin' ); // -> 'margin: 1px 1px 3em;'\n\t *\n\t * @param {String} property\n\t * @returns {String|undefined}\n\t */\n\tgetStyle( property ) {\n\t\treturn this._styles.getAsString( property );\n\t}\n\n\t/**\n\t * Returns a normalized style object or single style value.\n\t *\n\t * For an element with style set to: margin:1px 2px 3em;\n\t *\n\t *\t\telement.getNormalizedStyle( 'margin' ) );\n\t *\n\t * will return:\n\t *\n\t *\t\t{\n\t *\t\t\ttop: '1px',\n\t *\t\t\tright: '2px',\n\t *\t\t\tbottom: '3em',\n\t *\t\t\tleft: '2px'    // a normalized value from margin shorthand\n\t *\t\t}\n\t *\n\t * and reading for single style value:\n\t *\n\t *\t\tstyles.getNormalizedStyle( 'margin-left' );\n\t *\n\t * Will return a `2px` string.\n\t *\n\t * **Note**: This method will return normalized values only if\n\t * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#getNormalized `StylesMap#getNormalized()`} for details.\n\t *\n\t *\n\t * @param {String} property Name of CSS property\n\t * @returns {Object|String|undefined}\n\t */\n\tgetNormalizedStyle( property ) {\n\t\treturn this._styles.getNormalized( property );\n\t}\n\n\t/**\n\t * Returns iterator that contains all style names.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetStyleNames() {\n\t\treturn this._styles.getStyleNames();\n\t}\n\n\t/**\n\t * Returns true if style keys are present.\n\t * If more then one style property is provided - returns true only when all properties are present.\n\t *\n\t *\t\telement.hasStyle( 'color' ); // Returns true if 'border-top' style is present.\n\t *\t\telement.hasStyle( 'color', 'border-top' ); // Returns true if 'color' and 'border-top' styles are both present.\n\t *\n\t * @param {...String} property\n\t */\n\thasStyle( ...property ) {\n\t\tfor ( const name of property ) {\n\t\t\tif ( !this._styles.has( name ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns ancestor element that match specified pattern.\n\t * Provided patterns should be compatible with {@link module:engine/view/matcher~Matcher Matcher} as it is used internally.\n\t *\n\t * @see module:engine/view/matcher~Matcher\n\t * @param {Object|String|RegExp|Function} patterns Patterns used to match correct ancestor.\n\t * See {@link module:engine/view/matcher~Matcher}.\n\t * @returns {module:engine/view/element~Element|null} Found element or `null` if no matching ancestor was found.\n\t */\n\tfindAncestor( ...patterns ) {\n\t\tconst matcher = new Matcher( ...patterns );\n\t\tlet parent = this.parent;\n\n\t\twhile ( parent ) {\n\t\t\tif ( matcher.match( parent ) ) {\n\t\t\t\treturn parent;\n\t\t\t}\n\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns the custom property value for the given key.\n\t *\n\t * @param {String|Symbol} key\n\t * @returns {*}\n\t */\n\tgetCustomProperty( key ) {\n\t\treturn this._customProperties.get( key );\n\t}\n\n\t/**\n\t * Returns an iterator which iterates over this element's custom properties.\n\t * Iterator provides `[ key, value ]` pairs for each stored property.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\t* getCustomProperties() {\n\t\tyield* this._customProperties.entries();\n\t}\n\n\t/**\n\t * Returns identity string based on element's name, styles, classes and other attributes.\n\t * Two elements that {@link #isSimilar are similar} will have same identity string.\n\t * It has the following format:\n\t *\n\t *\t\t'name class=\"class1,class2\" style=\"style1:value1;style2:value2\" attr1=\"val1\" attr2=\"val2\"'\n \t *\n\t * For example:\n\t *\n\t *\t\tconst element = writer.createContainerElement( 'foo', {\n\t *\t\t\tbanana: '10',\n\t *\t\t\tapple: '20',\n\t *\t\t\tstyle: 'color: red; border-color: white;',\n\t *\t\t\tclass: 'baz'\n\t *\t\t} );\n\t *\n\t *\t\t// returns 'foo class=\"baz\" style=\"border-color:white;color:red\" apple=\"20\" banana=\"10\"'\n\t *\t\telement.getIdentity();\n\t *\n\t * **Note**: Classes, styles and other attributes are sorted alphabetically.\n\t *\n\t * @returns {String}\n\t */\n\tgetIdentity() {\n\t\tconst classes = Array.from( this._classes ).sort().join( ',' );\n\t\tconst styles = this._styles.toString();\n\t\tconst attributes = Array.from( this._attrs ).map( i => `${ i[ 0 ] }=\"${ i[ 1 ] }\"` ).sort().join( ' ' );\n\n\t\treturn this.name +\n\t\t\t( classes == '' ? '' : ` class=\"${ classes }\"` ) +\n\t\t\t( !styles ? '' : ` style=\"${ styles }\"` ) +\n\t\t\t( attributes == '' ? '' : ` ${ attributes }` );\n\t}\n\n\t/**\n\t * Clones provided element.\n\t *\n\t * @protected\n\t * @param {Boolean} [deep=false] If set to `true` clones element and all its children recursively. When set to `false`,\n\t * element will be cloned without any children.\n\t * @returns {module:engine/view/element~Element} Clone of this element.\n\t */\n\t_clone( deep = false ) {\n\t\tconst childrenClone = [];\n\n\t\tif ( deep ) {\n\t\t\tfor ( const child of this.getChildren() ) {\n\t\t\t\tchildrenClone.push( child._clone( deep ) );\n\t\t\t}\n\t\t}\n\n\t\t// ContainerElement and AttributeElement should be also cloned properly.\n\t\tconst cloned = new this.constructor( this.document, this.name, this._attrs, childrenClone );\n\n\t\t// Classes and styles are cloned separately - this solution is faster than adding them back to attributes and\n\t\t// parse once again in constructor.\n\t\tcloned._classes = new Set( this._classes );\n\t\tcloned._styles.set( this._styles.getNormalized() );\n\n\t\t// Clone custom properties.\n\t\tcloned._customProperties = new Map( this._customProperties );\n\n\t\t// Clone filler offset method.\n\t\t// We can't define this method in a prototype because it's behavior which\n\t\t// is changed by e.g. toWidget() function from ckeditor5-widget. Perhaps this should be one of custom props.\n\t\tcloned.getFillerOffset = this.getFillerOffset;\n\n\t\treturn cloned;\n\t}\n\n\t/**\n\t * {@link module:engine/view/element~Element#_insertChild Insert} a child node or a list of child nodes at the end of this node\n\t * and sets the parent of these nodes to this element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#insert\n\t * @protected\n\t * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.\n\t * @fires module:engine/view/node~Node#change\n\t * @returns {Number} Number of appended nodes.\n\t */\n\t_appendChild( items ) {\n\t\treturn this._insertChild( this.childCount, items );\n\t}\n\n\t/**\n\t * Inserts a child node or a list of child nodes on the given index and sets the parent of these nodes to\n\t * this element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#insert\n\t * @protected\n\t * @param {Number} index Position where nodes should be inserted.\n\t * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.\n\t * @fires module:engine/view/node~Node#change\n\t * @returns {Number} Number of inserted nodes.\n\t */\n\t_insertChild( index, items ) {\n\t\tthis._fireChange( 'children', this );\n\t\tlet count = 0;\n\n\t\tconst nodes = normalize( this.document, items );\n\n\t\tfor ( const node of nodes ) {\n\t\t\t// If node that is being added to this element is already inside another element, first remove it from the old parent.\n\t\t\tif ( node.parent !== null ) {\n\t\t\t\tnode._remove();\n\t\t\t}\n\n\t\t\tnode.parent = this;\n\t\t\tnode.document = this.document;\n\n\t\t\tthis._children.splice( index, 0, node );\n\t\t\tindex++;\n\t\t\tcount++;\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/**\n\t * Removes number of child nodes starting at the given index and set the parent of these nodes to `null`.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#remove\n\t * @protected\n\t * @param {Number} index Number of the first node to remove.\n\t * @param {Number} [howMany=1] Number of nodes to remove.\n\t * @fires module:engine/view/node~Node#change\n\t * @returns {Array.<module:engine/view/node~Node>} The array of removed nodes.\n\t */\n\t_removeChildren( index, howMany = 1 ) {\n\t\tthis._fireChange( 'children', this );\n\n\t\tfor ( let i = index; i < index + howMany; i++ ) {\n\t\t\tthis._children[ i ].parent = null;\n\t\t}\n\n\t\treturn this._children.splice( index, howMany );\n\t}\n\n\t/**\n\t * Adds or overwrite attribute with a specified key and value.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#setAttribute\n\t * @protected\n\t * @param {String} key Attribute key.\n\t * @param {String} value Attribute value.\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_setAttribute( key, value ) {\n\t\tvalue = String( value );\n\n\t\tthis._fireChange( 'attributes', this );\n\n\t\tif ( key == 'class' ) {\n\t\t\tparseClasses( this._classes, value );\n\t\t} else if ( key == 'style' ) {\n\t\t\tthis._styles.setTo( value );\n\t\t} else {\n\t\t\tthis._attrs.set( key, value );\n\t\t}\n\t}\n\n\t/**\n\t * Removes attribute from the element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#removeAttribute\n\t * @protected\n\t * @param {String} key Attribute key.\n\t * @returns {Boolean} Returns true if an attribute existed and has been removed.\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_removeAttribute( key ) {\n\t\tthis._fireChange( 'attributes', this );\n\n\t\t// Remove class attribute.\n\t\tif ( key == 'class' ) {\n\t\t\tif ( this._classes.size > 0 ) {\n\t\t\t\tthis._classes.clear();\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\t// Remove style attribute.\n\t\tif ( key == 'style' ) {\n\t\t\tif ( !this._styles.isEmpty ) {\n\t\t\t\tthis._styles.clear();\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\t// Remove other attributes.\n\t\treturn this._attrs.delete( key );\n\t}\n\n\t/**\n\t * Adds specified class.\n\t *\n\t *\t\telement._addClass( 'foo' ); // Adds 'foo' class.\n\t *\t\telement._addClass( [ 'foo', 'bar' ] ); // Adds 'foo' and 'bar' classes.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#addClass\n\t * @protected\n\t * @param {Array.<String>|String} className\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_addClass( className ) {\n\t\tthis._fireChange( 'attributes', this );\n\n\t\tfor ( const name of toArray( className ) ) {\n\t\t\tthis._classes.add( name );\n\t\t}\n\t}\n\n\t/**\n\t * Removes specified class.\n\t *\n\t *\t\telement._removeClass( 'foo' );  // Removes 'foo' class.\n\t *\t\telement._removeClass( [ 'foo', 'bar' ] ); // Removes both 'foo' and 'bar' classes.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#removeClass\n\t * @protected\n\t * @param {Array.<String>|String} className\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_removeClass( className ) {\n\t\tthis._fireChange( 'attributes', this );\n\n\t\tfor ( const name of toArray( className ) ) {\n\t\t\tthis._classes.delete( name );\n\t\t}\n\t}\n\n\t/**\n\t * Adds style to the element.\n\t *\n\t *\t\telement._setStyle( 'color', 'red' );\n\t *\t\telement._setStyle( {\n\t *\t\t\tcolor: 'red',\n\t *\t\t\tposition: 'fixed'\n\t *\t\t} );\n\t *\n\t * **Note**: This method can work with normalized style names if\n\t * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#set `StylesMap#set()`} for details.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#setStyle\n\t * @protected\n\t * @param {String|Object} property Property name or object with key - value pairs.\n\t * @param {String} [value] Value to set. This parameter is ignored if object is provided as the first parameter.\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_setStyle( property, value ) {\n\t\tthis._fireChange( 'attributes', this );\n\n\t\tthis._styles.set( property, value );\n\t}\n\n\t/**\n\t * Removes specified style.\n\t *\n\t *\t\telement._removeStyle( 'color' );  // Removes 'color' style.\n\t *\t\telement._removeStyle( [ 'color', 'border-top' ] ); // Removes both 'color' and 'border-top' styles.\n\t *\n\t * **Note**: This method can work with normalized style names if\n\t * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#remove `StylesMap#remove()`} for details.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#removeStyle\n\t * @protected\n\t * @param {Array.<String>|String} property\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_removeStyle( property ) {\n\t\tthis._fireChange( 'attributes', this );\n\n\t\tfor ( const name of toArray( property ) ) {\n\t\t\tthis._styles.remove( name );\n\t\t}\n\t}\n\n\t/**\n\t * Sets a custom property. Unlike attributes, custom properties are not rendered to the DOM,\n\t * so they can be used to add special data to elements.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#setCustomProperty\n\t * @protected\n\t * @param {String|Symbol} key\n\t * @param {*} value\n\t */\n\t_setCustomProperty( key, value ) {\n\t\tthis._customProperties.set( key, value );\n\t}\n\n\t/**\n\t * Removes the custom property stored under the given key.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#removeCustomProperty\n\t * @protected\n\t * @param {String|Symbol} key\n\t * @returns {Boolean} Returns true if property was removed.\n\t */\n\t_removeCustomProperty( key ) {\n\t\treturn this._customProperties.delete( key );\n\t}\n\n\t/**\n\t * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.\n\t *\n\t * @abstract\n\t * @method module:engine/view/element~Element#getFillerOffset\n\t */\n\n\t// @if CK_DEBUG_ENGINE // printTree( level = 0) {\n\t// @if CK_DEBUG_ENGINE // \tlet string = '';\n\n\t// @if CK_DEBUG_ENGINE //\tstring += '\\t'.repeat( level ) + `<${ this.name }${ convertMapToTags( this.getAttributes() ) }>`;\n\n\t// @if CK_DEBUG_ENGINE //\tfor ( const child of this.getChildren() ) {\n\t// @if CK_DEBUG_ENGINE //\t\tif ( child.is( '$text' ) ) {\n\t// @if CK_DEBUG_ENGINE //\t\t\tstring += '\\n' + '\\t'.repeat( level + 1 ) + child.data;\n\t// @if CK_DEBUG_ENGINE //\t\t} else {\n\t// @if CK_DEBUG_ENGINE //\t\t\tstring += '\\n' + child.printTree( level + 1 );\n\t// @if CK_DEBUG_ENGINE //\t\t}\n\t// @if CK_DEBUG_ENGINE //\t}\n\n\t// @if CK_DEBUG_ENGINE //\tif ( this.childCount ) {\n\t// @if CK_DEBUG_ENGINE //\t\tstring += '\\n' + '\\t'.repeat( level );\n\t// @if CK_DEBUG_ENGINE //\t}\n\n\t// @if CK_DEBUG_ENGINE //\tstring += `</${ this.name }>`;\n\n\t// @if CK_DEBUG_ENGINE //\treturn string;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logTree() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( this.printTree() );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\n// Parses attributes provided to the element constructor before they are applied to an element. If attributes are passed\n// as an object (instead of `Iterable`), the object is transformed to the map. Attributes with `null` value are removed.\n// Attributes with non-`String` value are converted to `String`.\n//\n// @param {Object|Iterable} attrs Attributes to parse.\n// @returns {Map} Parsed attributes.\nfunction parseAttributes( attrs ) {\n\tattrs = toMap( attrs );\n\n\tfor ( const [ key, value ] of attrs ) {\n\t\tif ( value === null ) {\n\t\t\tattrs.delete( key );\n\t\t} else if ( typeof value != 'string' ) {\n\t\t\tattrs.set( key, String( value ) );\n\t\t}\n\t}\n\n\treturn attrs;\n}\n\n// Parses class attribute and puts all classes into classes set.\n// Classes set s cleared before insertion.\n//\n// @param {Set.<String>} classesSet Set to insert parsed classes.\n// @param {String} classesString String with classes to parse.\nfunction parseClasses( classesSet, classesString ) {\n\tconst classArray = classesString.split( /\\s+/ );\n\tclassesSet.clear();\n\tclassArray.forEach( name => classesSet.add( name ) );\n}\n\n// Converts strings to Text and non-iterables to arrays.\n//\n// @param {String|module:engine/view/item~Item|Iterable.<String|module:engine/view/item~Item>}\n// @returns {Iterable.<module:engine/view/node~Node>}\nfunction normalize( document, nodes ) {\n\t// Separate condition because string is iterable.\n\tif ( typeof nodes == 'string' ) {\n\t\treturn [ new Text( document, nodes ) ];\n\t}\n\n\tif ( !isIterable( nodes ) ) {\n\t\tnodes = [ nodes ];\n\t}\n\n\t// Array.from to enable .map() on non-arrays.\n\treturn Array.from( nodes )\n\t\t.map( node => {\n\t\t\tif ( typeof node == 'string' ) {\n\t\t\t\treturn new Text( document, node );\n\t\t\t}\n\n\t\t\tif ( node instanceof TextProxy ) {\n\t\t\t\treturn new Text( document, node.data );\n\t\t\t}\n\n\t\t\treturn node;\n\t\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/containerelement\n */\n\nimport Element from './element';\n\n/**\n * Containers are elements which define document structure. They define boundaries for\n * {@link module:engine/view/attributeelement~AttributeElement attributes}. They are mostly used for block elements like `<p>` or `<div>`.\n *\n * Editing engine does not define a fixed HTML DTD. This is why a feature developer needs to choose between various\n * types (container element, {@link module:engine/view/attributeelement~AttributeElement attribute element},\n * {@link module:engine/view/emptyelement~EmptyElement empty element}, etc) when developing a feature.\n *\n * The container element should be your default choice when writing a converter, unless:\n *\n * * this element represents a model text attribute (then use {@link module:engine/view/attributeelement~AttributeElement}),\n * * this is an empty element like `<img>` (then use {@link module:engine/view/emptyelement~EmptyElement}),\n * * this is a root element,\n * * this is a nested editable element (then use  {@link module:engine/view/editableelement~EditableElement}).\n *\n * To create a new container element instance use the\n * {@link module:engine/view/downcastwriter~DowncastWriter#createContainerElement `DowncastWriter#createContainerElement()`}\n * method.\n *\n * @extends module:engine/view/element~Element\n */\nexport default class ContainerElement extends Element {\n\t/**\n\t * Creates a container element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#createContainerElement\n\t * @see module:engine/view/element~Element\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document instance to which this element belongs.\n\t * @param {String} name Node name.\n\t * @param {Object|Iterable} [attrs] Collection of attributes.\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into created element.\n\t */\n\tconstructor( document, name, attrs, children ) {\n\t\tsuper( document, name, attrs, children );\n\n\t\t/**\n\t\t * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.\n\t\t *\n\t\t * @method #getFillerOffset\n\t\t * @returns {Number|null} Block filler offset or `null` if block filler is not needed.\n\t\t */\n\t\tthis.getFillerOffset = getFillerOffset;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tcontainerElement.is( 'containerElement' ); // -> true\n\t *\t\tcontainerElement.is( 'element' ); // -> true\n\t *\t\tcontainerElement.is( 'node' ); // -> true\n\t *\t\tcontainerElement.is( 'view:containerElement' ); // -> true\n\t *\t\tcontainerElement.is( 'view:element' ); // -> true\n\t *\t\tcontainerElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\tcontainerElement.is( 'model:element' ); // -> false\n\t *\t\tcontainerElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is a container element, you can also check its\n\t * {@link module:engine/view/containerelement~ContainerElement#name name}:\n\t *\n\t *\t\tcontainerElement.is( 'element', 'div' ); // -> true if this is a div container element\n\t *\t\tcontainerElement.is( 'contaienrElement', 'div' ); // -> same as above\n\t *\t\ttext.is( 'element', 'div' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'containerElement' || type === 'view:containerElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'element' || type === 'view:element' ||\n\t\t\t\ttype === 'node' || type === 'view:node';\n\t\t} else {\n\t\t\treturn name === this.name && (\n\t\t\t\ttype === 'containerElement' || type === 'view:containerElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'element' || type === 'view:element'\n\t\t\t);\n\t\t}\n\t}\n}\n\n/**\n * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.\n *\n * @returns {Number|null} Block filler offset or `null` if block filler is not needed.\n */\nexport function getFillerOffset() {\n\tconst children = [ ...this.getChildren() ];\n\tconst lastChild = children[ this.childCount - 1 ];\n\n\t// Block filler is required after a `<br>` if it's the last element in its container. See #1422.\n\tif ( lastChild && lastChild.is( 'element', 'br' ) ) {\n\t\treturn this.childCount;\n\t}\n\n\tfor ( const child of children ) {\n\t\t// If there's any non-UI element – don't render the bogus.\n\t\tif ( !child.is( 'uiElement' ) ) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t// If there are only UI elements – render the bogus at the end of the element.\n\treturn this.childCount;\n}\n","import copyObject from './_copyObject.js';\nimport createAssigner from './_createAssigner.js';\nimport keysIn from './keysIn.js';\n\n/**\n * This method is like `_.assign` except that it iterates over own and\n * inherited source properties.\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @alias extend\n * @category Object\n * @param {Object} object The destination object.\n * @param {...Object} [sources] The source objects.\n * @returns {Object} Returns `object`.\n * @see _.assign\n * @example\n *\n * function Foo() {\n *   this.a = 1;\n * }\n *\n * function Bar() {\n *   this.c = 3;\n * }\n *\n * Foo.prototype.b = 2;\n * Bar.prototype.d = 4;\n *\n * _.assignIn({ 'a': 0 }, new Foo, new Bar);\n * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }\n */\nvar assignIn = createAssigner(function(object, source) {\n  copyObject(source, keysIn(source), object);\n});\n\nexport default assignIn;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/observablemixin\n */\n\nimport EmitterMixin from './emittermixin';\nimport CKEditorError from './ckeditorerror';\nimport { extend, isObject } from 'lodash-es';\n\nconst observablePropertiesSymbol = Symbol( 'observableProperties' );\nconst boundObservablesSymbol = Symbol( 'boundObservables' );\nconst boundPropertiesSymbol = Symbol( 'boundProperties' );\n\n/**\n * A mixin that injects the \"observable properties\" and data binding functionality described in the\n * {@link ~Observable} interface.\n *\n * Read more about the concept of observables in the:\n * * {@glink framework/guides/architecture/core-editor-architecture#event-system-and-observables \"Event system and observables\"}\n * section of the {@glink framework/guides/architecture/core-editor-architecture \"Core editor architecture\"} guide,\n * * {@glink framework/guides/deep-dive/observables \"Observables\" deep dive} guide.\n *\n * @mixin ObservableMixin\n * @mixes module:utils/emittermixin~EmitterMixin\n * @implements module:utils/observablemixin~Observable\n */\nconst ObservableMixin = {\n\t/**\n\t * @inheritDoc\n\t */\n\tset( name, value ) {\n\t\t// If the first parameter is an Object, iterate over its properties.\n\t\tif ( isObject( name ) ) {\n\t\t\tObject.keys( name ).forEach( property => {\n\t\t\t\tthis.set( property, name[ property ] );\n\t\t\t}, this );\n\n\t\t\treturn;\n\t\t}\n\n\t\tinitObservable( this );\n\n\t\tconst properties = this[ observablePropertiesSymbol ];\n\n\t\tif ( ( name in this ) && !properties.has( name ) ) {\n\t\t\t/**\n\t\t\t * Cannot override an existing property.\n\t\t\t *\n\t\t\t * This error is thrown when trying to {@link ~Observable#set set} a property with\n\t\t\t * a name of an already existing property. For example:\n\t\t\t *\n\t\t\t *\t\tlet observable = new Model();\n\t\t\t *\t\tobservable.property = 1;\n\t\t\t *\t\tobservable.set( 'property', 2 );\t\t\t// throws\n\t\t\t *\n\t\t\t *\t\tobservable.set( 'property', 1 );\n\t\t\t *\t\tobservable.set( 'property', 2 );\t\t\t// ok, because this is an existing property.\n\t\t\t *\n\t\t\t * @error observable-set-cannot-override\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'observable-set-cannot-override', this );\n\t\t}\n\n\t\tObject.defineProperty( this, name, {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\n\t\t\tget() {\n\t\t\t\treturn properties.get( name );\n\t\t\t},\n\n\t\t\tset( value ) {\n\t\t\t\tconst oldValue = properties.get( name );\n\n\t\t\t\t// Fire `set` event before the new value will be set to make it possible\n\t\t\t\t// to override observable property without affecting `change` event.\n\t\t\t\t// See https://github.com/ckeditor/ckeditor5-utils/issues/171.\n\t\t\t\tlet newValue = this.fire( 'set:' + name, name, value, oldValue );\n\n\t\t\t\tif ( newValue === undefined ) {\n\t\t\t\t\tnewValue = value;\n\t\t\t\t}\n\n\t\t\t\t// Allow undefined as an initial value like A.define( 'x', undefined ) (#132).\n\t\t\t\t// Note: When properties map has no such own property, then its value is undefined.\n\t\t\t\tif ( oldValue !== newValue || !properties.has( name ) ) {\n\t\t\t\t\tproperties.set( name, newValue );\n\t\t\t\t\tthis.fire( 'change:' + name, name, newValue, oldValue );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\tthis[ name ] = value;\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tbind( ...bindProperties ) {\n\t\tif ( !bindProperties.length || !isStringArray( bindProperties ) ) {\n\t\t\t/**\n\t\t\t * All properties must be strings.\n\t\t\t *\n\t\t\t * @error observable-bind-wrong-properties\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'observable-bind-wrong-properties', this );\n\t\t}\n\n\t\tif ( ( new Set( bindProperties ) ).size !== bindProperties.length ) {\n\t\t\t/**\n\t\t\t * Properties must be unique.\n\t\t\t *\n\t\t\t * @error observable-bind-duplicate-properties\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'observable-bind-duplicate-properties', this );\n\t\t}\n\n\t\tinitObservable( this );\n\n\t\tconst boundProperties = this[ boundPropertiesSymbol ];\n\n\t\tbindProperties.forEach( propertyName => {\n\t\t\tif ( boundProperties.has( propertyName ) ) {\n\t\t\t\t/**\n\t\t\t\t * Cannot bind the same property more than once.\n\t\t\t\t *\n\t\t\t\t * @error observable-bind-rebind\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'observable-bind-rebind', this );\n\t\t\t}\n\t\t} );\n\n\t\tconst bindings = new Map();\n\n\t\t// @typedef {Object} Binding\n\t\t// @property {Array} property Property which is bound.\n\t\t// @property {Array} to Array of observable–property components of the binding (`{ observable: ..., property: .. }`).\n\t\t// @property {Array} callback A function which processes `to` components.\n\t\tbindProperties.forEach( a => {\n\t\t\tconst binding = { property: a, to: [] };\n\n\t\t\tboundProperties.set( a, binding );\n\t\t\tbindings.set( a, binding );\n\t\t} );\n\n\t\t// @typedef {Object} BindChain\n\t\t// @property {Function} to See {@link ~ObservableMixin#_bindTo}.\n\t\t// @property {Function} toMany See {@link ~ObservableMixin#_bindToMany}.\n\t\t// @property {module:utils/observablemixin~Observable} _observable The observable which initializes the binding.\n\t\t// @property {Array} _bindProperties Array of `_observable` properties to be bound.\n\t\t// @property {Array} _to Array of `to()` observable–properties (`{ observable: toObservable, properties: ...toProperties }`).\n\t\t// @property {Map} _bindings Stores bindings to be kept in\n\t\t// {@link ~ObservableMixin#_boundProperties}/{@link ~ObservableMixin#_boundObservables}\n\t\t// initiated in this binding chain.\n\t\treturn {\n\t\t\tto: bindTo,\n\t\t\ttoMany: bindToMany,\n\n\t\t\t_observable: this,\n\t\t\t_bindProperties: bindProperties,\n\t\t\t_to: [],\n\t\t\t_bindings: bindings\n\t\t};\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tunbind( ...unbindProperties ) {\n\t\t// Nothing to do here if not inited yet.\n\t\tif ( !( this[ observablePropertiesSymbol ] ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst boundProperties = this[ boundPropertiesSymbol ];\n\t\tconst boundObservables = this[ boundObservablesSymbol ];\n\n\t\tif ( unbindProperties.length ) {\n\t\t\tif ( !isStringArray( unbindProperties ) ) {\n\t\t\t\t/**\n\t\t\t\t * Properties must be strings.\n\t\t\t\t *\n\t\t\t\t * @error observable-unbind-wrong-properties\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'observable-unbind-wrong-properties', this );\n\t\t\t}\n\n\t\t\tunbindProperties.forEach( propertyName => {\n\t\t\t\tconst binding = boundProperties.get( propertyName );\n\n\t\t\t\t// Nothing to do if the binding is not defined\n\t\t\t\tif ( !binding ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet toObservable, toProperty, toProperties, toPropertyBindings;\n\n\t\t\t\tbinding.to.forEach( to => {\n\t\t\t\t\t// TODO: ES6 destructuring.\n\t\t\t\t\ttoObservable = to[ 0 ];\n\t\t\t\t\ttoProperty = to[ 1 ];\n\t\t\t\t\ttoProperties = boundObservables.get( toObservable );\n\t\t\t\t\ttoPropertyBindings = toProperties[ toProperty ];\n\n\t\t\t\t\ttoPropertyBindings.delete( binding );\n\n\t\t\t\t\tif ( !toPropertyBindings.size ) {\n\t\t\t\t\t\tdelete toProperties[ toProperty ];\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( !Object.keys( toProperties ).length ) {\n\t\t\t\t\t\tboundObservables.delete( toObservable );\n\t\t\t\t\t\tthis.stopListening( toObservable, 'change' );\n\t\t\t\t\t}\n\t\t\t\t} );\n\n\t\t\t\tboundProperties.delete( propertyName );\n\t\t\t} );\n\t\t} else {\n\t\t\tboundObservables.forEach( ( bindings, boundObservable ) => {\n\t\t\t\tthis.stopListening( boundObservable, 'change' );\n\t\t\t} );\n\n\t\t\tboundObservables.clear();\n\t\t\tboundProperties.clear();\n\t\t}\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdecorate( methodName ) {\n\t\tconst originalMethod = this[ methodName ];\n\n\t\tif ( !originalMethod ) {\n\t\t\t/**\n\t\t\t * Cannot decorate an undefined method.\n\t\t\t *\n\t\t\t * @error observablemixin-cannot-decorate-undefined\n\t\t\t * @param {Object} object The object which method should be decorated.\n\t\t\t * @param {String} methodName Name of the method which does not exist.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'observablemixin-cannot-decorate-undefined',\n\t\t\t\tthis,\n\t\t\t\t{ object: this, methodName }\n\t\t\t);\n\t\t}\n\n\t\tthis.on( methodName, ( evt, args ) => {\n\t\t\tevt.return = originalMethod.apply( this, args );\n\t\t} );\n\n\t\tthis[ methodName ] = function( ...args ) {\n\t\t\treturn this.fire( methodName, args );\n\t\t};\n\t}\n};\n\nextend( ObservableMixin, EmitterMixin );\n\nexport default ObservableMixin;\n\n// Init symbol properties needed for the observable mechanism to work.\n//\n// @private\n// @param {module:utils/observablemixin~ObservableMixin} observable\nfunction initObservable( observable ) {\n\t// Do nothing if already inited.\n\tif ( observable[ observablePropertiesSymbol ] ) {\n\t\treturn;\n\t}\n\n\t// The internal hash containing the observable's state.\n\t//\n\t// @private\n\t// @type {Map}\n\tObject.defineProperty( observable, observablePropertiesSymbol, {\n\t\tvalue: new Map()\n\t} );\n\n\t// Map containing bindings to external observables. It shares the binding objects\n\t// (`{ observable: A, property: 'a', to: ... }`) with {@link module:utils/observablemixin~ObservableMixin#_boundProperties} and\n\t// it is used to observe external observables to update own properties accordingly.\n\t// See {@link module:utils/observablemixin~ObservableMixin#bind}.\n\t//\n\t//\t\tA.bind( 'a', 'b', 'c' ).to( B, 'x', 'y', 'x' );\n\t//\t\tconsole.log( A._boundObservables );\n\t//\n\t//\t\t\tMap( {\n\t//\t\t\t\tB: {\n\t//\t\t\t\t\tx: Set( [\n\t//\t\t\t\t\t\t{ observable: A, property: 'a', to: [ [ B, 'x' ] ] },\n\t//\t\t\t\t\t\t{ observable: A, property: 'c', to: [ [ B, 'x' ] ] }\n\t//\t\t\t\t\t] ),\n\t//\t\t\t\t\ty: Set( [\n\t//\t\t\t\t\t\t{ observable: A, property: 'b', to: [ [ B, 'y' ] ] },\n\t//\t\t\t\t\t] )\n\t//\t\t\t\t}\n\t//\t\t\t} )\n\t//\n\t//\t\tA.bind( 'd' ).to( B, 'z' ).to( C, 'w' ).as( callback );\n\t//\t\tconsole.log( A._boundObservables );\n\t//\n\t//\t\t\tMap( {\n\t//\t\t\t\tB: {\n\t//\t\t\t\t\tx: Set( [\n\t//\t\t\t\t\t\t{ observable: A, property: 'a', to: [ [ B, 'x' ] ] },\n\t//\t\t\t\t\t\t{ observable: A, property: 'c', to: [ [ B, 'x' ] ] }\n\t//\t\t\t\t\t] ),\n\t//\t\t\t\t\ty: Set( [\n\t//\t\t\t\t\t\t{ observable: A, property: 'b', to: [ [ B, 'y' ] ] },\n\t//\t\t\t\t\t] ),\n\t//\t\t\t\t\tz: Set( [\n\t//\t\t\t\t\t\t{ observable: A, property: 'd', to: [ [ B, 'z' ], [ C, 'w' ] ], callback: callback }\n\t//\t\t\t\t\t] )\n\t//\t\t\t\t},\n\t//\t\t\t\tC: {\n\t//\t\t\t\t\tw: Set( [\n\t//\t\t\t\t\t\t{ observable: A, property: 'd', to: [ [ B, 'z' ], [ C, 'w' ] ], callback: callback }\n\t//\t\t\t\t\t] )\n\t//\t\t\t\t}\n\t//\t\t\t} )\n\t//\n\t// @private\n\t// @type {Map}\n\tObject.defineProperty( observable, boundObservablesSymbol, {\n\t\tvalue: new Map()\n\t} );\n\n\t// Object that stores which properties of this observable are bound and how. It shares\n\t// the binding objects (`{ observable: A, property: 'a', to: ... }`) with\n\t// {@link module:utils/observablemixin~ObservableMixin#_boundObservables}. This data structure is\n\t// a reverse of {@link module:utils/observablemixin~ObservableMixin#_boundObservables} and it is helpful for\n\t// {@link module:utils/observablemixin~ObservableMixin#unbind}.\n\t//\n\t// See {@link module:utils/observablemixin~ObservableMixin#bind}.\n\t//\n\t//\t\tA.bind( 'a', 'b', 'c' ).to( B, 'x', 'y', 'x' );\n\t//\t\tconsole.log( A._boundProperties );\n\t//\n\t//\t\t\tMap( {\n\t//\t\t\t\ta: { observable: A, property: 'a', to: [ [ B, 'x' ] ] },\n\t//\t\t\t\tb: { observable: A, property: 'b', to: [ [ B, 'y' ] ] },\n\t//\t\t\t\tc: { observable: A, property: 'c', to: [ [ B, 'x' ] ] }\n\t//\t\t\t} )\n\t//\n\t//\t\tA.bind( 'd' ).to( B, 'z' ).to( C, 'w' ).as( callback );\n\t//\t\tconsole.log( A._boundProperties );\n\t//\n\t//\t\t\tMap( {\n\t//\t\t\t\ta: { observable: A, property: 'a', to: [ [ B, 'x' ] ] },\n\t//\t\t\t\tb: { observable: A, property: 'b', to: [ [ B, 'y' ] ] },\n\t//\t\t\t\tc: { observable: A, property: 'c', to: [ [ B, 'x' ] ] },\n\t//\t\t\t\td: { observable: A, property: 'd', to: [ [ B, 'z' ], [ C, 'w' ] ], callback: callback }\n\t//\t\t\t} )\n\t//\n\t// @private\n\t// @type {Map}\n\tObject.defineProperty( observable, boundPropertiesSymbol, {\n\t\tvalue: new Map()\n\t} );\n}\n\n// A chaining for {@link module:utils/observablemixin~ObservableMixin#bind} providing `.to()` interface.\n//\n// @private\n// @param {...[Observable|String|Function]} args Arguments of the `.to( args )` binding.\nfunction bindTo( ...args ) {\n\tconst parsedArgs = parseBindToArgs( ...args );\n\tconst bindingsKeys = Array.from( this._bindings.keys() );\n\tconst numberOfBindings = bindingsKeys.length;\n\n\t// Eliminate A.bind( 'x' ).to( B, C )\n\tif ( !parsedArgs.callback && parsedArgs.to.length > 1 ) {\n\t\t/**\n\t\t * Binding multiple observables only possible with callback.\n\t\t *\n\t\t * @error observable-bind-to-no-callback\n\t\t */\n\t\tthrow new CKEditorError( 'observable-bind-to-no-callback', this );\n\t}\n\n\t// Eliminate A.bind( 'x', 'y' ).to( B, callback )\n\tif ( numberOfBindings > 1 && parsedArgs.callback ) {\n\t\t/**\n\t\t * Cannot bind multiple properties and use a callback in one binding.\n\t\t *\n\t\t * @error observable-bind-to-extra-callback\n\t\t */\n\t\tthrow new CKEditorError(\n\t\t\t'observable-bind-to-extra-callback',\n\t\t\tthis\n\t\t);\n\t}\n\n\tparsedArgs.to.forEach( to => {\n\t\t// Eliminate A.bind( 'x', 'y' ).to( B, 'a' )\n\t\tif ( to.properties.length && to.properties.length !== numberOfBindings ) {\n\t\t\t/**\n\t\t\t * The number of properties must match.\n\t\t\t *\n\t\t\t * @error observable-bind-to-properties-length\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'observable-bind-to-properties-length', this );\n\t\t}\n\n\t\t// When no to.properties specified, observing source properties instead i.e.\n\t\t// A.bind( 'x', 'y' ).to( B ) -> Observe B.x and B.y\n\t\tif ( !to.properties.length ) {\n\t\t\tto.properties = this._bindProperties;\n\t\t}\n\t} );\n\n\tthis._to = parsedArgs.to;\n\n\t// Fill {@link BindChain#_bindings} with callback. When the callback is set there's only one binding.\n\tif ( parsedArgs.callback ) {\n\t\tthis._bindings.get( bindingsKeys[ 0 ] ).callback = parsedArgs.callback;\n\t}\n\n\tattachBindToListeners( this._observable, this._to );\n\n\t// Update observable._boundProperties and observable._boundObservables.\n\tupdateBindToBound( this );\n\n\t// Set initial values of bound properties.\n\tthis._bindProperties.forEach( propertyName => {\n\t\tupdateBoundObservableProperty( this._observable, propertyName );\n\t} );\n}\n\n// Binds to an attribute in a set of iterable observables.\n//\n// @private\n// @param {Array.<Observable>} observables\n// @param {String} attribute\n// @param {Function} callback\nfunction bindToMany( observables, attribute, callback ) {\n\tif ( this._bindings.size > 1 ) {\n\t\t/**\n\t\t * Binding one attribute to many observables only possible with one attribute.\n\t\t *\n\t\t * @error observable-bind-to-many-not-one-binding\n\t\t */\n\t\tthrow new CKEditorError( 'observable-bind-to-many-not-one-binding', this );\n\t}\n\n\tthis.to(\n\t\t// Bind to #attribute of each observable...\n\t\t...getBindingTargets( observables, attribute ),\n\t\t// ...using given callback to parse attribute values.\n\t\tcallback\n\t);\n}\n\n// Returns an array of binding components for\n// {@link Observable#bind} from a set of iterable observables.\n//\n// @param {Array.<Observable>} observables\n// @param {String} attribute\n// @returns {Array.<String|Observable>}\nfunction getBindingTargets( observables, attribute ) {\n\tconst observableAndAttributePairs = observables.map( observable => [ observable, attribute ] );\n\n\t// Merge pairs to one-dimension array of observables and attributes.\n\treturn Array.prototype.concat.apply( [], observableAndAttributePairs );\n}\n\n// Check if all entries of the array are of `String` type.\n//\n// @private\n// @param {Array} arr An array to be checked.\n// @returns {Boolean}\nfunction isStringArray( arr ) {\n\treturn arr.every( a => typeof a == 'string' );\n}\n\n// Parses and validates {@link Observable#bind}`.to( args )` arguments and returns\n// an object with a parsed structure. For example\n//\n//\t\tA.bind( 'x' ).to( B, 'a', C, 'b', call );\n//\n// becomes\n//\n//\t\t{\n//\t\t\tto: [\n//\t\t\t\t{ observable: B, properties: [ 'a' ] },\n//\t\t\t\t{ observable: C, properties: [ 'b' ] },\n//\t\t\t],\n//\t\t\tcallback: call\n// \t\t}\n//\n// @private\n// @param {...*} args Arguments of {@link Observable#bind}`.to( args )`.\n// @returns {Object}\nfunction parseBindToArgs( ...args ) {\n\t// Eliminate A.bind( 'x' ).to()\n\tif ( !args.length ) {\n\t\t/**\n\t\t * Invalid argument syntax in `to()`.\n\t\t *\n\t\t * @error observable-bind-to-parse-error\n\t\t */\n\t\tthrow new CKEditorError( 'observable-bind-to-parse-error', null );\n\t}\n\n\tconst parsed = { to: [] };\n\tlet lastObservable;\n\n\tif ( typeof args[ args.length - 1 ] == 'function' ) {\n\t\tparsed.callback = args.pop();\n\t}\n\n\targs.forEach( a => {\n\t\tif ( typeof a == 'string' ) {\n\t\t\tlastObservable.properties.push( a );\n\t\t} else if ( typeof a == 'object' ) {\n\t\t\tlastObservable = { observable: a, properties: [] };\n\t\t\tparsed.to.push( lastObservable );\n\t\t} else {\n\t\t\tthrow new CKEditorError( 'observable-bind-to-parse-error', null );\n\t\t}\n\t} );\n\n\treturn parsed;\n}\n\n// Synchronizes {@link module:utils/observablemixin#_boundObservables} with {@link Binding}.\n//\n// @private\n// @param {Binding} binding A binding to store in {@link Observable#_boundObservables}.\n// @param {Observable} toObservable A observable, which is a new component of `binding`.\n// @param {String} toPropertyName A name of `toObservable`'s property, a new component of the `binding`.\nfunction updateBoundObservables( observable, binding, toObservable, toPropertyName ) {\n\tconst boundObservables = observable[ boundObservablesSymbol ];\n\tconst bindingsToObservable = boundObservables.get( toObservable );\n\tconst bindings = bindingsToObservable || {};\n\n\tif ( !bindings[ toPropertyName ] ) {\n\t\tbindings[ toPropertyName ] = new Set();\n\t}\n\n\t// Pass the binding to a corresponding Set in `observable._boundObservables`.\n\tbindings[ toPropertyName ].add( binding );\n\n\tif ( !bindingsToObservable ) {\n\t\tboundObservables.set( toObservable, bindings );\n\t}\n}\n\n// Synchronizes {@link Observable#_boundProperties} and {@link Observable#_boundObservables}\n// with {@link BindChain}.\n//\n// Assuming the following binding being created\n//\n// \t\tA.bind( 'a', 'b' ).to( B, 'x', 'y' );\n//\n// the following bindings were initialized by {@link Observable#bind} in {@link BindChain#_bindings}:\n//\n// \t\t{\n// \t\t\ta: { observable: A, property: 'a', to: [] },\n// \t\t\tb: { observable: A, property: 'b', to: [] },\n// \t\t}\n//\n// Iterate over all bindings in this chain and fill their `to` properties with\n// corresponding to( ... ) arguments (components of the binding), so\n//\n// \t\t{\n// \t\t\ta: { observable: A, property: 'a', to: [ B, 'x' ] },\n// \t\t\tb: { observable: A, property: 'b', to: [ B, 'y' ] },\n// \t\t}\n//\n// Then update the structure of {@link Observable#_boundObservables} with updated\n// binding, so it becomes:\n//\n// \t\tMap( {\n// \t\t\tB: {\n// \t\t\t\tx: Set( [\n// \t\t\t\t\t{ observable: A, property: 'a', to: [ [ B, 'x' ] ] }\n// \t\t\t\t] ),\n// \t\t\t\ty: Set( [\n// \t\t\t\t\t{ observable: A, property: 'b', to: [ [ B, 'y' ] ] },\n// \t\t\t\t] )\n//\t\t\t}\n// \t\t} )\n//\n// @private\n// @param {BindChain} chain The binding initialized by {@link Observable#bind}.\nfunction updateBindToBound( chain ) {\n\tlet toProperty;\n\n\tchain._bindings.forEach( ( binding, propertyName ) => {\n\t\t// Note: For a binding without a callback, this will run only once\n\t\t// like in A.bind( 'x', 'y' ).to( B, 'a', 'b' )\n\t\t// TODO: ES6 destructuring.\n\t\tchain._to.forEach( to => {\n\t\t\ttoProperty = to.properties[ binding.callback ? 0 : chain._bindProperties.indexOf( propertyName ) ];\n\n\t\t\tbinding.to.push( [ to.observable, toProperty ] );\n\t\t\tupdateBoundObservables( chain._observable, binding, to.observable, toProperty );\n\t\t} );\n\t} );\n}\n\n// Updates an property of a {@link Observable} with a value\n// determined by an entry in {@link Observable#_boundProperties}.\n//\n// @private\n// @param {Observable} observable A observable which property is to be updated.\n// @param {String} propertyName An property to be updated.\nfunction updateBoundObservableProperty( observable, propertyName ) {\n\tconst boundProperties = observable[ boundPropertiesSymbol ];\n\tconst binding = boundProperties.get( propertyName );\n\tlet propertyValue;\n\n\t// When a binding with callback is created like\n\t//\n\t// \t\tA.bind( 'a' ).to( B, 'b', C, 'c', callback );\n\t//\n\t// collect B.b and C.c, then pass them to callback to set A.a.\n\tif ( binding.callback ) {\n\t\tpropertyValue = binding.callback.apply( observable, binding.to.map( to => to[ 0 ][ to[ 1 ] ] ) );\n\t} else {\n\t\tpropertyValue = binding.to[ 0 ];\n\t\tpropertyValue = propertyValue[ 0 ][ propertyValue[ 1 ] ];\n\t}\n\n\tif ( Object.prototype.hasOwnProperty.call( observable, propertyName ) ) {\n\t\tobservable[ propertyName ] = propertyValue;\n\t} else {\n\t\tobservable.set( propertyName, propertyValue );\n\t}\n}\n\n// Starts listening to changes in {@link BindChain._to} observables to update\n// {@link BindChain._observable} {@link BindChain._bindProperties}. Also sets the\n// initial state of {@link BindChain._observable}.\n//\n// @private\n// @param {BindChain} chain The chain initialized by {@link Observable#bind}.\nfunction attachBindToListeners( observable, toBindings ) {\n\ttoBindings.forEach( to => {\n\t\tconst boundObservables = observable[ boundObservablesSymbol ];\n\t\tlet bindings;\n\n\t\t// If there's already a chain between the observables (`observable` listens to\n\t\t// `to.observable`), there's no need to create another `change` event listener.\n\t\tif ( !boundObservables.get( to.observable ) ) {\n\t\t\tobservable.listenTo( to.observable, 'change', ( evt, propertyName ) => {\n\t\t\t\tbindings = boundObservables.get( to.observable )[ propertyName ];\n\n\t\t\t\t// Note: to.observable will fire for any property change, react\n\t\t\t\t// to changes of properties which are bound only.\n\t\t\t\tif ( bindings ) {\n\t\t\t\t\tbindings.forEach( binding => {\n\t\t\t\t\t\tupdateBoundObservableProperty( observable, binding.property );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t} );\n}\n\n/**\n * An interface which adds \"observable properties\" and data binding functionality.\n *\n * Can be easily implemented by a class by mixing the {@link module:utils/observablemixin~ObservableMixin} mixin.\n *\n * Read more about the usage of this interface in the:\n * * {@glink framework/guides/architecture/core-editor-architecture#event-system-and-observables \"Event system and observables\"}\n * section of the {@glink framework/guides/architecture/core-editor-architecture \"Core editor architecture\"} guide,\n * * {@glink framework/guides/deep-dive/observables \"Observables\" deep dive} guide.\n *\n * @interface Observable\n * @extends module:utils/emittermixin~Emitter\n */\n\n/**\n * Fired when a property changed value.\n *\n *\t\tobservable.set( 'prop', 1 );\n *\n *\t\tobservable.on( 'change:prop', ( evt, propertyName, newValue, oldValue ) => {\n *\t\t\tconsole.log( `${ propertyName } has changed from ${ oldValue } to ${ newValue }` );\n *\t\t} );\n *\n *\t\tobservable.prop = 2; // -> 'prop has changed from 1 to 2'\n *\n * @event change:{property}\n * @param {String} name The property name.\n * @param {*} value The new property value.\n * @param {*} oldValue The previous property value.\n */\n\n/**\n * Fired when a property value is going to be set but is not set yet (before the `change` event is fired).\n *\n * You can control the final value of the property by using\n * the {@link module:utils/eventinfo~EventInfo#return event's `return` property}.\n *\n *\t\tobservable.set( 'prop', 1 );\n *\n *\t\tobservable.on( 'set:prop', ( evt, propertyName, newValue, oldValue ) => {\n *\t\t\tconsole.log( `Value is going to be changed from ${ oldValue } to ${ newValue }` );\n *\t\t\tconsole.log( `Current property value is ${ observable[ propertyName ] }` );\n *\n *\t\t\t// Let's override the value.\n *\t\t\tevt.return = 3;\n *\t\t} );\n *\n *\t\tobservable.on( 'change:prop', ( evt, propertyName, newValue, oldValue ) => {\n *\t\t\tconsole.log( `Value has changed from ${ oldValue } to ${ newValue }` );\n *\t\t} );\n *\n *\t\tobservable.prop = 2; // -> 'Value is going to be changed from 1 to 2'\n *\t\t                     // -> 'Current property value is 1'\n *\t\t                     // -> 'Value has changed from 1 to 3'\n *\n * **Note:** The event is fired even when the new value is the same as the old value.\n *\n * @event set:{property}\n * @param {String} name The property name.\n * @param {*} value The new property value.\n * @param {*} oldValue The previous property value.\n */\n\n/**\n * Creates and sets the value of an observable property of this object. Such a property becomes a part\n * of the state and is observable.\n *\n * It accepts also a single object literal containing key/value pairs with properties to be set.\n *\n * This method throws the `observable-set-cannot-override` error if the observable instance already\n * has a property with the given property name. This prevents from mistakenly overriding existing\n * properties and methods, but means that `foo.set( 'bar', 1 )` may be slightly slower than `foo.bar = 1`.\n *\n * @method #set\n * @param {String|Object} name The property's name or object with `name=>value` pairs.\n * @param {*} [value] The property's value (if `name` was passed in the first parameter).\n */\n\n/**\n * Binds {@link #set observable properties} to other objects implementing the\n * {@link module:utils/observablemixin~Observable} interface.\n *\n * Read more in the {@glink framework/guides/deep-dive/observables#property-bindings dedicated guide}\n * covering the topic of property bindings with some additional examples.\n *\n * Consider two objects: a `button` and an associated `command` (both `Observable`).\n *\n * A simple property binding could be as follows:\n *\n *\t\tbutton.bind( 'isEnabled' ).to( command, 'isEnabled' );\n *\n * or even shorter:\n *\n *\t\tbutton.bind( 'isEnabled' ).to( command );\n *\n * which works in the following way:\n *\n * * `button.isEnabled` **instantly equals** `command.isEnabled`,\n * * whenever `command.isEnabled` changes, `button.isEnabled` will immediately reflect its value.\n *\n * **Note**: To release the binding, use {@link module:utils/observablemixin~Observable#unbind}.\n *\n * You can also \"rename\" the property in the binding by specifying the new name in the `to()` chain:\n *\n *\t\tbutton.bind( 'isEnabled' ).to( command, 'isWorking' );\n *\n * It is possible to bind more than one property at a time to shorten the code:\n *\n *\t\tbutton.bind( 'isEnabled', 'value' ).to( command );\n *\n * which corresponds to:\n *\n *\t\tbutton.bind( 'isEnabled' ).to( command );\n *\t\tbutton.bind( 'value' ).to( command );\n *\n * The binding can include more than one observable, combining multiple data sources in a custom callback:\n *\n *\t\tbutton.bind( 'isEnabled' ).to( command, 'isEnabled', ui, 'isVisible',\n *\t\t\t( isCommandEnabled, isUIVisible ) => isCommandEnabled && isUIVisible );\n *\n * Using a custom callback allows processing the value before passing it to the target property:\n *\n *\t\tbutton.bind( 'isEnabled' ).to( command, 'value', value => value === 'heading1' );\n *\n * It is also possible to bind to the same property in an array of observables.\n * To bind a `button` to multiple commands (also `Observables`) so that each and every one of them\n * must be enabled for the button to become enabled, use the following code:\n *\n *\t\tbutton.bind( 'isEnabled' ).toMany( [ commandA, commandB, commandC ], 'isEnabled',\n *\t\t\t( isAEnabled, isBEnabled, isCEnabled ) => isAEnabled && isBEnabled && isCEnabled );\n *\n * @method #bind\n * @param {...String} bindProperties Observable properties that will be bound to other observable(s).\n * @returns {Object} The bind chain with the `to()` and `toMany()` methods.\n */\n\n/**\n * Removes the binding created with {@link #bind}.\n *\n *\t\t// Removes the binding for the 'a' property.\n *\t\tA.unbind( 'a' );\n *\n *\t\t// Removes bindings for all properties.\n *\t\tA.unbind();\n *\n * @method #unbind\n * @param {...String} [unbindProperties] Observable properties to be unbound. All the bindings will\n * be released if no properties are provided.\n */\n\n/**\n * Turns the given methods of this object into event-based ones. This means that the new method will fire an event\n * (named after the method) and the original action will be plugged as a listener to that event.\n *\n * Read more in the {@glink framework/guides/deep-dive/observables#decorating-object-methods dedicated guide}\n * covering the topic of decorating methods with some additional examples.\n *\n * Decorating the method does not change its behavior (it only adds an event),\n * but it allows to modify it later on by listening to the method's event.\n *\n * For example, to cancel the method execution the event can be {@link module:utils/eventinfo~EventInfo#stop stopped}:\n *\n *\t\tclass Foo {\n *\t\t\tconstructor() {\n *\t\t\t\tthis.decorate( 'method' );\n *\t\t\t}\n *\n *\t\t\tmethod() {\n *\t\t\t\tconsole.log( 'called!' );\n *\t\t\t}\n *\t\t}\n *\n *\t\tconst foo = new Foo();\n *\t\tfoo.on( 'method', ( evt ) => {\n *\t\t\tevt.stop();\n *\t\t}, { priority: 'high' } );\n *\n *\t\tfoo.method(); // Nothing is logged.\n *\n *\n * **Note**: The high {@link module:utils/priorities~PriorityString priority} listener\n * has been used to execute this particular callback before the one which calls the original method\n * (which uses the \"normal\" priority).\n *\n * It is also possible to change the returned value:\n *\n *\t\tfoo.on( 'method', ( evt ) => {\n *\t\t\tevt.return = 'Foo!';\n *\t\t} );\n *\n *\t\tfoo.method(); // -> 'Foo'\n *\n * Finally, it is possible to access and modify the arguments the method is called with:\n *\n *\t\tmethod( a, b ) {\n *\t\t\tconsole.log( `${ a }, ${ b }`  );\n *\t\t}\n *\n *\t\t// ...\n *\n *\t\tfoo.on( 'method', ( evt, args ) => {\n *\t\t\targs[ 0 ] = 3;\n *\n *\t\t\tconsole.log( args[ 1 ] ); // -> 2\n *\t\t}, { priority: 'high' } );\n *\n *\t\tfoo.method( 1, 2 ); // -> '3, 2'\n *\n * @method #decorate\n * @param {String} methodName Name of the method to decorate.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/editableelement\n */\n\nimport ContainerElement from './containerelement';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\n\n/**\n * Editable element which can be a {@link module:engine/view/rooteditableelement~RootEditableElement root}\n * or nested editable area in the editor.\n *\n * Editable is automatically read-only when its {@link module:engine/view/document~Document Document} is read-only.\n *\n * The constructor of this class shouldn't be used directly. To create new `EditableElement` use the\n * {@link module:engine/view/downcastwriter~DowncastWriter#createEditableElement `downcastWriter#createEditableElement()`} method.\n *\n * @extends module:engine/view/containerelement~ContainerElement\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class EditableElement extends ContainerElement {\n\t/**\n\t * Creates an editable element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#createEditableElement\n\t * @protected\n\t */\n\tconstructor( document, name, attrs, children ) {\n\t\tsuper( document, name, attrs, children );\n\n\t\t/**\n\t\t * Whether the editable is in read-write or read-only mode.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} module:engine/view/editableelement~EditableElement#isReadOnly\n\t\t */\n\t\tthis.set( 'isReadOnly', false );\n\n\t\t/**\n\t\t * Whether the editable is focused.\n\t\t *\n\t\t * This property updates when {@link module:engine/view/document~Document#isFocused document.isFocused} or view\n\t\t * selection is changed.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} module:engine/view/editableelement~EditableElement#isFocused\n\t\t */\n\t\tthis.set( 'isFocused', false );\n\n\t\tthis.bind( 'isReadOnly' ).to( document );\n\n\t\tthis.bind( 'isFocused' ).to(\n\t\t\tdocument,\n\t\t\t'isFocused',\n\t\t\tisFocused => isFocused && document.selection.editableElement == this\n\t\t);\n\n\t\t// Update focus state based on selection changes.\n\t\tthis.listenTo( document.selection, 'change', () => {\n\t\t\tthis.isFocused = document.isFocused && document.selection.editableElement == this;\n\t\t} );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\teditableElement.is( 'editableElement' ); // -> true\n\t *\t\teditableElement.is( 'element' ); // -> true\n\t *\t\teditableElement.is( 'node' ); // -> true\n\t *\t\teditableElement.is( 'view:editableElement' ); // -> true\n\t *\t\teditableElement.is( 'view:element' ); // -> true\n\t *\t\teditableElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\teditableElement.is( 'model:element' ); // -> false\n\t *\t\teditableElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is an editbale element, you can also check its\n\t * {@link module:engine/view/editableelement~EditableElement#name name}:\n\t *\n\t *\t\teditableElement.is( 'element', 'div' ); // -> true if this is a div element\n\t *\t\teditableElement.is( 'editableElement', 'div' ); // -> same as above\n\t *\t\ttext.is( 'element', 'div' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'editableElement' || type === 'view:editableElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'containerElement' || type === 'view:containerElement' ||\n\t\t\t\ttype === 'element' || type === 'view:element' ||\n\t\t\t\ttype === 'node' || type === 'view:node';\n\t\t} else {\n\t\t\treturn name === this.name && (\n\t\t\t\ttype === 'editableElement' || type === 'view:editableElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'containerElement' || type === 'view:containerElement' ||\n\t\t\t\ttype === 'element' || type === 'view:element'\n\t\t\t);\n\t\t}\n\t}\n\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n}\n\nmix( EditableElement, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/rooteditableelement\n */\n\nimport EditableElement from './editableelement';\n\nconst rootNameSymbol = Symbol( 'rootName' );\n\n/**\n * Class representing a single root in the data view. A root can be either {@link ~RootEditableElement#isReadOnly editable or read-only},\n * but in both cases it is called \"an editable\". Roots can contain other {@link module:engine/view/editableelement~EditableElement\n * editable elements} making them \"nested editables\".\n *\n * @extends module:engine/view/editableelement~EditableElement\n */\nexport default class RootEditableElement extends EditableElement {\n\t/**\n\t * Creates root editable element.\n\t *\n\t * @param {module:engine/view/document~Document} document The document instance to which this element belongs.\n\t * @param {String} name Node name.\n\t */\n\tconstructor( document, name ) {\n\t\tsuper( document, name );\n\n\t\t/**\n\t\t * Name of this root inside {@link module:engine/view/document~Document} that is an owner of this root. If no\n\t\t * other name is set, `main` name is used.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.rootName = 'main';\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\trootEditableElement.is( 'rootElement' ); // -> true\n\t *\t\trootEditableElement.is( 'editableElement' ); // -> true\n\t *\t\trootEditableElement.is( 'element' ); // -> true\n\t *\t\trootEditableElement.is( 'node' ); // -> true\n\t *\t\trootEditableElement.is( 'view:editableElement' ); // -> true\n\t *\t\trootEditableElement.is( 'view:element' ); // -> true\n\t *\t\trootEditableElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\trootEditableElement.is( 'model:element' ); // -> false\n\t *\t\trootEditableElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is a root editable element, you can also check its\n\t * {@link module:engine/view/rooteditableelement~RootEditableElement#name name}:\n\t *\n\t *\t\trootEditableElement.is( 'element', 'div' ); // -> true if this is a div root editable element\n\t *\t\trootEditableElement.is( 'rootElement', 'div' ); // -> same as above\n\t *\t\ttext.is( 'element', 'div' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'rootElement' || type === 'view:rootElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'editableElement' || type === 'view:editableElement' ||\n\t\t\t\ttype === 'containerElement' || type === 'view:containerElement' ||\n\t\t\t\ttype === 'element' || type === 'view:element' ||\n\t\t\t\ttype === 'node' || type === 'view:node';\n\t\t} else {\n\t\t\treturn name === this.name && (\n\t\t\t\ttype === 'rootElement' || type === 'view:rootElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'editableElement' || type === 'view:editableElement' ||\n\t\t\t\ttype === 'containerElement' || type === 'view:containerElement' ||\n\t\t\t\ttype === 'element' || type === 'view:element'\n\t\t\t);\n\t\t}\n\t}\n\n\tget rootName() {\n\t\treturn this.getCustomProperty( rootNameSymbol );\n\t}\n\n\tset rootName( rootName ) {\n\t\tthis._setCustomProperty( rootNameSymbol, rootName );\n\t}\n\n\t/**\n\t * Overrides old element name and sets new one.\n\t * This is needed because view roots are created before they are attached to the DOM.\n\t * The name of the root element is temporary at this stage. It has to be changed when the\n\t * view root element is attached to the DOM element.\n\t *\n\t * @protected\n\t * @param {String} name The new name of element.\n\t */\n\tset _name( name ) {\n\t\tthis.name = name;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/treewalker\n */\n\nimport Element from './element';\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport Position from './position';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Position iterator class. It allows to iterate forward and backward over the document.\n */\nexport default class TreeWalker {\n\t/**\n\t * Creates a range iterator. All parameters are optional, but you have to specify either `boundaries` or `startPosition`.\n\t *\n\t * @constructor\n\t * @param {Object} options Object with configuration.\n\t * @param {module:engine/view/range~Range} [options.boundaries=null] Range to define boundaries of the iterator.\n\t * @param {module:engine/view/position~Position} [options.startPosition] Starting position.\n\t * @param {'forward'|'backward'} [options.direction='forward'] Walking direction.\n\t * @param {Boolean} [options.singleCharacters=false] Flag indicating whether all characters from\n\t * {@link module:engine/view/text~Text} should be returned as one {@link module:engine/view/text~Text} (`false`) ore one by one as\n\t * {@link module:engine/view/textproxy~TextProxy} (`true`).\n\t * @param {Boolean} [options.shallow=false] Flag indicating whether iterator should enter elements or not. If the\n\t * iterator is shallow child nodes of any iterated node will not be returned along with `elementEnd` tag.\n\t * @param {Boolean} [options.ignoreElementEnd=false] Flag indicating whether iterator should ignore `elementEnd`\n\t * tags. If the option is true walker will not return a parent node of start position. If this option is `true`\n\t * each {@link module:engine/view/element~Element} will be returned once, while if the option is `false` they might be returned\n\t * twice: for `'elementStart'` and `'elementEnd'`.\n\t */\n\tconstructor( options = {} ) {\n\t\tif ( !options.boundaries && !options.startPosition ) {\n\t\t\t/**\n\t\t\t * Neither boundaries nor starting position have been defined.\n\t\t\t *\n\t\t\t * @error view-tree-walker-no-start-position\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-tree-walker-no-start-position',\n\t\t\t\tnull\n\t\t\t);\n\t\t}\n\n\t\tif ( options.direction && options.direction != 'forward' && options.direction != 'backward' ) {\n\t\t\t/**\n\t\t\t * Only `backward` and `forward` direction allowed.\n\t\t\t *\n\t\t\t * @error view-tree-walker-unknown-direction\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-tree-walker-unknown-direction', options.startPosition, { direction: options.direction } );\n\t\t}\n\n\t\t/**\n\t\t * Iterator boundaries.\n\t\t *\n\t\t * When the iterator is walking `'forward'` on the end of boundary or is walking `'backward'`\n\t\t * on the start of boundary, then `{ done: true }` is returned.\n\t\t *\n\t\t * If boundaries are not defined they are set before first and after last child of the root node.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/range~Range} module:engine/view/treewalker~TreeWalker#boundaries\n\t\t */\n\t\tthis.boundaries = options.boundaries || null;\n\n\t\t/**\n\t\t * Iterator position. If start position is not defined then position depends on {@link #direction}. If direction is\n\t\t * `'forward'` position starts form the beginning, when direction is `'backward'` position starts from the end.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/position~Position} module:engine/view/treewalker~TreeWalker#position\n\t\t */\n\t\tif ( options.startPosition ) {\n\t\t\tthis.position = Position._createAt( options.startPosition );\n\t\t} else {\n\t\t\tthis.position = Position._createAt( options.boundaries[ options.direction == 'backward' ? 'end' : 'start' ] );\n\t\t}\n\n\t\t/**\n\t\t * Walking direction. Defaults `'forward'`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {'backward'|'forward'} module:engine/view/treewalker~TreeWalker#direction\n\t\t */\n\t\tthis.direction = options.direction || 'forward';\n\n\t\t/**\n\t\t * Flag indicating whether all characters from {@link module:engine/view/text~Text} should be returned as one\n\t\t * {@link module:engine/view/text~Text} or one by one as {@link module:engine/view/textproxy~TextProxy}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/view/treewalker~TreeWalker#singleCharacters\n\t\t */\n\t\tthis.singleCharacters = !!options.singleCharacters;\n\n\t\t/**\n\t\t * Flag indicating whether iterator should enter elements or not. If the iterator is shallow child nodes of any\n\t\t * iterated node will not be returned along with `elementEnd` tag.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/view/treewalker~TreeWalker#shallow\n\t\t */\n\t\tthis.shallow = !!options.shallow;\n\n\t\t/**\n\t\t * Flag indicating whether iterator should ignore `elementEnd` tags. If set to `true`, walker will not\n\t\t * return a parent node of the start position. Each {@link module:engine/view/element~Element} will be returned once.\n\t\t * When set to `false` each element might be returned twice: for `'elementStart'` and `'elementEnd'`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/view/treewalker~TreeWalker#ignoreElementEnd\n\t\t */\n\t\tthis.ignoreElementEnd = !!options.ignoreElementEnd;\n\n\t\t/**\n\t\t * Start boundary parent.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/view/node~Node} module:engine/view/treewalker~TreeWalker#_boundaryStartParent\n\t\t */\n\t\tthis._boundaryStartParent = this.boundaries ? this.boundaries.start.parent : null;\n\n\t\t/**\n\t\t * End boundary parent.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/view/node~Node} module:engine/view/treewalker~TreeWalker#_boundaryEndParent\n\t\t */\n\t\tthis._boundaryEndParent = this.boundaries ? this.boundaries.end.parent : null;\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * @returns {Iterable.<module:engine/view/treewalker~TreeWalkerValue>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Moves {@link #position} in the {@link #direction} skipping values as long as the callback function returns `true`.\n\t *\n\t * For example:\n\t *\n\t * \t\twalker.skip( value => value.type == 'text' ); // <p>{}foo</p> -> <p>foo[]</p>\n\t * \t\twalker.skip( value => true ); // Move the position to the end: <p>{}foo</p> -> <p>foo</p>[]\n\t * \t\twalker.skip( value => false ); // Do not move the position.\n\t *\n\t * @param {Function} skip Callback function. Gets {@link module:engine/view/treewalker~TreeWalkerValue} and should\n\t * return `true` if the value should be skipped or `false` if not.\n\t */\n\tskip( skip ) {\n\t\tlet done, value, prevPosition;\n\n\t\tdo {\n\t\t\tprevPosition = this.position;\n\n\t\t\t( { done, value } = this.next() );\n\t\t} while ( !done && skip( value ) );\n\n\t\tif ( !done ) {\n\t\t\tthis.position = prevPosition;\n\t\t}\n\t}\n\n\t/**\n\t * Gets the next tree walker's value.\n\t *\n\t * @returns {module:engine/view/treewalker~TreeWalkerValue} Object implementing iterator interface, returning\n\t * information about taken step.\n\t */\n\tnext() {\n\t\tif ( this.direction == 'forward' ) {\n\t\t\treturn this._next();\n\t\t} else {\n\t\t\treturn this._previous();\n\t\t}\n\t}\n\n\t/**\n\t * Makes a step forward in view. Moves the {@link #position} to the next position and returns the encountered value.\n\t *\n\t * @private\n\t * @returns {Object}\n\t * @returns {Boolean} return.done `true` if iterator is done, `false` otherwise.\n\t * @returns {module:engine/view/treewalker~TreeWalkerValue} return.value Information about taken step.\n\t */\n\t_next() {\n\t\tlet position = this.position.clone();\n\t\tconst previousPosition = this.position;\n\t\tconst parent = position.parent;\n\n\t\t// We are at the end of the root.\n\t\tif ( parent.parent === null && position.offset === parent.childCount ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// We reached the walker boundary.\n\t\tif ( parent === this._boundaryEndParent && position.offset == this.boundaries.end.offset ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// Get node just after current position.\n\t\tlet node;\n\n\t\t// Text is a specific parent because it contains string instead of child nodes.\n\t\tif ( parent instanceof Text ) {\n\t\t\tif ( position.isAtEnd ) {\n\t\t\t\t// Prevent returning \"elementEnd\" for Text node. Skip that value and return the next walker step.\n\t\t\t\tthis.position = Position._createAfter( parent );\n\n\t\t\t\treturn this._next();\n\t\t\t}\n\n\t\t\tnode = parent.data[ position.offset ];\n\t\t} else {\n\t\t\tnode = parent.getChild( position.offset );\n\t\t}\n\n\t\tif ( node instanceof Element ) {\n\t\t\tif ( !this.shallow ) {\n\t\t\t\tposition = new Position( node, 0 );\n\t\t\t} else {\n\t\t\t\tposition.offset++;\n\t\t\t}\n\n\t\t\tthis.position = position;\n\n\t\t\treturn this._formatReturnValue( 'elementStart', node, previousPosition, position, 1 );\n\t\t} else if ( node instanceof Text ) {\n\t\t\tif ( this.singleCharacters ) {\n\t\t\t\tposition = new Position( node, 0 );\n\t\t\t\tthis.position = position;\n\n\t\t\t\treturn this._next();\n\t\t\t} else {\n\t\t\t\tlet charactersCount = node.data.length;\n\t\t\t\tlet item;\n\n\t\t\t\t// If text stick out of walker range, we need to cut it and wrap in TextProxy.\n\t\t\t\tif ( node == this._boundaryEndParent ) {\n\t\t\t\t\tcharactersCount = this.boundaries.end.offset;\n\t\t\t\t\titem = new TextProxy( node, 0, charactersCount );\n\t\t\t\t\tposition = Position._createAfter( item );\n\t\t\t\t} else {\n\t\t\t\t\titem = new TextProxy( node, 0, node.data.length );\n\t\t\t\t\t// If not just keep moving forward.\n\t\t\t\t\tposition.offset++;\n\t\t\t\t}\n\n\t\t\t\tthis.position = position;\n\n\t\t\t\treturn this._formatReturnValue( 'text', item, previousPosition, position, charactersCount );\n\t\t\t}\n\t\t} else if ( typeof node == 'string' ) {\n\t\t\tlet textLength;\n\n\t\t\tif ( this.singleCharacters ) {\n\t\t\t\ttextLength = 1;\n\t\t\t} else {\n\t\t\t\t// Check if text stick out of walker range.\n\t\t\t\tconst endOffset = parent === this._boundaryEndParent ? this.boundaries.end.offset : parent.data.length;\n\n\t\t\t\ttextLength = endOffset - position.offset;\n\t\t\t}\n\n\t\t\tconst textProxy = new TextProxy( parent, position.offset, textLength );\n\n\t\t\tposition.offset += textLength;\n\t\t\tthis.position = position;\n\n\t\t\treturn this._formatReturnValue( 'text', textProxy, previousPosition, position, textLength );\n\t\t} else {\n\t\t\t// `node` is not set, we reached the end of current `parent`.\n\t\t\tposition = Position._createAfter( parent );\n\t\t\tthis.position = position;\n\n\t\t\tif ( this.ignoreElementEnd ) {\n\t\t\t\treturn this._next();\n\t\t\t} else {\n\t\t\t\treturn this._formatReturnValue( 'elementEnd', parent, previousPosition, position );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Makes a step backward in view. Moves the {@link #position} to the previous position and returns the encountered value.\n\t *\n\t * @private\n\t * @returns {Object}\n\t * @returns {Boolean} return.done True if iterator is done.\n\t * @returns {module:engine/view/treewalker~TreeWalkerValue} return.value Information about taken step.\n\t */\n\t_previous() {\n\t\tlet position = this.position.clone();\n\t\tconst previousPosition = this.position;\n\t\tconst parent = position.parent;\n\n\t\t// We are at the beginning of the root.\n\t\tif ( parent.parent === null && position.offset === 0 ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// We reached the walker boundary.\n\t\tif ( parent == this._boundaryStartParent && position.offset == this.boundaries.start.offset ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// Get node just before current position.\n\t\tlet node;\n\n\t\t// Text {@link module:engine/view/text~Text} element is a specific parent because contains string instead of child nodes.\n\t\tif ( parent instanceof Text ) {\n\t\t\tif ( position.isAtStart ) {\n\t\t\t\t// Prevent returning \"elementStart\" for Text node. Skip that value and return the next walker step.\n\t\t\t\tthis.position = Position._createBefore( parent );\n\n\t\t\t\treturn this._previous();\n\t\t\t}\n\n\t\t\tnode = parent.data[ position.offset - 1 ];\n\t\t} else {\n\t\t\tnode = parent.getChild( position.offset - 1 );\n\t\t}\n\n\t\tif ( node instanceof Element ) {\n\t\t\tif ( !this.shallow ) {\n\t\t\t\tposition = new Position( node, node.childCount );\n\t\t\t\tthis.position = position;\n\n\t\t\t\tif ( this.ignoreElementEnd ) {\n\t\t\t\t\treturn this._previous();\n\t\t\t\t} else {\n\t\t\t\t\treturn this._formatReturnValue( 'elementEnd', node, previousPosition, position );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tposition.offset--;\n\t\t\t\tthis.position = position;\n\n\t\t\t\treturn this._formatReturnValue( 'elementStart', node, previousPosition, position, 1 );\n\t\t\t}\n\t\t} else if ( node instanceof Text ) {\n\t\t\tif ( this.singleCharacters ) {\n\t\t\t\tposition = new Position( node, node.data.length );\n\t\t\t\tthis.position = position;\n\n\t\t\t\treturn this._previous();\n\t\t\t} else {\n\t\t\t\tlet charactersCount = node.data.length;\n\t\t\t\tlet item;\n\n\t\t\t\t// If text stick out of walker range, we need to cut it and wrap in TextProxy.\n\t\t\t\tif ( node == this._boundaryStartParent ) {\n\t\t\t\t\tconst offset = this.boundaries.start.offset;\n\n\t\t\t\t\titem = new TextProxy( node, offset, node.data.length - offset );\n\t\t\t\t\tcharactersCount = item.data.length;\n\t\t\t\t\tposition = Position._createBefore( item );\n\t\t\t\t} else {\n\t\t\t\t\titem = new TextProxy( node, 0, node.data.length );\n\t\t\t\t\t// If not just keep moving backward.\n\t\t\t\t\tposition.offset--;\n\t\t\t\t}\n\n\t\t\t\tthis.position = position;\n\n\t\t\t\treturn this._formatReturnValue( 'text', item, previousPosition, position, charactersCount );\n\t\t\t}\n\t\t} else if ( typeof node == 'string' ) {\n\t\t\tlet textLength;\n\n\t\t\tif ( !this.singleCharacters ) {\n\t\t\t\t// Check if text stick out of walker range.\n\t\t\t\tconst startOffset = parent === this._boundaryStartParent ? this.boundaries.start.offset : 0;\n\n\t\t\t\ttextLength = position.offset - startOffset;\n\t\t\t} else {\n\t\t\t\ttextLength = 1;\n\t\t\t}\n\n\t\t\tposition.offset -= textLength;\n\n\t\t\tconst textProxy = new TextProxy( parent, position.offset, textLength );\n\n\t\t\tthis.position = position;\n\n\t\t\treturn this._formatReturnValue( 'text', textProxy, previousPosition, position, textLength );\n\t\t} else {\n\t\t\t// `node` is not set, we reached the beginning of current `parent`.\n\t\t\tposition = Position._createBefore( parent );\n\t\t\tthis.position = position;\n\n\t\t\treturn this._formatReturnValue( 'elementStart', parent, previousPosition, position, 1 );\n\t\t}\n\t}\n\n\t/**\n\t * Format returned data and adjust `previousPosition` and `nextPosition` if reach the bound of the {@link module:engine/view/text~Text}.\n\t *\n\t * @private\n\t * @param {module:engine/view/treewalker~TreeWalkerValueType} type Type of step.\n\t * @param {module:engine/view/item~Item} item Item between old and new position.\n\t * @param {module:engine/view/position~Position} previousPosition Previous position of iterator.\n\t * @param {module:engine/view/position~Position} nextPosition Next position of iterator.\n\t * @param {Number} [length] Length of the item.\n\t * @returns {module:engine/view/treewalker~TreeWalkerValue}\n\t */\n\t_formatReturnValue( type, item, previousPosition, nextPosition, length ) {\n\t\t// Text is a specific parent, because contains string instead of children.\n\t\t// Walker doesn't enter to the Text except situations when walker is iterating over every single character,\n\t\t// or the bound starts/ends inside the Text. So when the position is at the beginning or at the end of the Text\n\t\t// we move it just before or just after Text.\n\t\tif ( item instanceof TextProxy ) {\n\t\t\t// Position is at the end of Text.\n\t\t\tif ( item.offsetInText + item.data.length == item.textNode.data.length ) {\n\t\t\t\tif ( this.direction == 'forward' && !( this.boundaries && this.boundaries.end.isEqual( this.position ) ) ) {\n\t\t\t\t\tnextPosition = Position._createAfter( item.textNode );\n\t\t\t\t\t// When we change nextPosition of returned value we need also update walker current position.\n\t\t\t\t\tthis.position = nextPosition;\n\t\t\t\t} else {\n\t\t\t\t\tpreviousPosition = Position._createAfter( item.textNode );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Position is at the begining ot the text.\n\t\t\tif ( item.offsetInText === 0 ) {\n\t\t\t\tif ( this.direction == 'backward' && !( this.boundaries && this.boundaries.start.isEqual( this.position ) ) ) {\n\t\t\t\t\tnextPosition = Position._createBefore( item.textNode );\n\t\t\t\t\t// When we change nextPosition of returned value we need also update walker current position.\n\t\t\t\t\tthis.position = nextPosition;\n\t\t\t\t} else {\n\t\t\t\t\tpreviousPosition = Position._createBefore( item.textNode );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tdone: false,\n\t\t\tvalue: {\n\t\t\t\ttype,\n\t\t\t\titem,\n\t\t\t\tpreviousPosition,\n\t\t\t\tnextPosition,\n\t\t\t\tlength\n\t\t\t}\n\t\t};\n\t}\n}\n\n/**\n * Type of the step made by {@link module:engine/view/treewalker~TreeWalker}.\n * Possible values: `'elementStart'` if walker is at the beginning of a node, `'elementEnd'` if walker is at the end\n * of node, or `'text'` if walker traversed over single and multiple characters.\n * For {@link module:engine/view/text~Text} `elementStart` and `elementEnd` is not returned.\n *\n * @typedef {String} module:engine/view/treewalker~TreeWalkerValueType\n */\n\n/**\n * Object returned by {@link module:engine/view/treewalker~TreeWalker} when traversing tree view.\n *\n * @typedef {Object} module:engine/view/treewalker~TreeWalkerValue\n * @property {module:engine/view/treewalker~TreeWalkerValueType} type\n * @property {module:engine/view/item~Item} item Item between the old and the new positions\n * of the tree walker.\n * @property {module:engine/view/position~Position} previousPosition Previous position of the iterator.\n * * Forward iteration: For `'elementEnd'` it is the last position inside the element. For all other types it is the\n * position before the item.\n * * Backward iteration: For `'elementStart'` it is the first position inside the element. For all other types it is\n * the position after item.\n * * If the position is at the beginning or at the end of the {@link module:engine/view/text~Text} it is always moved from the\n * inside of the text to its parent just before or just after that text.\n * @property {module:engine/view/position~Position} nextPosition Next position of the iterator.\n * * Forward iteration: For `'elementStart'` it is the first position inside the element. For all other types it is\n * the position after the item.\n * * Backward iteration: For `'elementEnd'` it is last position inside element. For all other types it is the position\n * before the item.\n * * If the position is at the beginning or at the end of the {@link module:engine/view/text~Text} it is always moved from the\n * inside of the text to its parent just before or just after that text.\n * @property {Number} [length] Length of the item. For `'elementStart'` it is `1`. For `'text'` it is\n * the length of that text. For `'elementEnd'` it is `undefined`.\n */\n\n/**\n * Tree walking directions.\n *\n * @typedef {'forward'|'backward'} module:engine/view/treewalker~TreeWalkerDirection\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/position\n */\n\nimport TreeWalker from './treewalker';\n\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport EditableElement from './editableelement';\n\n// To check if component is loaded more than once.\nimport '@ckeditor/ckeditor5-utils/src/version';\n\n/**\n * Position in the view tree. Position is represented by its parent node and an offset in this parent.\n *\n * In order to create a new position instance use the `createPosition*()` factory methods available in:\n *\n * * {@link module:engine/view/view~View}\n * * {@link module:engine/view/downcastwriter~DowncastWriter}\n * * {@link module:engine/view/upcastwriter~UpcastWriter}\n */\nexport default class Position {\n\t/**\n\t * Creates a position.\n\t *\n\t * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} parent Position parent.\n\t * @param {Number} offset Position offset.\n\t */\n\tconstructor( parent, offset ) {\n\t\t/**\n\t\t * Position parent.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment}\n\t\t * module:engine/view/position~Position#parent\n\t\t */\n\t\tthis.parent = parent;\n\n\t\t/**\n\t\t * Position offset.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} module:engine/view/position~Position#offset\n\t\t */\n\t\tthis.offset = offset;\n\t}\n\n\t/**\n\t * Node directly after the position. Equals `null` when there is no node after position or position is located\n\t * inside text node.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|null}\n\t */\n\tget nodeAfter() {\n\t\tif ( this.parent.is( '$text' ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.parent.getChild( this.offset ) || null;\n\t}\n\n\t/**\n\t * Node directly before the position. Equals `null` when there is no node before position or position is located\n\t * inside text node.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|null}\n\t */\n\tget nodeBefore() {\n\t\tif ( this.parent.is( '$text' ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.parent.getChild( this.offset - 1 ) || null;\n\t}\n\n\t/**\n\t * Is `true` if position is at the beginning of its {@link module:engine/view/position~Position#parent parent}, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isAtStart() {\n\t\treturn this.offset === 0;\n\t}\n\n\t/**\n\t * Is `true` if position is at the end of its {@link module:engine/view/position~Position#parent parent}, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isAtEnd() {\n\t\tconst endOffset = this.parent.is( '$text' ) ? this.parent.data.length : this.parent.childCount;\n\n\t\treturn this.offset === endOffset;\n\t}\n\n\t/**\n\t * Position's root, that is the root of the position's parent element.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this.parent.root;\n\t}\n\n\t/**\n\t * {@link module:engine/view/editableelement~EditableElement EditableElement} instance that contains this position, or `null` if\n\t * position is not inside an editable element.\n\t *\n\t * @type {module:engine/view/editableelement~EditableElement|null}\n\t */\n\tget editableElement() {\n\t\tlet editable = this.parent;\n\n\t\twhile ( !( editable instanceof EditableElement ) ) {\n\t\t\tif ( editable.parent ) {\n\t\t\t\teditable = editable.parent;\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\treturn editable;\n\t}\n\n\t/**\n\t * Returns a new instance of Position with offset incremented by `shift` value.\n\t *\n\t * @param {Number} shift How position offset should get changed. Accepts negative values.\n\t * @returns {module:engine/view/position~Position} Shifted position.\n\t */\n\tgetShiftedBy( shift ) {\n\t\tconst shifted = Position._createAt( this );\n\n\t\tconst offset = shifted.offset + shift;\n\t\tshifted.offset = offset < 0 ? 0 : offset;\n\n\t\treturn shifted;\n\t}\n\n\t/**\n\t * Gets the farthest position which matches the callback using\n\t * {@link module:engine/view/treewalker~TreeWalker TreeWalker}.\n\t *\n\t * For example:\n\t *\n\t * \t\tgetLastMatchingPosition( value => value.type == 'text' ); // <p>{}foo</p> -> <p>foo[]</p>\n\t * \t\tgetLastMatchingPosition( value => value.type == 'text', { direction: 'backward' } ); // <p>foo[]</p> -> <p>{}foo</p>\n\t * \t\tgetLastMatchingPosition( value => false ); // Do not move the position.\n\t *\n\t * @param {Function} skip Callback function. Gets {@link module:engine/view/treewalker~TreeWalkerValue} and should\n\t * return `true` if the value should be skipped or `false` if not.\n\t * @param {Object} options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}.\n\t *\n\t * @returns {module:engine/view/position~Position} The position after the last item which matches the `skip` callback test.\n\t */\n\tgetLastMatchingPosition( skip, options = {} ) {\n\t\toptions.startPosition = this;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\t\ttreeWalker.skip( skip );\n\n\t\treturn treeWalker.position;\n\t}\n\n\t/**\n\t * Returns ancestors array of this position, that is this position's parent and it's ancestors.\n\t *\n\t * @returns {Array} Array with ancestors.\n\t */\n\tgetAncestors() {\n\t\tif ( this.parent.is( 'documentFragment' ) ) {\n\t\t\treturn [ this.parent ];\n\t\t} else {\n\t\t\treturn this.parent.getAncestors( { includeSelf: true } );\n\t\t}\n\t}\n\n\t/**\n\t * Returns a {@link module:engine/view/node~Node} or {@link module:engine/view/documentfragment~DocumentFragment}\n\t * which is a common ancestor of both positions.\n\t *\n\t * @param {module:engine/view/position~Position} position\n\t * @returns {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor( position ) {\n\t\tconst ancestorsA = this.getAncestors();\n\t\tconst ancestorsB = position.getAncestors();\n\n\t\tlet i = 0;\n\n\t\twhile ( ancestorsA[ i ] == ancestorsB[ i ] && ancestorsA[ i ] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i === 0 ? null : ancestorsA[ i - 1 ];\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tposition.is( 'position' ); // -> true\n\t *\t\tposition.is( 'view:position' ); // -> true\n\t *\n\t *\t\tposition.is( 'model:position' ); // -> false\n\t *\t\tposition.is( 'element' ); // -> false\n\t *\t\tposition.is( 'range' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'position' || type === 'view:position';\n\t}\n\n\t/**\n\t * Checks whether this position equals given position.\n\t *\n\t * @param {module:engine/view/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} True if positions are same.\n\t */\n\tisEqual( otherPosition ) {\n\t\treturn ( this.parent == otherPosition.parent && this.offset == otherPosition.offset );\n\t}\n\n\t/**\n\t * Checks whether this position is located before given position. When method returns `false` it does not mean that\n\t * this position is after give one. Two positions may be located inside separate roots and in that situation this\n\t * method will still return `false`.\n\t *\n\t * @see module:engine/view/position~Position#isAfter\n\t * @see module:engine/view/position~Position#compareWith\n\t * @param {module:engine/view/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} Returns `true` if this position is before given position.\n\t */\n\tisBefore( otherPosition ) {\n\t\treturn this.compareWith( otherPosition ) == 'before';\n\t}\n\n\t/**\n\t * Checks whether this position is located after given position. When method returns `false` it does not mean that\n\t * this position is before give one. Two positions may be located inside separate roots and in that situation this\n\t * method will still return `false`.\n\t *\n\t * @see module:engine/view/position~Position#isBefore\n\t * @see module:engine/view/position~Position#compareWith\n\t * @param {module:engine/view/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} Returns `true` if this position is after given position.\n\t */\n\tisAfter( otherPosition ) {\n\t\treturn this.compareWith( otherPosition ) == 'after';\n\t}\n\n\t/**\n\t * Checks whether this position is before, after or in same position that other position. Two positions may be also\n\t * different when they are located in separate roots.\n\t *\n\t * @param {module:engine/view/position~Position} otherPosition Position to compare with.\n\t * @returns {module:engine/view/position~PositionRelation}\n\t */\n\tcompareWith( otherPosition ) {\n\t\tif ( this.root !== otherPosition.root ) {\n\t\t\treturn 'different';\n\t\t}\n\n\t\tif ( this.isEqual( otherPosition ) ) {\n\t\t\treturn 'same';\n\t\t}\n\n\t\t// Get path from root to position's parent element.\n\t\tconst thisPath = this.parent.is( 'node' ) ? this.parent.getPath() : [];\n\t\tconst otherPath = otherPosition.parent.is( 'node' ) ? otherPosition.parent.getPath() : [];\n\n\t\t// Add the positions' offsets to the parents offsets.\n\t\tthisPath.push( this.offset );\n\t\totherPath.push( otherPosition.offset );\n\n\t\t// Compare both path arrays to find common ancestor.\n\t\tconst result = compareArrays( thisPath, otherPath );\n\n\t\tswitch ( result ) {\n\t\t\tcase 'prefix':\n\t\t\t\treturn 'before';\n\n\t\t\tcase 'extension':\n\t\t\t\treturn 'after';\n\n\t\t\tdefault:\n\t\t\t\treturn thisPath[ result ] < otherPath[ result ] ? 'before' : 'after';\n\t\t}\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/view/treewalker~TreeWalker TreeWalker} instance with this positions as a start position.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}\n\t * @param {module:engine/view/range~Range} [options.boundaries=null] Range to define boundaries of the iterator.\n\t * @param {Boolean} [options.singleCharacters=false]\n\t * @param {Boolean} [options.shallow=false]\n\t * @param {Boolean} [options.ignoreElementEnd=false]\n\t */\n\tgetWalker( options = {} ) {\n\t\toptions.startPosition = this;\n\n\t\treturn new TreeWalker( options );\n\t}\n\n\tclone() {\n\t\treturn new Position( this.parent, this.offset );\n\t}\n\n\t/**\n\t * Creates position at the given location. The location can be specified as:\n\t *\n\t * * a {@link module:engine/view/position~Position position},\n\t * * parent element and offset (offset defaults to `0`),\n\t * * parent element and `'end'` (sets position at the end of that element),\n\t * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).\n\t *\n\t * This method is a shortcut to other constructors such as:\n\t *\n\t * * {@link module:engine/view/position~Position._createBefore},\n\t * * {@link module:engine/view/position~Position._createAfter}.\n\t *\n\t * @protected\n\t * @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/view/item~Item view item}.\n\t */\n\tstatic _createAt( itemOrPosition, offset ) {\n\t\tif ( itemOrPosition instanceof Position ) {\n\t\t\treturn new this( itemOrPosition.parent, itemOrPosition.offset );\n\t\t} else {\n\t\t\tconst node = itemOrPosition;\n\n\t\t\tif ( offset == 'end' ) {\n\t\t\t\toffset = node.is( '$text' ) ? node.data.length : node.childCount;\n\t\t\t} else if ( offset == 'before' ) {\n\t\t\t\treturn this._createBefore( node );\n\t\t\t} else if ( offset == 'after' ) {\n\t\t\t\treturn this._createAfter( node );\n\t\t\t} else if ( offset !== 0 && !offset ) {\n\t\t\t\t/**\n\t\t\t\t * {@link module:engine/view/view~View#createPositionAt `View#createPositionAt()`}\n\t\t\t\t * requires the offset to be specified when the first parameter is a view item.\n\t\t\t\t *\n\t\t\t\t * @error view-createpositionat-offset-required\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'view-createpositionat-offset-required', node );\n\t\t\t}\n\n\t\t\treturn new Position( node, offset );\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new position after given view item.\n\t *\n\t * @protected\n\t * @param {module:engine/view/item~Item} item View item after which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tstatic _createAfter( item ) {\n\t\t// TextProxy is not a instance of Node so we need do handle it in specific way.\n\t\tif ( item.is( '$textProxy' ) ) {\n\t\t\treturn new Position( item.textNode, item.offsetInText + item.data.length );\n\t\t}\n\n\t\tif ( !item.parent ) {\n\t\t\t/**\n\t\t\t * You can not make a position after a root.\n\t\t\t *\n\t\t\t * @error view-position-after-root\n\t\t\t * @param {module:engine/view/node~Node} root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-position-after-root', item, { root: item } );\n\t\t}\n\n\t\treturn new Position( item.parent, item.index + 1 );\n\t}\n\n\t/**\n\t * Creates a new position before given view item.\n\t *\n\t * @protected\n\t * @param {module:engine/view/item~Item} item View item before which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tstatic _createBefore( item ) {\n\t\t// TextProxy is not a instance of Node so we need do handle it in specific way.\n\t\tif ( item.is( '$textProxy' ) ) {\n\t\t\treturn new Position( item.textNode, item.offsetInText );\n\t\t}\n\n\t\tif ( !item.parent ) {\n\t\t\t/**\n\t\t\t * You cannot make a position before a root.\n\t\t\t *\n\t\t\t * @error view-position-before-root\n\t\t\t * @param {module:engine/view/node~Node} root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-position-before-root', item, { root: item } );\n\t\t}\n\n\t\treturn new Position( item.parent, item.index );\n\t}\n}\n\n/**\n * A flag indicating whether this position is `'before'` or `'after'` or `'same'` as given position.\n * If positions are in different roots `'different'` flag is returned.\n *\n * @typedef {String} module:engine/view/position~PositionRelation\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/range\n */\n\nimport Position from './position';\nimport TreeWalker from './treewalker';\n\n/**\n * Range in the view tree. A range is represented by its start and end {@link module:engine/view/position~Position positions}.\n *\n * In order to create a new position instance use the `createPosition*()` factory methods available in:\n *\n * * {@link module:engine/view/view~View}\n * * {@link module:engine/view/downcastwriter~DowncastWriter}\n * * {@link module:engine/view/upcastwriter~UpcastWriter}\n */\nexport default class Range {\n\t/**\n\t * Creates a range spanning from `start` position to `end` position.\n\t *\n\t * **Note:** Constructor creates it's own {@link module:engine/view/position~Position} instances basing on passed values.\n\t *\n\t * @param {module:engine/view/position~Position} start Start position.\n\t * @param {module:engine/view/position~Position} [end] End position. If not set, range will be collapsed at the `start` position.\n\t */\n\tconstructor( start, end = null ) {\n\t\t/**\n\t\t * Start position.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/position~Position}\n\t\t */\n\t\tthis.start = start.clone();\n\n\t\t/**\n\t\t * End position.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/position~Position}\n\t\t */\n\t\tthis.end = end ? end.clone() : start.clone();\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over all {@link module:engine/view/item~Item view items} that are in this range and returns\n\t * them together with additional information like length or {@link module:engine/view/position~Position positions},\n\t * grouped as {@link module:engine/view/treewalker~TreeWalkerValue}.\n\t *\n\t * This iterator uses {@link module:engine/view/treewalker~TreeWalker TreeWalker} with `boundaries` set to this range and\n\t * `ignoreElementEnd` option\n\t * set to `true`.\n\t *\n\t * @returns {Iterable.<module:engine/view/treewalker~TreeWalkerValue>}\n\t */\n\t* [ Symbol.iterator ]() {\n\t\tyield* new TreeWalker( { boundaries: this, ignoreElementEnd: true } );\n\t}\n\n\t/**\n\t * Returns whether the range is collapsed, that is it start and end positions are equal.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\treturn this.start.isEqual( this.end );\n\t}\n\n\t/**\n\t * Returns whether this range is flat, that is if {@link module:engine/view/range~Range#start start} position and\n\t * {@link module:engine/view/range~Range#end end} position are in the same {@link module:engine/view/position~Position#parent parent}.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isFlat() {\n\t\treturn this.start.parent === this.end.parent;\n\t}\n\n\t/**\n\t * Range root element.\n\t *\n\t * @type {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this.start.root;\n\t}\n\n\t/**\n\t * Creates a maximal range that has the same content as this range but is expanded in both ways (at the beginning\n\t * and at the end).\n\t *\n\t * For example:\n\t *\n\t *\t\t<p>Foo</p><p><b>{Bar}</b></p> -> <p>Foo</p>[<p><b>Bar</b>]</p>\n\t *\t\t<p><b>foo</b>{bar}<span></span></p> -> <p><b>foo[</b>bar<span></span>]</p>\n\t *\n\t * Note that in the sample above:\n\t *\n\t * - `<p>` have type of {@link module:engine/view/containerelement~ContainerElement},\n\t * - `<b>` have type of {@link module:engine/view/attributeelement~AttributeElement},\n\t * - `<span>` have type of {@link module:engine/view/uielement~UIElement}.\n\t *\n\t * @returns {module:engine/view/range~Range} Enlarged range.\n\t */\n\tgetEnlarged() {\n\t\tlet start = this.start.getLastMatchingPosition( enlargeTrimSkip, { direction: 'backward' } );\n\t\tlet end = this.end.getLastMatchingPosition( enlargeTrimSkip );\n\n\t\t// Fix positions, in case if they are in Text node.\n\t\tif ( start.parent.is( '$text' ) && start.isAtStart ) {\n\t\t\tstart = Position._createBefore( start.parent );\n\t\t}\n\n\t\tif ( end.parent.is( '$text' ) && end.isAtEnd ) {\n\t\t\tend = Position._createAfter( end.parent );\n\t\t}\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Creates a minimum range that has the same content as this range but is trimmed in both ways (at the beginning\n\t * and at the end).\n\t *\n\t * For example:\n\t *\n\t *\t\t<p>Foo</p>[<p><b>Bar</b>]</p> -> <p>Foo</p><p><b>{Bar}</b></p>\n\t *\t\t<p><b>foo[</b>bar<span></span>]</p> -> <p><b>foo</b>{bar}<span></span></p>\n\t *\n\t * Note that in the sample above:\n\t *\n\t * - `<p>` have type of {@link module:engine/view/containerelement~ContainerElement},\n\t * - `<b>` have type of {@link module:engine/view/attributeelement~AttributeElement},\n\t * - `<span>` have type of {@link module:engine/view/uielement~UIElement}.\n\t *\n\t * @returns {module:engine/view/range~Range} Shrink range.\n\t */\n\tgetTrimmed() {\n\t\tlet start = this.start.getLastMatchingPosition( enlargeTrimSkip );\n\n\t\tif ( start.isAfter( this.end ) || start.isEqual( this.end ) ) {\n\t\t\treturn new Range( start, start );\n\t\t}\n\n\t\tlet end = this.end.getLastMatchingPosition( enlargeTrimSkip, { direction: 'backward' } );\n\t\tconst nodeAfterStart = start.nodeAfter;\n\t\tconst nodeBeforeEnd = end.nodeBefore;\n\n\t\t// Because TreeWalker prefers positions next to text node, we need to move them manually into these text nodes.\n\t\tif ( nodeAfterStart && nodeAfterStart.is( '$text' ) ) {\n\t\t\tstart = new Position( nodeAfterStart, 0 );\n\t\t}\n\n\t\tif ( nodeBeforeEnd && nodeBeforeEnd.is( '$text' ) ) {\n\t\t\tend = new Position( nodeBeforeEnd, nodeBeforeEnd.data.length );\n\t\t}\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Two ranges are equal if their start and end positions are equal.\n\t *\n\t * @param {module:engine/view/range~Range} otherRange Range to compare with.\n\t * @returns {Boolean} `true` if ranges are equal, `false` otherwise\n\t */\n\tisEqual( otherRange ) {\n\t\treturn this == otherRange || ( this.start.isEqual( otherRange.start ) && this.end.isEqual( otherRange.end ) );\n\t}\n\n\t/**\n\t * Checks whether this range contains given {@link module:engine/view/position~Position position}.\n\t *\n\t * @param {module:engine/view/position~Position} position Position to check.\n\t * @returns {Boolean} `true` if given {@link module:engine/view/position~Position position} is contained in this range,\n\t * `false` otherwise.\n\t */\n\tcontainsPosition( position ) {\n\t\treturn position.isAfter( this.start ) && position.isBefore( this.end );\n\t}\n\n\t/**\n\t * Checks whether this range contains given {@link module:engine/view/range~Range range}.\n\t *\n\t * @param {module:engine/view/range~Range} otherRange Range to check.\n\t * @param {Boolean} [loose=false] Whether the check is loose or strict. If the check is strict (`false`), compared range cannot\n\t * start or end at the same position as this range boundaries. If the check is loose (`true`), compared range can start, end or\n\t * even be equal to this range. Note that collapsed ranges are always compared in strict mode.\n\t * @returns {Boolean} `true` if given {@link module:engine/view/range~Range range} boundaries are contained by this range, `false`\n\t * otherwise.\n\t */\n\tcontainsRange( otherRange, loose = false ) {\n\t\tif ( otherRange.isCollapsed ) {\n\t\t\tloose = false;\n\t\t}\n\n\t\tconst containsStart = this.containsPosition( otherRange.start ) || ( loose && this.start.isEqual( otherRange.start ) );\n\t\tconst containsEnd = this.containsPosition( otherRange.end ) || ( loose && this.end.isEqual( otherRange.end ) );\n\n\t\treturn containsStart && containsEnd;\n\t}\n\n\t/**\n\t * Computes which part(s) of this {@link module:engine/view/range~Range range} is not a part of given\n\t * {@link module:engine/view/range~Range range}.\n\t * Returned array contains zero, one or two {@link module:engine/view/range~Range ranges}.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet foo = downcastWriter.createText( 'foo' );\n\t *\t\tlet img = downcastWriter.createContainerElement( 'img' );\n\t *\t\tlet bar = downcastWriter.createText( 'bar' );\n\t *\t\tlet p = downcastWriter.createContainerElement( 'p', null, [ foo, img, bar ] );\n\t *\n\t *\t\tlet range = view.createRange( view.createPositionAt( foo, 2 ), view.createPositionAt( bar, 1 ); // \"o\", img, \"b\" are in range.\n\t *\t\tlet otherRange = view.createRange( // \"oo\", img, \"ba\" are in range.\n\t *\t\t\tview.createPositionAt( foo, 1 ),\n\t *\t\t\tview.createPositionAt( bar, 2 )\n\t *\t\t);\n\t *\t\tlet transformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has no ranges because `otherRange` contains `range`\n\t *\n\t *\t\totherRange = view.createRange( view.createPositionAt( foo, 1 ), view.createPositionAt( p, 2 ); // \"oo\", img are in range.\n\t *\t\ttransformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has one range: from ( p, 2 ) to ( bar, 1 )\n\t *\n\t *\t\totherRange = view.createRange( view.createPositionAt( p, 1 ), view.createPositionAt( p, 2 ) ); // img is in range.\n\t *\t\ttransformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has two ranges: from ( foo, 1 ) to ( p, 1 ) and from ( p, 2 ) to ( bar, 1 )\n\t *\n\t * @param {module:engine/view/range~Range} otherRange Range to differentiate against.\n\t * @returns {Array.<module:engine/view/range~Range>} The difference between ranges.\n\t */\n\tgetDifference( otherRange ) {\n\t\tconst ranges = [];\n\n\t\tif ( this.isIntersecting( otherRange ) ) {\n\t\t\t// Ranges intersect.\n\n\t\t\tif ( this.containsPosition( otherRange.start ) ) {\n\t\t\t\t// Given range start is inside this range. This means that we have to\n\t\t\t\t// add shrunken range - from the start to the middle of this range.\n\t\t\t\tranges.push( new Range( this.start, otherRange.start ) );\n\t\t\t}\n\n\t\t\tif ( this.containsPosition( otherRange.end ) ) {\n\t\t\t\t// Given range end is inside this range. This means that we have to\n\t\t\t\t// add shrunken range - from the middle of this range to the end.\n\t\t\t\tranges.push( new Range( otherRange.end, this.end ) );\n\t\t\t}\n\t\t} else {\n\t\t\t// Ranges do not intersect, return the original range.\n\t\t\tranges.push( this.clone() );\n\t\t}\n\n\t\treturn ranges;\n\t}\n\n\t/**\n\t * Returns an intersection of this {@link module:engine/view/range~Range range} and given {@link module:engine/view/range~Range range}.\n\t * Intersection is a common part of both of those ranges. If ranges has no common part, returns `null`.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet foo = downcastWriter.createText( 'foo' );\n\t *\t\tlet img = downcastWriter.createContainerElement( 'img' );\n\t *\t\tlet bar = downcastWriter.createText( 'bar' );\n\t *\t\tlet p = downcastWriter.createContainerElement( 'p', null, [ foo, img, bar ] );\n\t *\n\t *\t\tlet range = view.createRange( view.createPositionAt( foo, 2 ), view.createPositionAt( bar, 1 ); // \"o\", img, \"b\" are in range.\n\t *\t\tlet otherRange = view.createRange( view.createPositionAt( foo, 1 ), view.createPositionAt( p, 2 ); // \"oo\", img are in range.\n\t *\t\tlet transformed = range.getIntersection( otherRange ); // range from ( foo, 1 ) to ( p, 2 ).\n\t *\n\t *\t\totherRange = view.createRange( view.createPositionAt( bar, 1 ), view.createPositionAt( bar, 3 ); \"ar\" is in range.\n\t *\t\ttransformed = range.getIntersection( otherRange ); // null - no common part.\n\t *\n\t * @param {module:engine/view/range~Range} otherRange Range to check for intersection.\n\t * @returns {module:engine/view/range~Range|null} A common part of given ranges or `null` if ranges have no common part.\n\t */\n\tgetIntersection( otherRange ) {\n\t\tif ( this.isIntersecting( otherRange ) ) {\n\t\t\t// Ranges intersect, so a common range will be returned.\n\t\t\t// At most, it will be same as this range.\n\t\t\tlet commonRangeStart = this.start;\n\t\t\tlet commonRangeEnd = this.end;\n\n\t\t\tif ( this.containsPosition( otherRange.start ) ) {\n\t\t\t\t// Given range start is inside this range. This means thaNt we have to\n\t\t\t\t// shrink common range to the given range start.\n\t\t\t\tcommonRangeStart = otherRange.start;\n\t\t\t}\n\n\t\t\tif ( this.containsPosition( otherRange.end ) ) {\n\t\t\t\t// Given range end is inside this range. This means that we have to\n\t\t\t\t// shrink common range to the given range end.\n\t\t\t\tcommonRangeEnd = otherRange.end;\n\t\t\t}\n\n\t\t\treturn new Range( commonRangeStart, commonRangeEnd );\n\t\t}\n\n\t\t// Ranges do not intersect, so they do not have common part.\n\t\treturn null;\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/view/treewalker~TreeWalker TreeWalker} instance with this range as a boundary.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}.\n\t * @param {module:engine/view/position~Position} [options.startPosition]\n\t * @param {Boolean} [options.singleCharacters=false]\n\t * @param {Boolean} [options.shallow=false]\n\t * @param {Boolean} [options.ignoreElementEnd=false]\n\t * @returns {module:engine/view/treewalker~TreeWalker}\n\t */\n\tgetWalker( options = {} ) {\n\t\toptions.boundaries = this;\n\n\t\treturn new TreeWalker( options );\n\t}\n\n\t/**\n\t * Returns a {@link module:engine/view/node~Node} or {@link module:engine/view/documentfragment~DocumentFragment}\n\t * which is a common ancestor of range's both ends (in which the entire range is contained).\n\t *\n\t * @returns {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor() {\n\t\treturn this.start.getCommonAncestor( this.end );\n\t}\n\n\t/**\n\t * Returns an {@link module:engine/view/element~Element Element} contained by the range.\n\t * The element will be returned when it is the **only** node within the range and **fully–contained**\n\t * at the same time.\n\t *\n\t * @returns {module:engine/view/element~Element|null}\n\t */\n\tgetContainedElement() {\n\t\tif ( this.isCollapsed ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tlet nodeAfterStart = this.start.nodeAfter;\n\t\tlet nodeBeforeEnd = this.end.nodeBefore;\n\n\t\t// Handle the situation when the range position is at the beginning / at the end of a text node.\n\t\t// In such situation `.nodeAfter` and `.nodeBefore` are `null` but the range still might be spanning\n\t\t// over one element.\n\t\t//\n\t\t// <p>Foo{<span class=\"widget\"></span>}bar</p> vs <p>Foo[<span class=\"widget\"></span>]bar</p>\n\t\t//\n\t\t// These are basically the same range, only the difference is if the range position is at\n\t\t// at the end/at the beginning of a text node or just before/just after the text node.\n\t\t//\n\t\tif ( this.start.parent.is( '$text' ) && this.start.isAtEnd && this.start.parent.nextSibling ) {\n\t\t\tnodeAfterStart = this.start.parent.nextSibling;\n\t\t}\n\n\t\tif ( this.end.parent.is( '$text' ) && this.end.isAtStart && this.end.parent.previousSibling ) {\n\t\t\tnodeBeforeEnd = this.end.parent.previousSibling;\n\t\t}\n\n\t\tif ( nodeAfterStart && nodeAfterStart.is( 'element' ) && nodeAfterStart === nodeBeforeEnd ) {\n\t\t\treturn nodeAfterStart;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Clones this range.\n\t *\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tclone() {\n\t\treturn new Range( this.start, this.end );\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all {@link module:engine/view/item~Item view items} that are in this range and returns\n\t * them.\n\t *\n\t * This method uses {@link module:engine/view/treewalker~TreeWalker} with `boundaries` set to this range and `ignoreElementEnd` option\n\t * set to `true`. However it returns only {@link module:engine/view/item~Item items},\n\t * not {@link module:engine/view/treewalker~TreeWalkerValue}.\n\t *\n\t * You may specify additional options for the tree walker. See {@link module:engine/view/treewalker~TreeWalker} for\n\t * a full list of available options.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}.\n\t * @returns {Iterable.<module:engine/view/item~Item>}\n\t */\n\t* getItems( options = {} ) {\n\t\toptions.boundaries = this;\n\t\toptions.ignoreElementEnd = true;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\n\t\tfor ( const value of treeWalker ) {\n\t\t\tyield value.item;\n\t\t}\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all {@link module:engine/view/position~Position positions} that are boundaries or\n\t * contained in this range.\n\t *\n\t * This method uses {@link module:engine/view/treewalker~TreeWalker} with `boundaries` set to this range. However it returns only\n\t * {@link module:engine/view/position~Position positions}, not {@link module:engine/view/treewalker~TreeWalkerValue}.\n\t *\n\t * You may specify additional options for the tree walker. See {@link module:engine/view/treewalker~TreeWalker} for\n\t * a full list of available options.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}.\n\t * @returns {Iterable.<module:engine/view/position~Position>}\n\t */\n\t* getPositions( options = {} ) {\n\t\toptions.boundaries = this;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\n\t\tyield treeWalker.position;\n\n\t\tfor ( const value of treeWalker ) {\n\t\t\tyield value.nextPosition;\n\t\t}\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\trange.is( 'range' ); // -> true\n\t *\t\trange.is( 'view:range' ); // -> true\n\t *\n\t *\t\trange.is( 'model:range' ); // -> false\n\t *\t\trange.is( 'element' ); // -> false\n\t *\t\trange.is( 'selection' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'range' || type === 'view:range';\n\t}\n\n\t/**\n\t * Checks and returns whether this range intersects with the given range.\n\t *\n\t * @param {module:engine/view/range~Range} otherRange Range to compare with.\n\t * @returns {Boolean} True if ranges intersect.\n\t */\n\tisIntersecting( otherRange ) {\n\t\treturn this.start.isBefore( otherRange.end ) && this.end.isAfter( otherRange.start );\n\t}\n\n\t/**\n\t * Creates a range from the given parents and offsets.\n\t *\n\t * @protected\n\t * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} startElement Start position\n\t * parent element.\n\t * @param {Number} startOffset Start position offset.\n\t * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} endElement End position\n\t * parent element.\n\t * @param {Number} endOffset End position offset.\n\t * @returns {module:engine/view/range~Range} Created range.\n\t */\n\tstatic _createFromParentsAndOffsets( startElement, startOffset, endElement, endOffset ) {\n\t\treturn new this(\n\t\t\tnew Position( startElement, startOffset ),\n\t\t\tnew Position( endElement, endOffset )\n\t\t);\n\t}\n\n\t/**\n\t * Creates a new range, spreading from specified {@link module:engine/view/position~Position position} to a position moved by\n\t * given `shift`. If `shift` is a negative value, shifted position is treated as the beginning of the range.\n\t *\n\t * @protected\n\t * @param {module:engine/view/position~Position} position Beginning of the range.\n\t * @param {Number} shift How long the range should be.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tstatic _createFromPositionAndShift( position, shift ) {\n\t\tconst start = position;\n\t\tconst end = position.getShiftedBy( shift );\n\n\t\treturn shift > 0 ? new this( start, end ) : new this( end, start );\n\t}\n\n\t/**\n\t * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t * @protected\n\t * @param {module:engine/view/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tstatic _createIn( element ) {\n\t\treturn this._createFromParentsAndOffsets( element, 0, element, element.childCount );\n\t}\n\n\t/**\n\t * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.\n\t *\n\t * @protected\n\t * @param {module:engine/view/item~Item} item\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tstatic _createOn( item ) {\n\t\tconst size = item.is( '$textProxy' ) ? item.offsetSize : 1;\n\n\t\treturn this._createFromPositionAndShift( Position._createBefore( item ), size );\n\t}\n}\n\n// Function used by getEnlarged and getTrimmed methods.\nfunction enlargeTrimSkip( value ) {\n\tif ( value.item.is( 'attributeElement' ) || value.item.is( 'uiElement' ) ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/count\n */\n\n/**\n * Returns the number of items return by the iterator.\n *\n *\t\tcount( [ 1, 2, 3, 4, 5 ] ); // 5;\n *\n * @param {Iterable.<*>} iterator Any iterator.\n * @returns {Number} Number of items returned by that iterator.\n */\nexport default function count( iterator ) {\n\tlet count = 0;\n\n\tfor ( const _ of iterator ) { // eslint-disable-line no-unused-vars\n\t\tcount++;\n\t}\n\n\treturn count;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/selection\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport Range from './range';\nimport Position from './position';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport Node from './node';\nimport count from '@ckeditor/ckeditor5-utils/src/count';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\nimport DocumentSelection from './documentselection';\n\n/**\n * Class representing an arbirtary selection in the view.\n * See also {@link module:engine/view/documentselection~DocumentSelection}.\n *\n * New selection instances can be created via the constructor or one these methods:\n *\n * * {@link module:engine/view/view~View#createSelection `View#createSelection()`},\n * * {@link module:engine/view/upcastwriter~UpcastWriter#createSelection `UpcastWriter#createSelection()`}.\n *\n * A selection can consist of {@link module:engine/view/range~Range ranges} that can be set by using\n * the {@link module:engine/view/selection~Selection#setTo `Selection#setTo()`} method.\n */\nexport default class Selection {\n\t/**\n\t * Creates new selection instance.\n\t *\n\t * **Note**: The selection constructor is available as a factory method:\n\t *\n\t * * {@link module:engine/view/view~View#createSelection `View#createSelection()`},\n\t * * {@link module:engine/view/upcastwriter~UpcastWriter#createSelection `UpcastWriter#createSelection()`}.\n\t *\n\t * \t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = writer.createSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tconst selection = writer.createSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tconst selection = writer.createSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tconst selection = writer.createSelection( otherSelection );\n\t *\n\t *\t\t// Creates selection from the document selection.\n\t *\t\tconst selection = writer.createSelection( editor.editing.view.document.selection );\n\t *\n\t * \t\t// Creates selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\tconst selection = writer.createSelection( position );\n\t *\n\t *\t\t// Creates collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = writer.createContainerElement( 'paragraph' );\n\t *\t\tconst selection = writer.createSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'on' );\n\t *\n\t * `Selection`'s constructor allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = writer.createSelection( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * (and be  properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tconst selection = writer.createSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/selection~Selectable} [selectable=null]\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Offset or place when selectable is an `Item`.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t */\n\tconstructor( selectable = null, placeOrOffset, options ) {\n\t\t/**\n\t\t * Stores all ranges that are selected.\n\t\t *\n\t\t * @protected\n\t\t * @member {Array.<module:engine/view/range~Range>}\n\t\t */\n\t\tthis._ranges = [];\n\n\t\t/**\n\t\t * Specifies whether the last added range was added as a backward or forward range.\n\t\t *\n\t\t * @protected\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._lastRangeBackward = false;\n\n\t\t/**\n\t\t * Specifies whether selection instance is fake.\n\t\t *\n\t\t * @private\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._isFake = false;\n\n\t\t/**\n\t\t * Fake selection's label.\n\t\t *\n\t\t * @private\n\t\t * @member {String}\n\t\t */\n\t\tthis._fakeSelectionLabel = '';\n\n\t\tthis.setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Returns true if selection instance is marked as `fake`.\n\t *\n\t * @see #setTo\n\t * @returns {Boolean}\n\t */\n\tget isFake() {\n\t\treturn this._isFake;\n\t}\n\n\t/**\n\t * Returns fake selection label.\n\t *\n\t * @see #setTo\n\t * @returns {String}\n\t */\n\tget fakeSelectionLabel() {\n\t\treturn this._fakeSelectionLabel;\n\t}\n\n\t/**\n\t * Selection anchor. Anchor may be described as a position where the selection starts. Together with\n\t * {@link #focus focus} they define the direction of selection, which is important\n\t * when expanding/shrinking selection. Anchor is always the start or end of the most recent added range.\n\t * It may be a bit unintuitive when there are multiple ranges in selection.\n\t *\n\t * @see #focus\n\t * @type {module:engine/view/position~Position}\n\t */\n\tget anchor() {\n\t\tif ( !this._ranges.length ) {\n\t\t\treturn null;\n\t\t}\n\t\tconst range = this._ranges[ this._ranges.length - 1 ];\n\t\tconst anchor = this._lastRangeBackward ? range.end : range.start;\n\n\t\treturn anchor.clone();\n\t}\n\n\t/**\n\t * Selection focus. Focus is a position where the selection ends.\n\t *\n\t * @see #anchor\n\t * @type {module:engine/view/position~Position}\n\t */\n\tget focus() {\n\t\tif ( !this._ranges.length ) {\n\t\t\treturn null;\n\t\t}\n\t\tconst range = this._ranges[ this._ranges.length - 1 ];\n\t\tconst focus = this._lastRangeBackward ? range.start : range.end;\n\n\t\treturn focus.clone();\n\t}\n\n\t/**\n\t * Returns whether the selection is collapsed. Selection is collapsed when there is exactly one range which is\n\t * collapsed.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\treturn this.rangeCount === 1 && this._ranges[ 0 ].isCollapsed;\n\t}\n\n\t/**\n\t * Returns number of ranges in selection.\n\t *\n\t * @type {Number}\n\t */\n\tget rangeCount() {\n\t\treturn this._ranges.length;\n\t}\n\n\t/**\n\t * Specifies whether the {@link #focus} precedes {@link #anchor}.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isBackward() {\n\t\treturn !this.isCollapsed && this._lastRangeBackward;\n\t}\n\n\t/**\n\t * {@link module:engine/view/editableelement~EditableElement EditableElement} instance that contains this selection, or `null`\n\t * if the selection is not inside an editable element.\n\t *\n\t * @type {module:engine/view/editableelement~EditableElement|null}\n\t */\n\tget editableElement() {\n\t\tif ( this.anchor ) {\n\t\t\treturn this.anchor.editableElement;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns an iterable that contains copies of all ranges added to the selection.\n\t *\n\t * @returns {Iterable.<module:engine/view/range~Range>}\n\t */\n\t* getRanges() {\n\t\tfor ( const range of this._ranges ) {\n\t\t\tyield range.clone();\n\t\t}\n\t}\n\n\t/**\n\t * Returns copy of the first range in the selection. First range is the one which\n\t * {@link module:engine/view/range~Range#start start} position {@link module:engine/view/position~Position#isBefore is before} start\n\t * position of all other ranges (not to confuse with the first range added to the selection).\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/range~Range|null}\n\t */\n\tgetFirstRange() {\n\t\tlet first = null;\n\n\t\tfor ( const range of this._ranges ) {\n\t\t\tif ( !first || range.start.isBefore( first.start ) ) {\n\t\t\t\tfirst = range;\n\t\t\t}\n\t\t}\n\n\t\treturn first ? first.clone() : null;\n\t}\n\n\t/**\n\t * Returns copy of the last range in the selection. Last range is the one which {@link module:engine/view/range~Range#end end}\n\t * position {@link module:engine/view/position~Position#isAfter is after} end position of all other ranges (not to confuse\n\t * with the last range added to the selection). Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/range~Range|null}\n\t */\n\tgetLastRange() {\n\t\tlet last = null;\n\n\t\tfor ( const range of this._ranges ) {\n\t\t\tif ( !last || range.end.isAfter( last.end ) ) {\n\t\t\t\tlast = range;\n\t\t\t}\n\t\t}\n\n\t\treturn last ? last.clone() : null;\n\t}\n\n\t/**\n\t * Returns copy of the first position in the selection. First position is the position that\n\t * {@link module:engine/view/position~Position#isBefore is before} any other position in the selection ranges.\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/position~Position|null}\n\t */\n\tgetFirstPosition() {\n\t\tconst firstRange = this.getFirstRange();\n\n\t\treturn firstRange ? firstRange.start.clone() : null;\n\t}\n\n\t/**\n\t * Returns copy of the last position in the selection. Last position is the position that\n\t * {@link module:engine/view/position~Position#isAfter is after} any other position in the selection ranges.\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/position~Position|null}\n\t */\n\tgetLastPosition() {\n\t\tconst lastRange = this.getLastRange();\n\n\t\treturn lastRange ? lastRange.end.clone() : null;\n\t}\n\n\t/**\n\t * Checks whether, this selection is equal to given selection. Selections are equal if they have same directions,\n\t * same number of ranges and all ranges from one selection equal to a range from other selection.\n\t *\n\t * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} otherSelection\n\t * Selection to compare with.\n\t * @returns {Boolean} `true` if selections are equal, `false` otherwise.\n\t */\n\tisEqual( otherSelection ) {\n\t\tif ( this.isFake != otherSelection.isFake ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( this.isFake && this.fakeSelectionLabel != otherSelection.fakeSelectionLabel ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( this.rangeCount != otherSelection.rangeCount ) {\n\t\t\treturn false;\n\t\t} else if ( this.rangeCount === 0 ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif ( !this.anchor.isEqual( otherSelection.anchor ) || !this.focus.isEqual( otherSelection.focus ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor ( const thisRange of this._ranges ) {\n\t\t\tlet found = false;\n\n\t\t\tfor ( const otherRange of otherSelection._ranges ) {\n\t\t\t\tif ( thisRange.isEqual( otherRange ) ) {\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( !found ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Checks whether this selection is similar to given selection. Selections are similar if they have same directions, same\n\t * number of ranges, and all {@link module:engine/view/range~Range#getTrimmed trimmed} ranges from one selection are\n\t * equal to any trimmed range from other selection.\n\t *\n\t * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} otherSelection\n\t * Selection to compare with.\n\t * @returns {Boolean} `true` if selections are similar, `false` otherwise.\n\t */\n\tisSimilar( otherSelection ) {\n\t\tif ( this.isBackward != otherSelection.isBackward ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst numOfRangesA = count( this.getRanges() );\n\t\tconst numOfRangesB = count( otherSelection.getRanges() );\n\n\t\t// If selections have different number of ranges, they cannot be similar.\n\t\tif ( numOfRangesA != numOfRangesB ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// If both selections have no ranges, they are similar.\n\t\tif ( numOfRangesA == 0 ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Check if each range in one selection has a similar range in other selection.\n\t\tfor ( let rangeA of this.getRanges() ) {\n\t\t\trangeA = rangeA.getTrimmed();\n\n\t\t\tlet found = false;\n\n\t\t\tfor ( let rangeB of otherSelection.getRanges() ) {\n\t\t\t\trangeB = rangeB.getTrimmed();\n\n\t\t\t\tif ( rangeA.start.isEqual( rangeB.start ) && rangeA.end.isEqual( rangeB.end ) ) {\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// For `rangeA`, neither range in `otherSelection` was similar. So selections are not similar.\n\t\t\tif ( !found ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// There were no ranges that weren't matched. Selections are similar.\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns the selected element. {@link module:engine/view/element~Element Element} is considered as selected if there is only\n\t * one range in the selection, and that range contains exactly one element.\n\t * Returns `null` if there is no selected element.\n\t *\n\t * @returns {module:engine/view/element~Element|null}\n\t */\n\tgetSelectedElement() {\n\t\tif ( this.rangeCount !== 1 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.getFirstRange().getContainedElement();\n\t}\n\n\t/**\n\t * Sets this selection's ranges and direction to the specified location based on the given\n\t * {@link module:engine/view/selection~Selectable selectable}.\n\t *\n\t *\t\t// Sets selection to the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tselection.setTo( range );\n\t *\n\t *\t\t// Sets selection to given ranges.\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tselection.setTo( range );\n\t *\n\t *\t\t// Sets selection to the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tselection.setTo( otherSelection );\n\t *\n\t *\t \t// Sets selection to contents of DocumentSelection.\n\t *\t\tselection.setTo( editor.editing.view.document.selection );\n\t *\n\t * \t\t// Sets collapsed selection at the given position.\n\t *\t\tconst position = writer.createPositionAt( root, path );\n\t *\t\tselection.setTo( position );\n\t *\n\t * \t\t// Sets collapsed selection at the position of given item and offset.\n\t *\t\tselection.setTo( paragraph, offset );\n\t *\n\t * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t *\t\tselection.setTo( paragraph, 'in' );\n\t *\n\t * Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends just after the item.\n\t *\n\t *\t\tselection.setTo( paragraph, 'on' );\n\t *\n\t * \t\t// Clears selection. Removes all ranges.\n\t *\t\tselection.setTo( null );\n\t *\n\t * `Selection#setTo()` method allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Sets selection as backward.\n\t *\t\tselection.setTo( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * (and be  properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tselection.setTo( range, { fake: true, label: 'foo' } );\n\t *\n\t * @fires change\n\t * @param {module:engine/view/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t */\n\tsetTo( selectable, placeOrOffset, options ) {\n\t\tif ( selectable === null ) {\n\t\t\tthis._setRanges( [] );\n\t\t\tthis._setFakeOptions( placeOrOffset );\n\t\t} else if ( selectable instanceof Selection || selectable instanceof DocumentSelection ) {\n\t\t\tthis._setRanges( selectable.getRanges(), selectable.isBackward );\n\t\t\tthis._setFakeOptions( { fake: selectable.isFake, label: selectable.fakeSelectionLabel } );\n\t\t} else if ( selectable instanceof Range ) {\n\t\t\tthis._setRanges( [ selectable ], placeOrOffset && placeOrOffset.backward );\n\t\t\tthis._setFakeOptions( placeOrOffset );\n\t\t} else if ( selectable instanceof Position ) {\n\t\t\tthis._setRanges( [ new Range( selectable ) ] );\n\t\t\tthis._setFakeOptions( placeOrOffset );\n\t\t} else if ( selectable instanceof Node ) {\n\t\t\tconst backward = !!options && !!options.backward;\n\t\t\tlet range;\n\n\t\t\tif ( placeOrOffset === undefined ) {\n\t\t\t\t/**\n\t\t\t\t * selection.setTo requires the second parameter when the first parameter is a node.\n\t\t\t\t *\n\t\t\t\t * @error view-selection-setto-required-second-parameter\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'view-selection-setto-required-second-parameter', this );\n\t\t\t} else if ( placeOrOffset == 'in' ) {\n\t\t\t\trange = Range._createIn( selectable );\n\t\t\t} else if ( placeOrOffset == 'on' ) {\n\t\t\t\trange = Range._createOn( selectable );\n\t\t\t} else {\n\t\t\t\trange = new Range( Position._createAt( selectable, placeOrOffset ) );\n\t\t\t}\n\n\t\t\tthis._setRanges( [ range ], backward );\n\t\t\tthis._setFakeOptions( options );\n\t\t} else if ( isIterable( selectable ) ) {\n\t\t\t// We assume that the selectable is an iterable of ranges.\n\t\t\t// Array.from() is used to prevent setting ranges to the old iterable\n\t\t\tthis._setRanges( selectable, placeOrOffset && placeOrOffset.backward );\n\t\t\tthis._setFakeOptions( placeOrOffset );\n\t\t} else {\n\t\t\t/**\n\t\t\t * Cannot set selection to given place.\n\t\t\t *\n\t\t\t * @error view-selection-setto-not-selectable\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-selection-setto-not-selectable', this );\n\t\t}\n\n\t\tthis.fire( 'change' );\n\t}\n\n\t/**\n\t * Moves {@link #focus} to the specified location.\n\t *\n\t * The location can be specified in the same form as {@link module:engine/view/view~View#createPositionAt view.createPositionAt()}\n\t * parameters.\n\t *\n\t * @fires change\n\t * @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/view/item~Item view item}.\n\t */\n\tsetFocus( itemOrPosition, offset ) {\n\t\tif ( this.anchor === null ) {\n\t\t\t/**\n\t\t\t * Cannot set selection focus if there are no ranges in selection.\n\t\t\t *\n\t\t\t * @error view-selection-setfocus-no-ranges\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-selection-setfocus-no-ranges', this );\n\t\t}\n\n\t\tconst newFocus = Position._createAt( itemOrPosition, offset );\n\n\t\tif ( newFocus.compareWith( this.focus ) == 'same' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst anchor = this.anchor;\n\n\t\tthis._ranges.pop();\n\n\t\tif ( newFocus.compareWith( anchor ) == 'before' ) {\n\t\t\tthis._addRange( new Range( newFocus, anchor ), true );\n\t\t} else {\n\t\t\tthis._addRange( new Range( anchor, newFocus ) );\n\t\t}\n\n\t\tthis.fire( 'change' );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tselection.is( 'selection' ); // -> true\n\t *\t\tselection.is( 'view:selection' ); // -> true\n\t *\n\t *\t\tselection.is( 'model:selection' ); // -> false\n\t *\t\tselection.is( 'element' ); // -> false\n\t *\t\tselection.is( 'range' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'selection' || type === 'view:selection';\n\t}\n\n\t/**\n\t * Replaces all ranges that were added to the selection with given array of ranges. Last range of the array\n\t * is treated like the last added range and is used to set {@link #anchor anchor} and {@link #focus focus}.\n\t * Accepts a flag describing in which way the selection is made.\n\t *\n\t * @private\n\t * @param {Iterable.<module:engine/view/range~Range>} newRanges Iterable object of ranges to set.\n\t * @param {Boolean} [isLastBackward=false] Flag describing if last added range was selected forward - from start to end\n\t * (`false`) or backward - from end to start (`true`). Defaults to `false`.\n\t */\n\t_setRanges( newRanges, isLastBackward = false ) {\n\t\t// New ranges should be copied to prevent removing them by setting them to `[]` first.\n\t\t// Only applies to situations when selection is set to the same selection or same selection's ranges.\n\t\tnewRanges = Array.from( newRanges );\n\n\t\tthis._ranges = [];\n\n\t\tfor ( const range of newRanges ) {\n\t\t\tthis._addRange( range );\n\t\t}\n\n\t\tthis._lastRangeBackward = !!isLastBackward;\n\t}\n\n\t/**\n\t * Sets this selection instance to be marked as `fake`. A fake selection does not render as browser native selection\n\t * over selected elements and is hidden to the user. This way, no native selection UI artifacts are displayed to\n\t * the user and selection over elements can be represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM (and be\n\t * properly handled by screen readers).\n\t *\n\t * @private\n\t * @param {Object} [options] Options.\n\t * @param {Boolean} [options.fake] If set to true selection will be marked as `fake`.\n\t * @param {String} [options.label=''] Fake selection label.\n\t */\n\t_setFakeOptions( options = {} ) {\n\t\tthis._isFake = !!options.fake;\n\t\tthis._fakeSelectionLabel = options.fake ? options.label || '' : '';\n\t}\n\n\t/**\n\t * Adds a range to the selection. Added range is copied. This means that passed range is not saved in the\n\t * selection instance and you can safely operate on it.\n\t *\n\t * Accepts a flag describing in which way the selection is made - passed range might be selected from\n\t * {@link module:engine/view/range~Range#start start} to {@link module:engine/view/range~Range#end end}\n\t * or from {@link module:engine/view/range~Range#end end} to {@link module:engine/view/range~Range#start start}.\n\t * The flag is used to set {@link #anchor anchor} and {@link #focus focus} properties.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-selection-range-intersects` if added range intersects\n\t * with ranges already stored in Selection instance.\n\t *\n\t * @private\n\t * @fires change\n\t * @param {module:engine/view/range~Range} range\n\t * @param {Boolean} [isBackward]\n\t */\n\t_addRange( range, isBackward = false ) {\n\t\tif ( !( range instanceof Range ) ) {\n\t\t\t/**\n\t\t\t * Selection range set to an object that is not an instance of {@link module:engine/view/range~Range}.\n\t\t\t *\n\t\t\t * @error view-selection-add-range-not-range\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-selection-add-range-not-range',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tthis._pushRange( range );\n\t\tthis._lastRangeBackward = !!isBackward;\n\t}\n\n\t/**\n\t * Adds range to selection - creates copy of given range so it can be safely used and modified.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-selection-range-intersects` if added range intersects\n\t * with ranges already stored in selection instance.\n\t *\n\t * @private\n\t * @param {module:engine/view/range~Range} range\n\t */\n\t_pushRange( range ) {\n\t\tfor ( const storedRange of this._ranges ) {\n\t\t\tif ( range.isIntersecting( storedRange ) ) {\n\t\t\t\t/**\n\t\t\t\t * Trying to add a range that intersects with another range from selection.\n\t\t\t\t *\n\t\t\t\t * @error view-selection-range-intersects\n\t\t\t\t * @param {module:engine/view/range~Range} addedRange Range that was added to the selection.\n\t\t\t\t * @param {module:engine/view/range~Range} intersectingRange Range from selection that intersects with `addedRange`.\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'view-selection-range-intersects',\n\t\t\t\t\tthis,\n\t\t\t\t\t{ addedRange: range, intersectingRange: storedRange }\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tthis._ranges.push( new Range( range.start, range.end ) );\n\t}\n\n\t/**\n\t * Fired whenever selection ranges are changed through {@link ~Selection Selection API}.\n\t *\n\t * @event change\n\t */\n}\n\nmix( Selection, EmitterMixin );\n\n/**\n * An entity that is used to set selection.\n *\n * See also {@link module:engine/view/selection~Selection#setTo}\n *\n * @typedef {\n *    module:engine/view/selection~Selection|\n *    module:engine/view/documentselection~DocumentSelection|\n *    module:engine/view/position~Position|\n *    Iterable.<module:engine/view/range~Range>|\n *    module:engine/view/range~Range|\n *    module:engine/view/item~Item|\n *    null\n * } module:engine/view/selection~Selectable\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/documentselection\n */\n\nimport Selection from './selection';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\n\n/**\n * Class representing the document selection in the view.\n *\n * Its instance is available in {@link module:engine/view/document~Document#selection `Document#selection`}.\n *\n * It is similar to {@link module:engine/view/selection~Selection} but\n * it has a read-only API and can be modified only by the writer available in\n * the {@link module:engine/view/view~View#change `View#change()`} block\n * (so via {@link module:engine/view/downcastwriter~DowncastWriter#setSelection `DowncastWriter#setSelection()`}).\n */\nexport default class DocumentSelection {\n\t/**\n\t * Creates new DocumentSelection instance.\n\t *\n\t * \t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = new DocumentSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tconst selection = new DocumentSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( start2, end2 ) ];\n\t *\t\tconst selection = new DocumentSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tconst selection = new DocumentSelection( otherSelection );\n\t *\n\t * \t\t// Creates selection at the given position.\n\t *\t\tconst position = writer.createPositionAt( root, offset );\n\t *\t\tconst selection = new DocumentSelection( position );\n\t *\n\t *\t\t// Creates collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = writer.createContainerElement( 'paragraph' );\n\t *\t\tconst selection = new DocumentSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = new DocumentSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = new DocumentSelection( paragraph, 'on' );\n\t *\n\t * `Selection`'s constructor allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = new DocumentSelection( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * (and be  properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tconst selection = new DocumentSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/selection~Selectable} [selectable=null]\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Offset or place when selectable is an `Item`.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t */\n\tconstructor( selectable = null, placeOrOffset, options ) {\n\t\t/**\n\t\t * Selection is used internally (`DocumentSelection` is a proxy to that selection).\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/view/selection~Selection}\n\t\t */\n\t\tthis._selection = new Selection();\n\n\t\t// Delegate change event to be fired on DocumentSelection instance.\n\t\tthis._selection.delegate( 'change' ).to( this );\n\n\t\t// Set selection data.\n\t\tthis._selection.setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Returns true if selection instance is marked as `fake`.\n\t *\n\t * @see #_setTo\n\t * @returns {Boolean}\n\t */\n\tget isFake() {\n\t\treturn this._selection.isFake;\n\t}\n\n\t/**\n\t * Returns fake selection label.\n\t *\n\t * @see #_setTo\n\t * @returns {String}\n\t */\n\tget fakeSelectionLabel() {\n\t\treturn this._selection.fakeSelectionLabel;\n\t}\n\n\t/**\n\t * Selection anchor. Anchor may be described as a position where the selection starts. Together with\n\t * {@link #focus focus} they define the direction of selection, which is important\n\t * when expanding/shrinking selection. Anchor is always the start or end of the most recent added range.\n\t * It may be a bit unintuitive when there are multiple ranges in selection.\n\t *\n\t * @see #focus\n\t * @type {module:engine/view/position~Position}\n\t */\n\tget anchor() {\n\t\treturn this._selection.anchor;\n\t}\n\n\t/**\n\t * Selection focus. Focus is a position where the selection ends.\n\t *\n\t * @see #anchor\n\t * @type {module:engine/view/position~Position}\n\t */\n\tget focus() {\n\t\treturn this._selection.focus;\n\t}\n\n\t/**\n\t * Returns whether the selection is collapsed. Selection is collapsed when there is exactly one range which is\n\t * collapsed.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\treturn this._selection.isCollapsed;\n\t}\n\n\t/**\n\t * Returns number of ranges in selection.\n\t *\n\t * @type {Number}\n\t */\n\tget rangeCount() {\n\t\treturn this._selection.rangeCount;\n\t}\n\n\t/**\n\t * Specifies whether the {@link #focus} precedes {@link #anchor}.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isBackward() {\n\t\treturn this._selection.isBackward;\n\t}\n\n\t/**\n\t * {@link module:engine/view/editableelement~EditableElement EditableElement} instance that contains this selection, or `null`\n\t * if the selection is not inside an editable element.\n\t *\n\t * @type {module:engine/view/editableelement~EditableElement|null}\n\t */\n\tget editableElement() {\n\t\treturn this._selection.editableElement;\n\t}\n\n\t/**\n\t * Used for the compatibility with the {@link module:engine/view/selection~Selection#isEqual} method.\n\t *\n\t * @protected\n\t */\n\tget _ranges() {\n\t\treturn this._selection._ranges;\n\t}\n\n\t/**\n\t * Returns an iterable that contains copies of all ranges added to the selection.\n\t *\n\t * @returns {Iterable.<module:engine/view/range~Range>}\n\t */\n\t* getRanges() {\n\t\tyield* this._selection.getRanges();\n\t}\n\n\t/**\n\t * Returns copy of the first range in the selection. First range is the one which\n\t * {@link module:engine/view/range~Range#start start} position {@link module:engine/view/position~Position#isBefore is before} start\n\t * position of all other ranges (not to confuse with the first range added to the selection).\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/range~Range|null}\n\t */\n\tgetFirstRange() {\n\t\treturn this._selection.getFirstRange();\n\t}\n\n\t/**\n\t * Returns copy of the last range in the selection. Last range is the one which {@link module:engine/view/range~Range#end end}\n\t * position {@link module:engine/view/position~Position#isAfter is after} end position of all other ranges (not to confuse\n\t * with the last range added to the selection). Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/range~Range|null}\n\t */\n\tgetLastRange() {\n\t\treturn this._selection.getLastRange();\n\t}\n\n\t/**\n\t * Returns copy of the first position in the selection. First position is the position that\n\t * {@link module:engine/view/position~Position#isBefore is before} any other position in the selection ranges.\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/position~Position|null}\n\t */\n\tgetFirstPosition() {\n\t\treturn this._selection.getFirstPosition();\n\t}\n\n\t/**\n\t * Returns copy of the last position in the selection. Last position is the position that\n\t * {@link module:engine/view/position~Position#isAfter is after} any other position in the selection ranges.\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/position~Position|null}\n\t */\n\tgetLastPosition() {\n\t\treturn this._selection.getLastPosition();\n\t}\n\n\t/**\n\t * Returns the selected element. {@link module:engine/view/element~Element Element} is considered as selected if there is only\n\t * one range in the selection, and that range contains exactly one element.\n\t * Returns `null` if there is no selected element.\n\t *\n\t * @returns {module:engine/view/element~Element|null}\n\t */\n\tgetSelectedElement() {\n\t\treturn this._selection.getSelectedElement();\n\t}\n\n\t/**\n\t * Checks whether, this selection is equal to given selection. Selections are equal if they have same directions,\n\t * same number of ranges and all ranges from one selection equal to a range from other selection.\n\t *\n\t * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} otherSelection\n\t * Selection to compare with.\n\t * @returns {Boolean} `true` if selections are equal, `false` otherwise.\n\t */\n\tisEqual( otherSelection ) {\n\t\treturn this._selection.isEqual( otherSelection );\n\t}\n\n\t/**\n\t * Checks whether this selection is similar to given selection. Selections are similar if they have same directions, same\n\t * number of ranges, and all {@link module:engine/view/range~Range#getTrimmed trimmed} ranges from one selection are\n\t * equal to any trimmed range from other selection.\n\t *\n\t * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} otherSelection\n\t * Selection to compare with.\n\t * @returns {Boolean} `true` if selections are similar, `false` otherwise.\n\t */\n\tisSimilar( otherSelection ) {\n\t\treturn this._selection.isSimilar( otherSelection );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tdocSelection.is( 'selection' ); // -> true\n\t *\t\tdocSelection.is( 'documentSelection' ); // -> true\n\t *\t\tdocSelection.is( 'view:selection' ); // -> true\n\t *\t\tdocSelection.is( 'view:documentSelection' ); // -> true\n\t *\n\t *\t\tdocSelection.is( 'model:documentSelection' ); // -> false\n\t *\t\tdocSelection.is( 'element' ); // -> false\n\t *\t\tdocSelection.is( 'node' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'selection' ||\n\t\t\ttype == 'documentSelection' ||\n\t\t\ttype == 'view:selection' ||\n\t\t\ttype == 'view:documentSelection';\n\t}\n\n\t/**\n\t * Sets this selection's ranges and direction to the specified location based on the given\n\t * {@link module:engine/view/selection~Selectable selectable}.\n\t *\n\t *\t\t// Sets selection to the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tdocumentSelection._setTo( range );\n\t *\n\t *\t\t// Sets selection to given ranges.\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( start2, end2 ) ];\n\t *\t\tdocumentSelection._setTo( range );\n\t *\n\t *\t\t// Sets selection to the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tdocumentSelection._setTo( otherSelection );\n\t *\n\t * \t\t// Sets collapsed selection at the given position.\n\t *\t\tconst position = writer.createPositionAt( root, offset );\n\t *\t\tdocumentSelection._setTo( position );\n\t *\n\t * \t\t// Sets collapsed selection at the position of given item and offset.\n\t *\t\tdocumentSelection._setTo( paragraph, offset );\n\t *\n\t * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t *\t\tdocumentSelection._setTo( paragraph, 'in' );\n\t *\n\t * Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends just after the item.\n\t *\n\t *\t\tdocumentSelection._setTo( paragraph, 'on' );\n\t *\n\t * \t\t// Clears selection. Removes all ranges.\n\t *\t\tdocumentSelection._setTo( null );\n\t *\n\t * `Selection#_setTo()` method allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Sets selection as backward.\n\t *\t\tdocumentSelection._setTo( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to des cribe fake selection in DOM\n\t * (and be  properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tdocumentSelection._setTo( range, { fake: true, label: 'foo' } );\n\t *\n\t * @protected\n\t * @fires change\n\t * @param {module:engine/view/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t */\n\t_setTo( selectable, placeOrOffset, options ) {\n\t\tthis._selection.setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Moves {@link #focus} to the specified location.\n\t *\n\t * The location can be specified in the same form as {@link module:engine/view/view~View#createPositionAt view.createPositionAt()}\n\t * parameters.\n\t *\n\t * @protected\n\t * @fires change\n\t * @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/view/item~Item view item}.\n\t */\n\t_setFocus( itemOrPosition, offset ) {\n\t\tthis._selection.setFocus( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Fired whenever selection ranges are changed through {@link ~DocumentSelection Selection API}.\n\t *\n\t * @event change\n\t */\n}\n\nmix( DocumentSelection, EmitterMixin );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/document\n */\n\nimport DocumentSelection from './documentselection';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\n\n// @if CK_DEBUG_ENGINE // const { logDocument } = require( '../dev-utils/utils' );\n\n/**\n * Document class creates an abstract layer over the content editable area, contains a tree of view elements and\n * {@link module:engine/view/documentselection~DocumentSelection view selection} associated with this document.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Document {\n\t/**\n\t * Creates a Document instance.\n\t *\n\t * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor The styles processor instance.\n\t */\n\tconstructor( stylesProcessor ) {\n\t\t/**\n\t\t * Selection done on this document.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/documentselection~DocumentSelection} module:engine/view/document~Document#selection\n\t\t */\n\t\tthis.selection = new DocumentSelection();\n\n\t\t/**\n\t\t * Roots of the view tree. Collection of the {@link module:engine/view/element~Element view elements}.\n\t\t *\n\t\t * View roots are created as a result of binding between {@link module:engine/view/document~Document#roots} and\n\t\t * {@link module:engine/model/document~Document#roots} and this is handled by\n\t\t * {@link module:engine/controller/editingcontroller~EditingController}, so to create view root we need to create\n\t\t * model root using {@link module:engine/model/document~Document#createRoot}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/collection~Collection} module:engine/view/document~Document#roots\n\t\t */\n\t\tthis.roots = new Collection( { idProperty: 'rootName' } );\n\n\t\t/**\n\t\t * The styles processor instance used by this document when normalizing styles.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/stylesmap~StylesProcessor}\n\t\t */\n\t\tthis.stylesProcessor = stylesProcessor;\n\n\t\t/**\n\t\t * Defines whether document is in read-only mode.\n\t\t *\n\t\t * When document is read-ony then all roots are read-only as well and caret placed inside this root is hidden.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isReadOnly\n\t\t */\n\t\tthis.set( 'isReadOnly', false );\n\n\t\t/**\n\t\t * True if document is focused.\n\t\t *\n\t\t * This property is updated by the {@link module:engine/view/observer/focusobserver~FocusObserver}.\n\t\t * If the {@link module:engine/view/observer/focusobserver~FocusObserver} is disabled this property will not change.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} module:engine/view/document~Document#isFocused\n\t\t */\n\t\tthis.set( 'isFocused', false );\n\n\t\t/**\n\t\t * True if composition is in progress inside the document.\n\t\t *\n\t\t * This property is updated by the {@link module:engine/view/observer/compositionobserver~CompositionObserver}.\n\t\t * If the {@link module:engine/view/observer/compositionobserver~CompositionObserver} is disabled this property will not change.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} module:engine/view/document~Document#isComposing\n\t\t */\n\t\tthis.set( 'isComposing', false );\n\n\t\t/**\n\t\t * Post-fixer callbacks registered to the view document.\n\t\t *\n\t\t * @private\n\t\t * @member {Set}\n\t\t */\n\t\tthis._postFixers = new Set();\n\t}\n\n\t/**\n\t * Gets a {@link module:engine/view/document~Document#roots view root element} with the specified name. If the name is not\n\t * specific \"main\" root is returned.\n\t *\n\t * @param {String} [name='main'] Name of the root.\n\t * @returns {module:engine/view/rooteditableelement~RootEditableElement|null} The view root element with the specified name\n\t * or null when there is no root of given name.\n\t */\n\tgetRoot( name = 'main' ) {\n\t\treturn this.roots.get( name );\n\t}\n\n\t/**\n\t * Allows registering post-fixer callbacks. A post-fixers mechanism allows to update the view tree just before it is rendered\n\t * to the DOM.\n\t *\n\t * Post-fixers are executed right after all changes from the outermost change block were applied but\n\t * before the {@link module:engine/view/view~View#event:render render event} is fired. If a post-fixer callback made\n\t * a change, it should return `true`. When this happens, all post-fixers are fired again to check if something else should\n\t * not be fixed in the new document tree state.\n\t *\n\t * View post-fixers are useful when you want to apply some fixes whenever the view structure changes. Keep in mind that\n\t * changes executed in a view post-fixer should not break model-view mapping.\n\t *\n\t * The types of changes which should be safe:\n\t *\n\t * * adding or removing attribute from elements,\n\t * * changes inside of {@link module:engine/view/uielement~UIElement UI elements},\n\t * * {@link module:engine/model/differ~Differ#refreshItem marking some of the model elements to be re-converted}.\n\t *\n\t * Try to avoid changes which touch view structure:\n\t *\n\t * * you should not add or remove nor wrap or unwrap any view elements,\n\t * * you should not change the editor data model in a view post-fixer.\n\t *\n\t * As a parameter, a post-fixer callback receives a {@link module:engine/view/downcastwriter~DowncastWriter downcast writer}.\n\t *\n\t * Typically, a post-fixer will look like this:\n\t *\n\t *\t\teditor.editing.view.document.registerPostFixer( writer => {\n\t *\t\t\tif ( checkSomeCondition() ) {\n\t *\t\t\t\twriter.doSomething();\n\t *\n\t *\t\t\t\t// Let other post-fixers know that something changed.\n\t *\t\t\t\treturn true;\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * Note that nothing happens right after you register a post-fixer (e.g. execute such a code in the console).\n\t * That is because adding a post-fixer does not execute it.\n\t * The post-fixer will be executed as soon as any change in the document needs to cause its rendering.\n\t * If you want to re-render the editor's view after registering the post-fixer then you should do it manually by calling\n\t * {@link module:engine/view/view~View#forceRender `view.forceRender()`}.\n\t *\n\t * If you need to register a callback which is executed when DOM elements are already updated,\n\t * use {@link module:engine/view/view~View#event:render render event}.\n\t *\n\t * @param {Function} postFixer\n\t */\n\tregisterPostFixer( postFixer ) {\n\t\tthis._postFixers.add( postFixer );\n\t}\n\n\t/**\n\t * Destroys this instance. Makes sure that all observers are destroyed and listeners removed.\n\t */\n\tdestroy() {\n\t\tthis.roots.map( root => root.destroy() );\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Performs post-fixer loops. Executes post-fixer callbacks as long as none of them has done any changes to the model.\n\t *\n\t * @protected\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n\t */\n\t_callPostFixers( writer ) {\n\t\tlet wasFixed = false;\n\n\t\tdo {\n\t\t\tfor ( const callback of this._postFixers ) {\n\t\t\t\twasFixed = callback( writer );\n\n\t\t\t\tif ( wasFixed ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} while ( wasFixed );\n\t}\n\n\t/**\n\t * Event fired whenever document content layout changes. It is fired whenever content is\n\t * {@link module:engine/view/view~View#event:render rendered}, but should be also fired by observers in case of\n\t * other actions which may change layout, for instance when image loads.\n\t *\n\t * @event layoutChanged\n\t */\n\n\t// @if CK_DEBUG_ENGINE // log( version ) {\n\t// @if CK_DEBUG_ENGINE //\tlogDocument( this, version );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\nmix( Document, ObservableMixin );\n\n/**\n * Enum representing type of the change.\n *\n * Possible values:\n *\n * * `children` - for child list changes,\n * * `attributes` - for element attributes changes,\n * * `text` - for text nodes changes.\n *\n * @typedef {String} module:engine/view/document~ChangeType\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/attributeelement\n */\n\nimport Element from './element';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n// Default attribute priority.\nconst DEFAULT_PRIORITY = 10;\n\n/**\n * Attribute elements are used to represent formatting elements in the view (think – `<b>`, `<span style=\"font-size: 2em\">`, etc.).\n * Most often they are created when downcasting model text attributes.\n *\n * Editing engine does not define a fixed HTML DTD. This is why a feature developer needs to choose between various\n * types (container element, {@link module:engine/view/attributeelement~AttributeElement attribute element},\n * {@link module:engine/view/emptyelement~EmptyElement empty element}, etc) when developing a feature.\n *\n * To create a new attribute element instance use the\n * {@link module:engine/view/downcastwriter~DowncastWriter#createAttributeElement `DowncastWriter#createAttributeElement()`} method.\n *\n * @extends module:engine/view/element~Element\n */\nexport default class AttributeElement extends Element {\n\t/**\n\t * Creates an attribute element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#createAttributeElement\n\t * @see module:engine/view/element~Element\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document instance to which this element belongs.\n\t * @param {String} name Node name.\n\t * @param {Object|Iterable} [attrs] Collection of attributes.\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into created element.\n\t */\n\tconstructor( document, name, attrs, children ) {\n\t\tsuper( document, name, attrs, children );\n\n\t\t/**\n\t\t * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.\n\t\t *\n\t\t * @method #getFillerOffset\n\t\t * @returns {Number|null} Block filler offset or `null` if block filler is not needed.\n\t\t */\n\t\tthis.getFillerOffset = getFillerOffset;\n\n\t\t/**\n\t\t * Element priority. Decides in what order elements are wrapped by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t\t *\n\t\t * @protected\n\t\t * @member {Number}\n\t\t */\n\t\tthis._priority = DEFAULT_PRIORITY;\n\n\t\t/**\n\t\t * Element identifier. If set, it is used by {@link module:engine/view/element~Element#isSimilar},\n\t\t * and then two elements are considered similar if, and only if they have the same `_id`.\n\t\t *\n\t\t * @protected\n\t\t * @member {String|Number}\n\t\t */\n\t\tthis._id = null;\n\n\t\t/**\n\t\t * Keeps all the attribute elements that have the same {@link module:engine/view/attributeelement~AttributeElement#id ids}\n\t\t * and still exist in the view tree.\n\t\t *\n\t\t * This property is managed by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t\t *\n\t\t * @protected\n\t\t * @member {Set.<module:engine/view/attributeelement~AttributeElement>|null}\n\t\t */\n\t\tthis._clonesGroup = null;\n\t}\n\n\t/**\n\t * Element priority. Decides in what order elements are wrapped by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget priority() {\n\t\treturn this._priority;\n\t}\n\n\t/**\n\t * Element identifier. If set, it is used by {@link module:engine/view/element~Element#isSimilar},\n\t * and then two elements are considered similar if, and only if they have the same `id`.\n\t *\n\t * @readonly\n\t * @type {String|Number}\n\t */\n\tget id() {\n\t\treturn this._id;\n\t}\n\n\t/**\n\t * Returns all {@link module:engine/view/attributeelement~AttributeElement attribute elements} that has the\n\t * same {@link module:engine/view/attributeelement~AttributeElement#id id} and are in the view tree (were not removed).\n\t *\n\t * Note: If this element has been removed from the tree, returned set will not include it.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError attribute-element-get-elements-with-same-id-no-id}\n\t * if this element has no `id`.\n\t *\n\t * @returns {Set.<module:engine/view/attributeelement~AttributeElement>} Set containing all the attribute elements\n\t * with the same `id` that were added and not removed from the view tree.\n\t */\n\tgetElementsWithSameId() {\n\t\tif ( this.id === null ) {\n\t\t\t/**\n\t\t\t * Cannot get elements with the same id for an attribute element without id.\n\t\t\t *\n\t\t\t * @error attribute-element-get-elements-with-same-id-no-id\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'attribute-element-get-elements-with-same-id-no-id',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\treturn new Set( this._clonesGroup );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tattributeElement.is( 'attributeElement' ); // -> true\n\t *\t\tattributeElement.is( 'element' ); // -> true\n\t *\t\tattributeElement.is( 'node' ); // -> true\n\t *\t\tattributeElement.is( 'view:attributeElement' ); // -> true\n\t *\t\tattributeElement.is( 'view:element' ); // -> true\n\t *\t\tattributeElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\tattributeElement.is( 'model:element' ); // -> false\n\t *\t\tattributeElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is an attribute element, you can also check its\n\t * {@link module:engine/view/attributeelement~AttributeElement#name name}:\n\t *\n\t *\t\tattributeElement.is( 'element', 'b' ); // -> true if this is a bold element\n\t *\t\tattributeElement.is( 'attributeElement', 'b' ); // -> same as above\n\t *\t\ttext.is( 'element', 'b' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'attributeElement' || type === 'view:attributeElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'element' || type === 'view:element' ||\n\t\t\t\ttype === 'node' || type === 'view:node';\n\t\t} else {\n\t\t\treturn name === this.name && (\n\t\t\t\ttype === 'attributeElement' || type === 'view:attributeElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'element' || type === 'view:element'\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Checks if this element is similar to other element.\n\t *\n\t * If none of elements has set {@link module:engine/view/attributeelement~AttributeElement#id}, then both elements\n\t * should have the same name, attributes and priority to be considered as similar. Two similar elements can contain\n\t * different set of children nodes.\n\t *\n\t * If at least one element has {@link module:engine/view/attributeelement~AttributeElement#id} set, then both\n\t * elements have to have the same {@link module:engine/view/attributeelement~AttributeElement#id} value to be\n\t * considered similar.\n\t *\n\t * Similarity is important for {@link module:engine/view/downcastwriter~DowncastWriter}. For example:\n\t *\n\t * * two following similar elements can be merged together into one, longer element,\n\t * * {@link module:engine/view/downcastwriter~DowncastWriter#unwrap} checks similarity of passed element and processed element to\n\t * decide whether processed element should be unwrapped,\n\t * * etc.\n\t *\n\t * @param {module:engine/view/element~Element} otherElement\n\t * @returns {Boolean}\n\t */\n\tisSimilar( otherElement ) {\n\t\t// If any element has an `id` set, just compare the ids.\n\t\tif ( this.id !== null || otherElement.id !== null ) {\n\t\t\treturn this.id === otherElement.id;\n\t\t}\n\n\t\treturn super.isSimilar( otherElement ) && this.priority == otherElement.priority;\n\t}\n\n\t/**\n\t * Clones provided element with priority.\n\t *\n\t * @protected\n\t * @param {Boolean} deep If set to `true` clones element and all its children recursively. When set to `false`,\n\t * element will be cloned without any children.\n\t * @returns {module:engine/view/attributeelement~AttributeElement} Clone of this element.\n\t */\n\t_clone( deep ) {\n\t\tconst cloned = super._clone( deep );\n\n\t\t// Clone priority too.\n\t\tcloned._priority = this._priority;\n\n\t\t// And id too.\n\t\tcloned._id = this._id;\n\n\t\treturn cloned;\n\t}\n}\n\n/**\n * Default attribute priority.\n *\n * @member {Number} module:engine/view/attributeelement~AttributeElement.DEFAULT_PRIORITY\n */\nAttributeElement.DEFAULT_PRIORITY = DEFAULT_PRIORITY;\n\n// Returns block {@link module:engine/view/filler~Filler filler} offset or `null` if block filler is not needed.\n//\n// @returns {Number|null} Block filler offset or `null` if block filler is not needed.\nfunction getFillerOffset() {\n\t// <b>foo</b> does not need filler.\n\tif ( nonUiChildrenCount( this ) ) {\n\t\treturn null;\n\t}\n\n\tlet element = this.parent;\n\n\t// <p><b></b></p> needs filler -> <p><b><br></b></p>\n\twhile ( element && element.is( 'attributeElement' ) ) {\n\t\tif ( nonUiChildrenCount( element ) > 1 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\telement = element.parent;\n\t}\n\n\tif ( !element || nonUiChildrenCount( element ) > 1 ) {\n\t\treturn null;\n\t}\n\n\t// Render block filler at the end of element (after all ui elements).\n\treturn this.childCount;\n}\n\n// Returns total count of children that are not {@link module:engine/view/uielement~UIElement UIElements}.\n//\n// @param {module:engine/view/element~Element} element\n// @returns {Number}\nfunction nonUiChildrenCount( element ) {\n\treturn Array.from( element.getChildren() ).filter( element => !element.is( 'uiElement' ) ).length;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/emptyelement\n */\n\nimport Element from './element';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport Node from './node';\n\n/**\n * Empty element class. It is used to represent elements that cannot contain any child nodes (for example `<img>` elements).\n *\n * To create a new empty element use the\n * {@link module:engine/view/downcastwriter~DowncastWriter#createEmptyElement `downcastWriter#createEmptyElement()`} method.\n *\n * @extends module:engine/view/element~Element\n */\nexport default class EmptyElement extends Element {\n\t/**\n\t * Creates new instance of EmptyElement.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-emptyelement-cannot-add` when third parameter is passed,\n\t * to inform that usage of EmptyElement is incorrect (adding child nodes to EmptyElement is forbidden).\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#createEmptyElement\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document instance to which this element belongs.\n\t * @param {String} name Node name.\n\t * @param {Object|Iterable} [attrs] Collection of attributes.\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into created element.\n\t */\n\tconstructor( document, name, attrs, children ) {\n\t\tsuper( document, name, attrs, children );\n\n\t\t/**\n\t\t * Returns `null` because filler is not needed for EmptyElements.\n\t\t *\n\t\t * @method #getFillerOffset\n\t\t * @returns {null} Always returns null.\n\t\t */\n\t\tthis.getFillerOffset = getFillerOffset;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\temptyElement.is( 'emptyElement' ); // -> true\n\t *\t\temptyElement.is( 'element' ); // -> true\n\t *\t\temptyElement.is( 'node' ); // -> true\n\t *\t\temptyElement.is( 'view:emptyElement' ); // -> true\n\t *\t\temptyElement.is( 'view:element' ); // -> true\n\t *\t\temptyElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\temptyElement.is( 'model:element' ); // -> false\n\t *\t\temptyElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is an empty element, you can also check its\n\t * {@link module:engine/view/emptyelement~EmptyElement#name name}:\n\t *\n\t *\t\temptyElement.is( 'element', 'img' ); // -> true if this is a img element\n\t *\t\temptyElement.is( 'emptyElement', 'img' ); // -> same as above\n\t *\t\ttext.is( 'element', 'img' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'emptyElement' || type === 'view:emptyElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'element' || type === 'view:element' ||\n\t\t\t\ttype === 'node' || type === 'view:node';\n\t\t} else {\n\t\t\treturn name === this.name && (\n\t\t\t\ttype === 'emptyElement' || type === 'view:emptyElement' ||\n\t\t\t\ttype === 'element' || type === 'view:element'\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Overrides {@link module:engine/view/element~Element#_insertChild} method.\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-emptyelement-cannot-add` to prevent\n\t * adding any child nodes to EmptyElement.\n\t *\n\t * @protected\n\t */\n\t_insertChild( index, nodes ) {\n\t\tif ( nodes && ( nodes instanceof Node || Array.from( nodes ).length > 0 ) ) {\n\t\t\t/**\n\t\t\t * Cannot add children to {@link module:engine/view/emptyelement~EmptyElement}.\n\t\t\t *\n\t\t\t * @error view-emptyelement-cannot-add\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-emptyelement-cannot-add',\n\t\t\t\t[ this, nodes ]\n\t\t\t);\n\t\t}\n\t}\n}\n\n// Returns `null` because block filler is not needed for EmptyElements.\n//\n// @returns {null}\nfunction getFillerOffset() {\n\treturn null;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* globals navigator:false */\n\n/**\n * @module utils/env\n */\n\nconst userAgent = navigator.userAgent.toLowerCase();\n\n/**\n * A namespace containing environment and browser information.\n *\n * @namespace\n */\nconst env = {\n\t/**\n\t * Indicates that the application is running on Macintosh.\n\t *\n\t * @static\n\t * @type {Boolean}\n\t */\n\tisMac: isMac( userAgent ),\n\n\t/**\n\t * Indicates that the application is running in Firefox (Gecko).\n\t *\n\t * @static\n\t * @type {Boolean}\n\t */\n\tisGecko: isGecko( userAgent ),\n\n\t/**\n\t * Indicates that the application is running in Safari.\n\t *\n\t * @static\n\t * @type {Boolean}\n\t */\n\tisSafari: isSafari( userAgent ),\n\n\t/**\n\t * Indicates that the application is running on Android mobile device.\n\t *\n\t * @static\n\t * @type {Boolean}\n\t */\n\tisAndroid: isAndroid( userAgent ),\n\n\t/**\n\t * Indicates that the application is running in a browser using the Blink engine.\n\t *\n\t * @static\n\t * @type {Boolean}\n\t */\n\tisBlink: isBlink( userAgent ),\n\n\t/**\n\t * Environment features information.\n\t *\n\t * @memberOf module:utils/env~env\n\t * @namespace\n\t */\n\tfeatures: {\n\t\t/**\n\t\t * Indicates that the environment supports ES2018 Unicode property escapes — like `\\p{P}` or `\\p{L}`.\n\t\t * More information about unicode properties might be found\n\t\t * [in Unicode Standard Annex #44](https://www.unicode.org/reports/tr44/#GC_Values_Table).\n\t\t *\n\t\t * @type {Boolean}\n\t\t */\n\t\tisRegExpUnicodePropertySupported: isRegExpUnicodePropertySupported()\n\t}\n};\n\nexport default env;\n\n/**\n * Checks if User Agent represented by the string is running on Macintosh.\n *\n * @param {String} userAgent **Lowercase** `navigator.userAgent` string.\n * @returns {Boolean} Whether User Agent is running on Macintosh or not.\n */\nexport function isMac( userAgent ) {\n\treturn userAgent.indexOf( 'macintosh' ) > -1;\n}\n\n/**\n * Checks if User Agent represented by the string is Firefox (Gecko).\n *\n * @param {String} userAgent **Lowercase** `navigator.userAgent` string.\n * @returns {Boolean} Whether User Agent is Firefox or not.\n */\nexport function isGecko( userAgent ) {\n\treturn !!userAgent.match( /gecko\\/\\d+/ );\n}\n\n/**\n * Checks if User Agent represented by the string is Safari.\n *\n * @param {String} userAgent **Lowercase** `navigator.userAgent` string.\n * @returns {Boolean} Whether User Agent is Safari or not.\n */\nexport function isSafari( userAgent ) {\n\treturn userAgent.indexOf( ' applewebkit/' ) > -1 && userAgent.indexOf( 'chrome' ) === -1;\n}\n\n/**\n * Checks if User Agent represented by the string is Android mobile device.\n *\n * @param {String} userAgent **Lowercase** `navigator.userAgent` string.\n * @returns {Boolean} Whether User Agent is Safari or not.\n */\nexport function isAndroid( userAgent ) {\n\treturn userAgent.indexOf( 'android' ) > -1;\n}\n\n/**\n * Checks if User Agent represented by the string is Blink engine.\n *\n * @param {String} userAgent **Lowercase** `navigator.userAgent` string.\n * @returns {Boolean} Whether User Agent is Blink engine or not.\n */\nexport function isBlink( userAgent ) {\n\t// The Edge browser before switching to the Blink engine used to report itself as Chrome (and \"Edge/\")\n\t// but after switching to the Blink it replaced \"Edge/\" with \"Edg/\".\n\treturn userAgent.indexOf( 'chrome/' ) > -1 && userAgent.indexOf( 'edge/' ) < 0;\n}\n\n/**\n * Checks if the current environment supports ES2018 Unicode properties like `\\p{P}` or `\\p{L}`.\n * More information about unicode properties might be found\n * [in Unicode Standard Annex #44](https://www.unicode.org/reports/tr44/#GC_Values_Table).\n *\n * @returns {Boolean}\n */\nexport function isRegExpUnicodePropertySupported() {\n\tlet isSupported = false;\n\n\t// Feature detection for Unicode properties. Added in ES2018. Currently Firefox does not support it.\n\t// See https://github.com/ckeditor/ckeditor5-mention/issues/44#issuecomment-487002174.\n\n\ttry {\n\t\t// Usage of regular expression literal cause error during build (ckeditor/ckeditor5-dev#534).\n\t\tisSupported = 'ć'.search( new RegExp( '[\\\\p{L}]', 'u' ) ) === 0;\n\t} catch ( error ) {\n\t\t// Firefox throws a SyntaxError when the group is unsupported.\n\t}\n\n\treturn isSupported;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * Set of utils related to keyboard support.\n *\n * @module utils/keyboard\n */\n\nimport CKEditorError from './ckeditorerror';\nimport env from './env';\n\nconst macGlyphsToModifiers = {\n\t'⌘': 'ctrl',\n\t'⇧': 'shift',\n\t'⌥': 'alt'\n};\n\nconst modifiersToMacGlyphs = {\n\t'ctrl': '⌘',\n\t'shift': '⇧',\n\t'alt': '⌥'\n};\n\n/**\n * Object with `keyName => keyCode` pairs for a set of known keys.\n *\n * Contains:\n *\n * * `a-z`,\n * * `0-9`,\n * * `f1-f12`,\n * * `arrow(left|up|right|bottom)`,\n * * `backspace`, `delete`, `enter`, `esc`, `tab`,\n * * `ctrl`, `cmd`, `shift`, `alt`.\n */\nexport const keyCodes = generateKnownKeyCodes();\n\n/**\n * Converts a key name or a {@link module:utils/keyboard~KeystrokeInfo keystroke info} into a key code.\n *\n * Note: Key names are matched with {@link module:utils/keyboard~keyCodes} in a case-insensitive way.\n *\n * @param {String|module:utils/keyboard~KeystrokeInfo} Key name (see {@link module:utils/keyboard~keyCodes})\n * or a keystroke data object.\n * @returns {Number} Key or keystroke code.\n */\nexport function getCode( key ) {\n\tlet keyCode;\n\n\tif ( typeof key == 'string' ) {\n\t\tkeyCode = keyCodes[ key.toLowerCase() ];\n\n\t\tif ( !keyCode ) {\n\t\t\t/**\n\t\t\t * Unknown key name. Only key names contained by the {@link module:utils/keyboard~keyCodes} can be used.\n\t\t\t *\n\t\t\t * @error keyboard-unknown-key\n\t\t\t * @param {String} key\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'keyboard-unknown-key', null, { key } );\n\t\t}\n\t} else {\n\t\tkeyCode = key.keyCode +\n\t\t\t( key.altKey ? keyCodes.alt : 0 ) +\n\t\t\t( key.ctrlKey ? keyCodes.ctrl : 0 ) +\n\t\t\t( key.shiftKey ? keyCodes.shift : 0 );\n\t}\n\n\treturn keyCode;\n}\n\n/**\n * Parses keystroke and returns a keystroke code that will match the code returned by\n * link {@link module:utils/keyboard~getCode} for a corresponding {@link module:utils/keyboard~KeystrokeInfo keystroke info}.\n *\n * The keystroke can be passed in two formats:\n *\n * * as a single string – e.g. `ctrl + A`,\n * * as an array of {@link module:utils/keyboard~keyCodes known key names} and key codes – e.g.:\n *   * `[ 'ctrl', 32 ]` (ctrl + space),\n *   * `[ 'ctrl', 'a' ]` (ctrl + A).\n *\n * Note: Key names are matched with {@link module:utils/keyboard~keyCodes} in a case-insensitive way.\n *\n * Note: Only keystrokes with a single non-modifier key are supported (e.g. `ctrl+A` is OK, but `ctrl+A+B` is not).\n *\n * @param {String|Array.<Number|String>} keystroke Keystroke definition.\n * @returns {Number} Keystroke code.\n */\nexport function parseKeystroke( keystroke ) {\n\tif ( typeof keystroke == 'string' ) {\n\t\tkeystroke = splitKeystrokeText( keystroke );\n\t}\n\n\treturn keystroke\n\t\t.map( key => ( typeof key == 'string' ) ? getCode( key ) : key )\n\t\t.reduce( ( key, sum ) => sum + key, 0 );\n}\n\n/**\n * It translates any keystroke string text like `\"CTRL+A\"` to an\n * environment–specific keystroke, i.e. `\"⌘A\"` on Mac OSX.\n *\n * @param {String} keystroke Keystroke text.\n * @returns {String} Keystroke text specific for the environment.\n */\nexport function getEnvKeystrokeText( keystroke ) {\n\tif ( !env.isMac ) {\n\t\treturn keystroke;\n\t}\n\n\treturn splitKeystrokeText( keystroke )\n\t\t// Replace modifiers (e.g. \"ctrl\") with Mac glyphs (e.g. \"⌘\") first.\n\t\t.map( key => modifiersToMacGlyphs[ key.toLowerCase() ] || key )\n\n\t\t// Decide whether to put \"+\" between keys in the keystroke or not.\n\t\t.reduce( ( value, key ) => {\n\t\t\tif ( value.slice( -1 ) in macGlyphsToModifiers ) {\n\t\t\t\treturn value + key;\n\t\t\t} else {\n\t\t\t\treturn value + '+' + key;\n\t\t\t}\n\t\t} );\n}\n\n/**\n * Returns `true` if the provided key code represents one of the arrow keys.\n *\n * @param {Number} keyCode A key code as in {@link module:utils/keyboard~KeystrokeInfo#keyCode}.\n * @returns {Boolean}\n */\nexport function isArrowKeyCode( keyCode ) {\n\treturn keyCode == keyCodes.arrowright ||\n\t\tkeyCode == keyCodes.arrowleft ||\n\t\tkeyCode == keyCodes.arrowup ||\n\t\tkeyCode == keyCodes.arrowdown;\n}\n\n/**\n * Returns the direction in which the {@link module:engine/model/documentselection~DocumentSelection selection}\n * will move when a provided arrow key code is pressed considering the language direction of the editor content.\n *\n * For instance, in right–to–left (RTL) content languages, pressing the left arrow means moving selection right (forward)\n * in the model structure. Similarly, pressing the right arrow moves the selection left (backward).\n *\n * @param {Number} keyCode A key code as in {@link module:utils/keyboard~KeystrokeInfo#keyCode}.\n * @param {'ltr'|'rtl'} contentLanguageDirection The content language direction, corresponding to\n * {@link module:utils/locale~Locale#contentLanguageDirection}.\n * @returns {'left'|'up'|'right'|'down'} Localized arrow direction.\n */\nexport function getLocalizedArrowKeyCodeDirection( keyCode, contentLanguageDirection ) {\n\tconst isLtrContent = contentLanguageDirection === 'ltr';\n\n\tswitch ( keyCode ) {\n\t\tcase keyCodes.arrowleft:\n\t\t\treturn isLtrContent ? 'left' : 'right';\n\n\t\tcase keyCodes.arrowright:\n\t\t\treturn isLtrContent ? 'right' : 'left';\n\n\t\tcase keyCodes.arrowup:\n\t\t\treturn 'up';\n\n\t\tcase keyCodes.arrowdown:\n\t\t\treturn 'down';\n\t}\n}\n\n/**\n * Determines if the provided key code moves the {@link module:engine/model/documentselection~DocumentSelection selection}\n * forward or backward considering the language direction of the editor content.\n *\n * For instance, in right–to–left (RTL) languages, pressing the left arrow means moving forward\n * in the model structure. Similarly, pressing the right arrow moves the selection backward.\n *\n * @param {Number} keyCode A key code as in {@link module:utils/keyboard~KeystrokeInfo#keyCode}.\n * @param {'ltr'|'rtl'} contentLanguageDirection The content language direction, corresponding to\n * {@link module:utils/locale~Locale#contentLanguageDirection}.\n * @returns {Boolean}\n */\nexport function isForwardArrowKeyCode( keyCode, contentLanguageDirection ) {\n\tconst localizedKeyCodeDirection = getLocalizedArrowKeyCodeDirection( keyCode, contentLanguageDirection );\n\n\treturn localizedKeyCodeDirection === 'down' || localizedKeyCodeDirection === 'right';\n}\n\nfunction generateKnownKeyCodes() {\n\tconst keyCodes = {\n\t\tarrowleft: 37,\n\t\tarrowup: 38,\n\t\tarrowright: 39,\n\t\tarrowdown: 40,\n\t\tbackspace: 8,\n\t\tdelete: 46,\n\t\tenter: 13,\n\t\tspace: 32,\n\t\tesc: 27,\n\t\ttab: 9,\n\n\t\t// The idea about these numbers is that they do not collide with any real key codes, so we can use them\n\t\t// like bit masks.\n\t\tctrl: 0x110000,\n\t\t// Has the same code as ctrl, because their behaviour should be unified across the editor.\n\t\t// See http://ckeditor.github.io/editor-recommendations/general-policies#ctrl-vs-cmd\n\t\tcmd: 0x110000,\n\t\tshift: 0x220000,\n\t\talt: 0x440000\n\t};\n\n\t// a-z\n\tfor ( let code = 65; code <= 90; code++ ) {\n\t\tconst letter = String.fromCharCode( code );\n\n\t\tkeyCodes[ letter.toLowerCase() ] = code;\n\t}\n\n\t// 0-9\n\tfor ( let code = 48; code <= 57; code++ ) {\n\t\tkeyCodes[ code - 48 ] = code;\n\t}\n\n\t// F1-F12\n\tfor ( let code = 112; code <= 123; code++ ) {\n\t\tkeyCodes[ 'f' + ( code - 111 ) ] = code;\n\t}\n\n\treturn keyCodes;\n}\n\nfunction splitKeystrokeText( keystroke ) {\n\treturn keystroke.split( /\\s*\\+\\s*/ );\n}\n\n/**\n * Information about a keystroke.\n *\n * @interface module:utils/keyboard~KeystrokeInfo\n */\n\n/**\n * The [key code](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode).\n *\n * @member {Number} module:utils/keyboard~KeystrokeInfo#keyCode\n */\n\n/**\n * Whether the <kbd>Alt</kbd> modifier was pressed.\n *\n * @member {Bolean} module:utils/keyboard~KeystrokeInfo#altKey\n */\n\n/**\n * Whether the <kbd>Ctrl</kbd> or <kbd>Cmd</kbd> modifier was pressed.\n *\n * @member {Bolean} module:utils/keyboard~KeystrokeInfo#ctrlKey\n */\n\n/**\n * Whether the <kbd>Shift</kbd> modifier was pressed.\n *\n * @member {Bolean} module:utils/keyboard~KeystrokeInfo#shiftKey\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/uielement\n */\n\nimport Element from './element';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport Node from './node';\nimport { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';\n\n/**\n * UI element class. It should be used to represent editing UI which needs to be injected into the editing view\n * If possible, you should keep your UI outside the editing view. However, if that is not possible,\n * UI elements can be used.\n *\n * How a UI element is rendered is in your control (you pass a callback to\n * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement `downcastWriter#createUIElement()`}).\n * The editor will ignore your UI element – the selection cannot be placed in it, it is skipped (invisible) when\n * the user modifies the selection by using arrow keys and the editor does not listen to any mutations which\n * happen inside your UI elements.\n *\n * The limitation is that you cannot convert a model element to a UI element. UI elements need to be\n * created for {@link module:engine/model/markercollection~Marker markers} or as additinal elements\n * inside normal {@link module:engine/view/containerelement~ContainerElement container elements}.\n *\n * To create a new UI element use the\n * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement `downcastWriter#createUIElement()`} method.\n *\n * @extends module:engine/view/element~Element\n */\nexport default class UIElement extends Element {\n\t/**\n\t * Creates new instance of UIElement.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-uielement-cannot-add` when third parameter is passed,\n\t * to inform that usage of UIElement is incorrect (adding child nodes to UIElement is forbidden).\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#createUIElement\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document instance to which this element belongs.\n\t * @param {String} name Node name.\n\t * @param {Object|Iterable} [attributes] Collection of attributes.\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into created element.\n\t */\n\tconstructor( document, name, attributes, children ) {\n\t\tsuper( document, name, attributes, children );\n\n\t\t/**\n\t\t * Returns `null` because filler is not needed for UIElements.\n\t\t *\n\t\t * @method #getFillerOffset\n\t\t * @returns {null} Always returns null.\n\t\t */\n\t\tthis.getFillerOffset = getFillerOffset;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tuiElement.is( 'uiElement' ); // -> true\n\t *\t\tuiElement.is( 'element' ); // -> true\n\t *\t\tuiElement.is( 'node' ); // -> true\n\t *\t\tuiElement.is( 'view:uiElement' ); // -> true\n\t *\t\tuiElement.is( 'view:element' ); // -> true\n\t *\t\tuiElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\tuiElement.is( 'model:element' ); // -> false\n\t *\t\tuiElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is an ui element, you can also check its\n\t * {@link module:engine/view/uielement~UIElement#name name}:\n\t *\n\t *\t\tuiElement.is( 'element', 'span' ); // -> true if this is a span ui element\n\t *\t\tuiElement.is( 'uiElement', 'span' ); // -> same as above\n\t *\t\ttext.is( 'element', 'span' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'uiElement' || type === 'view:uiElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'element' || type === 'view:element' ||\n\t\t\t\ttype === 'node' || type === 'view:node';\n\t\t} else {\n\t\t\treturn name === this.name && (\n\t\t\t\ttype === 'uiElement' || type === 'view:uiElement' ||\n\t\t\t\ttype === 'element' || type === 'view:element'\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Overrides {@link module:engine/view/element~Element#_insertChild} method.\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-uielement-cannot-add` to prevent adding any child nodes\n\t * to UIElement.\n\t *\n\t * @protected\n\t */\n\t_insertChild( index, nodes ) {\n\t\tif ( nodes && ( nodes instanceof Node || Array.from( nodes ).length > 0 ) ) {\n\t\t\t/**\n\t\t\t * Cannot add children to {@link module:engine/view/uielement~UIElement}.\n\t\t\t *\n\t\t\t * @error view-uielement-cannot-add\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-uielement-cannot-add', this );\n\t\t}\n\t}\n\n\t/**\n\t * Renders this {@link module:engine/view/uielement~UIElement} to DOM. This method is called by\n\t * {@link module:engine/view/domconverter~DomConverter}.\n\t * Do not use inheritance to create custom rendering method, replace `render()` method instead:\n\t *\n\t *\t\tconst myUIElement = downcastWriter.createUIElement( 'span' );\n\t *\t\tmyUIElement.render = function( domDocument ) {\n\t *\t\t\tconst domElement = this.toDomElement( domDocument );\n\t *\t\t\tdomElement.innerHTML = '<b>this is ui element</b>';\n\t *\n\t *\t\t\treturn domElement;\n\t *\t\t};\n\t *\n\t * If changes in your UI element should trigger some editor UI update you should call\n\t * the {@link module:core/editor/editorui~EditorUI#update `editor.ui.update()`} method\n\t * after rendering your UI element.\n\t *\n\t * @param {Document} domDocument\n\t * @returns {HTMLElement}\n\t */\n\trender( domDocument ) {\n\t\treturn this.toDomElement( domDocument );\n\t}\n\n\t/**\n\t * Creates DOM element based on this view UIElement.\n\t * Note that each time this method is called new DOM element is created.\n\t *\n\t * @param {Document} domDocument\n\t * @returns {HTMLElement}\n\t */\n\ttoDomElement( domDocument ) {\n\t\tconst domElement = domDocument.createElement( this.name );\n\n\t\tfor ( const key of this.getAttributeKeys() ) {\n\t\t\tdomElement.setAttribute( key, this.getAttribute( key ) );\n\t\t}\n\n\t\treturn domElement;\n\t}\n}\n\n/**\n * This function injects UI element handling to the given {@link module:engine/view/document~Document document}.\n *\n * A callback is added to {@link module:engine/view/document~Document#event:keydown document keydown event}.\n * The callback handles the situation when right arrow key is pressed and selection is collapsed before a UI element.\n * Without this handler, it would be impossible to \"jump over\" UI element using right arrow key.\n *\n * @param {module:engine/view/view~View} view View controller to which the quirks handling will be injected.\n */\nexport function injectUiElementHandling( view ) {\n\tview.document.on( 'keydown', ( evt, data ) => jumpOverUiElement( evt, data, view.domConverter ) );\n}\n\n// Returns `null` because block filler is not needed for UIElements.\n//\n// @returns {null}\nfunction getFillerOffset() {\n\treturn null;\n}\n\n// Selection cannot be placed in a `UIElement`. Whenever it is placed there, it is moved before it. This\n// causes a situation when it is impossible to jump over `UIElement` using right arrow key, because the selection\n// ends up in ui element (in DOM) and is moved back to the left. This handler fixes this situation.\nfunction jumpOverUiElement( evt, data, domConverter ) {\n\tif ( data.keyCode == keyCodes.arrowright ) {\n\t\tconst domSelection = data.domTarget.ownerDocument.defaultView.getSelection();\n\t\tconst domSelectionCollapsed = domSelection.rangeCount == 1 && domSelection.getRangeAt( 0 ).collapsed;\n\n\t\t// Jump over UI element if selection is collapsed or shift key is pressed. These are the cases when selection would extend.\n\t\tif ( domSelectionCollapsed || data.shiftKey ) {\n\t\t\tconst domParent = domSelection.focusNode;\n\t\t\tconst domOffset = domSelection.focusOffset;\n\n\t\t\tconst viewPosition = domConverter.domPositionToView( domParent, domOffset );\n\n\t\t\t// In case if dom element is not converted to view or is not mapped or something. Happens for example in some tests.\n\t\t\tif ( viewPosition === null ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Skip all following ui elements.\n\t\t\tlet jumpedOverAnyUiElement = false;\n\n\t\t\tconst nextViewPosition = viewPosition.getLastMatchingPosition( value => {\n\t\t\t\tif ( value.item.is( 'uiElement' ) ) {\n\t\t\t\t\t// Remember that there was at least one ui element.\n\t\t\t\t\tjumpedOverAnyUiElement = true;\n\t\t\t\t}\n\n\t\t\t\t// Jump over ui elements, jump over empty attribute elements, move up from inside of attribute element.\n\t\t\t\tif ( value.item.is( 'uiElement' ) || value.item.is( 'attributeElement' ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\t// Don't jump over text or don't get out of container element.\n\t\t\t\treturn false;\n\t\t\t} );\n\n\t\t\t// If anything has been skipped, fix position.\n\t\t\t// This `if` could be possibly omitted but maybe it is better not to mess with DOM selection if not needed.\n\t\t\tif ( jumpedOverAnyUiElement ) {\n\t\t\t\tconst newDomPosition = domConverter.viewPositionToDom( nextViewPosition );\n\n\t\t\t\tif ( domSelectionCollapsed ) {\n\t\t\t\t\t// Selection was collapsed, so collapse it at further position.\n\t\t\t\t\tdomSelection.collapse( newDomPosition.parent, newDomPosition.offset );\n\t\t\t\t} else {\n\t\t\t\t\t// Selection was not collapse, so extend it instead of collapsing.\n\t\t\t\t\tdomSelection.extend( newDomPosition.parent, newDomPosition.offset );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/rawelement\n */\n\nimport Element from './element';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport Node from './node';\n\n/**\n * The raw element class.\n *\n * The raw elements work as data containers (\"wrappers\", \"sandboxes\") but their children are not managed or\n * even recognized by the editor. This encapsulation allows integrations to maintain custom DOM structures\n * in the editor content without, for instance, worrying about compatibility with other editor features.\n * Raw elements are a perfect tool for integration with external frameworks and data sources.\n *\n * Unlike {@link module:engine/view/uielement~UIElement UI elements}, raw elements act like real editor\n * content (similar to {@link module:engine/view/containerelement~ContainerElement} or\n * {@link module:engine/view/emptyelement~EmptyElement}), they are considered by the editor selection and\n * {@link module:widget/utils~toWidget they can work as widgets}.\n *\n * To create a new raw element, use the\n * {@link module:engine/view/downcastwriter~DowncastWriter#createRawElement `downcastWriter#createRawElement()`} method.\n *\n * @extends module:engine/view/element~Element\n */\nexport default class RawElement extends Element {\n\t/**\n\t * Creates a new instance of a raw element.\n\t *\n\t * Throws the `view-rawelement-cannot-add` {@link module:utils/ckeditorerror~CKEditorError CKEditorError} when the `children`\n\t * parameter is passed to inform that the usage of `RawElement` is incorrect (adding child nodes to `RawElement` is forbidden).\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#createRawElement\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document instance to which this element belongs.\n\t * @param {String} name A node name.\n\t * @param {Object|Iterable} [attrs] The collection of attributes.\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into the created element.\n\t */\n\tconstructor( document, name, attrs, children ) {\n\t\tsuper( document, name, attrs, children );\n\n\t\t/**\n\t\t * Returns `null` because filler is not needed for raw elements.\n\t\t *\n\t\t * @method #getFillerOffset\n\t\t * @returns {null} Always returns null.\n\t\t */\n\t\tthis.getFillerOffset = getFillerOffset;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type or name.\n\t *\n\t *\t\trawElement.is( 'rawElement' ); // -> true\n\t *\t\trawElement.is( 'element' ); // -> true\n\t *\t\trawElement.is( 'node' ); // -> true\n\t *\t\trawElement.is( 'view:rawElement' ); // -> true\n\t *\t\trawElement.is( 'view:element' ); // -> true\n\t *\t\trawElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\trawElement.is( 'model:element' ); // -> false\n\t *\t\trawElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is a raw element, you can also check its\n\t * {@link module:engine/view/rawelement~RawElement#name name}:\n\t *\n\t *\t\trawElement.is( 'img' ); // -> true if this is an img element\n\t *\t\trawElement.is( 'rawElement', 'img' ); // -> same as above\n\t *\t\ttext.is( 'img' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type The type to check when the `name` parameter is present.\n\t * Otherwise, it acts like the `name` parameter.\n\t * @param {String} [name] The element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'rawElement' || type === 'view:rawElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === this.name || type === 'view:' + this.name ||\n\t\t\t\ttype === 'element' || type === 'view:element' ||\n\t\t\t\ttype === 'node' || type === 'view:node';\n\t\t} else {\n\t\t\treturn name === this.name && (\n\t\t\t\ttype === 'rawElement' || type === 'view:rawElement' ||\n\t\t\t\ttype === 'element' || type === 'view:element'\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Overrides the {@link module:engine/view/element~Element#_insertChild} method.\n\t * Throws the `view-rawelement-cannot-add` {@link module:utils/ckeditorerror~CKEditorError CKEditorError} to prevent\n\t * adding any child nodes to a raw element.\n\t *\n\t * @protected\n\t */\n\t_insertChild( index, nodes ) {\n\t\tif ( nodes && ( nodes instanceof Node || Array.from( nodes ).length > 0 ) ) {\n\t\t\t/**\n\t\t\t * Cannot add children to a {@link module:engine/view/rawelement~RawElement} instance.\n\t\t\t *\n\t\t\t * @error view-rawelement-cannot-add\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-rawelement-cannot-add',\n\t\t\t\t[ this, nodes ]\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * This allows rendering the children of a {@link module:engine/view/rawelement~RawElement} on the DOM level.\n\t * This method is called by the {@link module:engine/view/domconverter~DomConverter} with the raw DOM element\n\t * passed as an argument, leaving the number and shape of the children up to the integrator.\n\t *\n\t * This method **must be defined** for the raw element to work:\n\t *\n\t *\t\tconst myRawElement = downcastWriter.createRawElement( 'div' );\n\t *\n\t *\t\tmyRawElement.render = function( domElement ) {\n\t *\t\t\tdomElement.innerHTML = '<b>This is the raw content of myRawElement.</b>';\n\t *\t\t};\n\t *\n\t * @method #render\n\t * @param {HTMLElement} domElement The native DOM element representing the raw view element.\n\t */\n}\n\n// Returns `null` because block filler is not needed for raw elements.\n//\n// @returns {null}\nfunction getFillerOffset() {\n\treturn null;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/documentfragment\n */\n\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\n\n/**\n * Document fragment.\n *\n * To create a new document fragment instance use the\n * {@link module:engine/view/upcastwriter~UpcastWriter#createDocumentFragment `UpcastWriter#createDocumentFragment()`}\n * method.\n */\nexport default class DocumentFragment {\n\t/**\n\t * Creates new DocumentFragment instance.\n\t *\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document to which this document fragment belongs.\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into the created document fragment.\n\t */\n\tconstructor( document, children ) {\n\t\t/**\n\t\t * The document to which this document fragment belongs.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = document;\n\n\t\t/**\n\t\t * Array of child nodes.\n\t\t *\n\t\t * @protected\n\t\t * @member {Array.<module:engine/view/element~Element>} module:engine/view/documentfragment~DocumentFragment#_children\n\t\t */\n\t\tthis._children = [];\n\n\t\tif ( children ) {\n\t\t\tthis._insertChild( 0, children );\n\t\t}\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over nodes added to this document fragment.\n\t *\n\t * @returns {Iterable.<module:engine/view/node~Node>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._children[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Number of child nodes in this document fragment.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget childCount() {\n\t\treturn this._children.length;\n\t}\n\n\t/**\n\t * Is `true` if there are no nodes inside this document fragment, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isEmpty() {\n\t\treturn this.childCount === 0;\n\t}\n\n\t/**\n\t * Artificial root of `DocumentFragment`. Returns itself. Added for compatibility reasons.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Artificial parent of `DocumentFragment`. Returns `null`. Added for compatibility reasons.\n\t *\n\t * @readonly\n\t * @type {null}\n\t */\n\tget parent() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tdocFrag.is( 'documentFragment' ); // -> true\n\t *\t\tdocFrag.is( 'view:documentFragment' ); // -> true\n\t *\n\t *\t\tdocFrag.is( 'model:documentFragment' ); // -> false\n\t *\t\tdocFrag.is( 'element' ); // -> false\n\t *\t\tdocFrag.is( 'node' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'documentFragment' || type === 'view:documentFragment';\n\t}\n\n\t/**\n\t * {@link module:engine/view/documentfragment~DocumentFragment#_insertChild Insert} a child node or a list of child nodes at the end\n\t * and sets the parent of these nodes to this fragment.\n\t *\n\t * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.\n\t * @returns {Number} Number of appended nodes.\n\t */\n\t_appendChild( items ) {\n\t\treturn this._insertChild( this.childCount, items );\n\t}\n\n\t/**\n\t * Gets child at the given index.\n\t *\n\t * @param {Number} index Index of child.\n\t * @returns {module:engine/view/node~Node} Child node.\n\t */\n\tgetChild( index ) {\n\t\treturn this._children[ index ];\n\t}\n\n\t/**\n\t * Gets index of the given child node. Returns `-1` if child node is not found.\n\t *\n\t * @param {module:engine/view/node~Node} node Child node.\n\t * @returns {Number} Index of the child node.\n\t */\n\tgetChildIndex( node ) {\n\t\treturn this._children.indexOf( node );\n\t}\n\n\t/**\n\t * Gets child nodes iterator.\n\t *\n\t * @returns {Iterable.<module:engine/view/node~Node>} Child nodes iterator.\n\t */\n\tgetChildren() {\n\t\treturn this._children[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Inserts a child node or a list of child nodes on the given index and sets the parent of these nodes to\n\t * this fragment.\n\t *\n\t * @param {Number} index Position where nodes should be inserted.\n\t * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.\n\t * @returns {Number} Number of inserted nodes.\n\t */\n\t_insertChild( index, items ) {\n\t\tthis._fireChange( 'children', this );\n\t\tlet count = 0;\n\n\t\tconst nodes = normalize( this.document, items );\n\n\t\tfor ( const node of nodes ) {\n\t\t\t// If node that is being added to this element is already inside another element, first remove it from the old parent.\n\t\t\tif ( node.parent !== null ) {\n\t\t\t\tnode._remove();\n\t\t\t}\n\n\t\t\tnode.parent = this;\n\n\t\t\tthis._children.splice( index, 0, node );\n\t\t\tindex++;\n\t\t\tcount++;\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/**\n\t * Removes number of child nodes starting at the given index and set the parent of these nodes to `null`.\n\t *\n\t * @param {Number} index Number of the first node to remove.\n\t * @param {Number} [howMany=1] Number of nodes to remove.\n\t * @returns {Array.<module:engine/view/node~Node>} The array of removed nodes.\n\t */\n\t_removeChildren( index, howMany = 1 ) {\n\t\tthis._fireChange( 'children', this );\n\n\t\tfor ( let i = index; i < index + howMany; i++ ) {\n\t\t\tthis._children[ i ].parent = null;\n\t\t}\n\n\t\treturn this._children.splice( index, howMany );\n\t}\n\n\t/**\n\t * Fires `change` event with given type of the change.\n\t *\n\t * @private\n\t * @param {module:engine/view/document~ChangeType} type Type of the change.\n\t * @param {module:engine/view/node~Node} node Changed node.\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_fireChange( type, node ) {\n\t\tthis.fire( 'change:' + type, node );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // printTree() {\n\t// @if CK_DEBUG_ENGINE //\tlet string = 'ViewDocumentFragment: [';\n\n\t// @if CK_DEBUG_ENGINE //\tfor ( const child of this.getChildren() ) {\n\t// @if CK_DEBUG_ENGINE //\t\tif ( child.is( '$text' ) ) {\n\t// @if CK_DEBUG_ENGINE //\t\t\tstring += '\\n' + '\\t'.repeat( 1 ) + child.data;\n\t// @if CK_DEBUG_ENGINE //\t\t} else {\n\t// @if CK_DEBUG_ENGINE //\t\t\tstring += '\\n' + child.printTree( 1 );\n\t// @if CK_DEBUG_ENGINE //\t\t}\n\t// @if CK_DEBUG_ENGINE //\t}\n\n\t// @if CK_DEBUG_ENGINE //\tstring += '\\n]';\n\n\t// @if CK_DEBUG_ENGINE //\treturn string;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logTree() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( this.printTree() );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\nmix( DocumentFragment, EmitterMixin );\n\n// Converts strings to Text and non-iterables to arrays.\n//\n// @param {String|module:engine/view/item~Item|Iterable.<String|module:engine/view/item~Item>}\n// @returns {Iterable.<module:engine/view/node~Node>}\nfunction normalize( document, nodes ) {\n\t// Separate condition because string is iterable.\n\tif ( typeof nodes == 'string' ) {\n\t\treturn [ new Text( document, nodes ) ];\n\t}\n\n\tif ( !isIterable( nodes ) ) {\n\t\tnodes = [ nodes ];\n\t}\n\n\t// Array.from to enable .map() on non-arrays.\n\treturn Array.from( nodes )\n\t\t.map( node => {\n\t\t\tif ( typeof node == 'string' ) {\n\t\t\t\treturn new Text( document, node );\n\t\t\t}\n\n\t\t\tif ( node instanceof TextProxy ) {\n\t\t\t\treturn new Text( document, node.data );\n\t\t\t}\n\n\t\t\treturn node;\n\t\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module module:engine/view/downcastwriter\n */\n\nimport Position from './position';\nimport Range from './range';\nimport Selection from './selection';\nimport ContainerElement from './containerelement';\nimport AttributeElement from './attributeelement';\nimport EmptyElement from './emptyelement';\nimport UIElement from './uielement';\nimport RawElement from './rawelement';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport DocumentFragment from './documentfragment';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\nimport Text from './text';\nimport EditableElement from './editableelement';\nimport { isPlainObject } from 'lodash-es';\n\n/**\n * View downcast writer.\n *\n * It provides a set of methods used to manipulate view nodes.\n *\n * Do not create an instance of this writer manually. To modify a view structure, use\n * the {@link module:engine/view/view~View#change `View#change()`} block.\n *\n * The `DowncastWriter` is designed to work with semantic views which are the views that were/are being downcasted from the model.\n * To work with ordinary views (e.g. parsed from a pasted content) use the\n * {@link module:engine/view/upcastwriter~UpcastWriter upcast writer}.\n *\n * Read more about changing the view in the {@glink framework/guides/architecture/editing-engine#changing-the-view Changing the view}\n * section of the {@glink framework/guides/architecture/editing-engine Editing engine architecture} guide.\n */\nexport default class DowncastWriter {\n\t/**\n\t * @param {module:engine/view/document~Document} document The view document instance.\n\t */\n\tconstructor( document ) {\n\t\t/**\n\t\t * The view document instance in which this writer operates.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = document;\n\n\t\t/**\n\t\t * Holds references to the attribute groups that share the same {@link module:engine/view/attributeelement~AttributeElement#id id}.\n\t\t * The keys are `id`s, the values are `Set`s holding {@link module:engine/view/attributeelement~AttributeElement}s.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.<String,Set>}\n\t\t */\n\t\tthis._cloneGroups = new Map();\n\t}\n\n\t/**\n\t * Sets {@link module:engine/view/documentselection~DocumentSelection selection's} ranges and direction to the\n\t * specified location based on the given {@link module:engine/view/selection~Selectable selectable}.\n\t *\n\t * Usage:\n\t *\n\t *\t\t// Sets selection to the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\twriter.setSelection( range );\n\t *\n\t *\t\t// Sets backward selection to the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\twriter.setSelection( range );\n\t *\n\t *\t\t// Sets selection to given ranges.\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( start2, end2 ) ];\n\t *\t\twriter.setSelection( range );\n\t *\n\t *\t\t// Sets selection to the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\twriter.setSelection( otherSelection );\n\t *\n\t * \t\t// Sets collapsed selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\twriter.setSelection( position );\n\t *\n\t * \t\t// Sets collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = writer.createContainerElement( 'p' );\n\t *\t\twriter.setSelection( paragraph, offset );\n\t *\n\t * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of\n \t * that element and ends after the last child of that element.\n\t *\n\t * \t\twriter.setSelection( paragraph, 'in' );\n\t *\n\t * Creates a range on the {@link module:engine/view/item~Item item} which starts before the item and ends just after the item.\n\t *\n\t *\t\twriter.setSelection( paragraph, 'on' );\n\t *\n\t * \t\t// Removes all ranges.\n\t *\t\twriter.setSelection( null );\n\t *\n\t * `DowncastWriter#setSelection()` allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Sets selection as backward.\n\t *\t\twriter.setSelection( range, { backward: true } );\n\t *\n\t *\t\t// Sets selection as fake.\n\t *\t\t// Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * \t\t// This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * \t\t// represented in other way, for example by applying proper CSS class.\n\t *\t\twriter.setSelection( range, { fake: true } );\n\t *\n\t * \t\t// Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * \t\t// (and be  properly handled by screen readers).\n\t *\t\twriter.setSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t */\n\tsetSelection( selectable, placeOrOffset, options ) {\n\t\tthis.document.selection._setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Moves {@link module:engine/view/documentselection~DocumentSelection#focus selection's focus} to the specified location.\n\t *\n\t * The location can be specified in the same form as {@link module:engine/view/view~View#createPositionAt view.createPositionAt()}\n\t * parameters.\n\t *\n\t * @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/view/item~Item view item}.\n\t */\n\tsetSelectionFocus( itemOrPosition, offset ) {\n\t\tthis.document.selection._setFocus( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/text~Text text node}.\n\t *\n\t *\t\twriter.createText( 'foo' );\n\t *\n\t * @param {String} data The text's data.\n\t * @returns {module:engine/view/text~Text} The created text node.\n\t */\n\tcreateText( data ) {\n\t\treturn new Text( this.document, data );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/attributeelement~AttributeElement}.\n\t *\n\t *\t\twriter.createAttributeElement( 'strong' );\n\t *\t\twriter.createAttributeElement( 'a', { href: 'foo.bar' } );\n\t *\n\t *\t\t// Make `<a>` element contain other attributes element so the `<a>` element is not broken.\n\t *\t\twriter.createAttributeElement( 'a', { href: 'foo.bar' }, { priority: 5 } );\n\t *\n\t *\t\t// Set `id` of a marker element so it is not joined or merged with \"normal\" elements.\n\t *\t\twriter.createAttributeElement( 'span', { class: 'my-marker' }, { id: 'marker:my' } );\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Element's attributes.\n\t * @param {Object} [options] Element's options.\n\t * @param {Number} [options.priority] Element's {@link module:engine/view/attributeelement~AttributeElement#priority priority}.\n\t * @param {Number|String} [options.id] Element's {@link module:engine/view/attributeelement~AttributeElement#id id}.\n\t * @returns {module:engine/view/attributeelement~AttributeElement} Created element.\n\t */\n\tcreateAttributeElement( name, attributes, options = {} ) {\n\t\tconst attributeElement = new AttributeElement( this.document, name, attributes );\n\n\t\tif ( options.priority ) {\n\t\t\tattributeElement._priority = options.priority;\n\t\t}\n\n\t\tif ( options.id ) {\n\t\t\tattributeElement._id = options.id;\n\t\t}\n\n\t\treturn attributeElement;\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/containerelement~ContainerElement}.\n\t *\n\t *\t\twriter.createContainerElement( 'p' );\n\t *\n\t *\t\t// Create element with custom attributes.\n\t *\t\twriter.createContainerElement( 'div', { id: 'foo-bar', 'data-baz': '123' } );\n\t *\n\t *\t\t// Create element with custom styles.\n\t *\t\twriter.createContainerElement( 'p', { style: 'font-weight: bold; padding-bottom: 10px' } );\n\t *\n\t *\t\t// Create element with custom classes.\n\t *\t\twriter.createContainerElement( 'p', { class: 'foo bar baz' } );\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @returns {module:engine/view/containerelement~ContainerElement} Created element.\n\t */\n\tcreateContainerElement( name, attributes ) {\n\t\treturn new ContainerElement( this.document, name, attributes );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/editableelement~EditableElement}.\n\t *\n\t *\t\twriter.createEditableElement( 'div' );\n\t *\t\twriter.createEditableElement( 'div', { id: 'foo-1234' } );\n\t *\n\t * Note: The editable element is to be used in the editing pipeline. Usually, together with\n\t * {@link module:widget/utils~toWidgetEditable `toWidgetEditable()`}.\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @returns {module:engine/view/editableelement~EditableElement} Created element.\n\t */\n\tcreateEditableElement( name, attributes ) {\n\t\tconst editableElement = new EditableElement( this.document, name, attributes );\n\t\teditableElement._document = this.document;\n\n\t\treturn editableElement;\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/emptyelement~EmptyElement}.\n\t *\n\t *\t\twriter.createEmptyElement( 'img' );\n\t *\t\twriter.createEmptyElement( 'img', { id: 'foo-1234' } );\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @returns {module:engine/view/emptyelement~EmptyElement} Created element.\n\t */\n\tcreateEmptyElement( name, attributes ) {\n\t\treturn new EmptyElement( this.document, name, attributes );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/uielement~UIElement}.\n\t *\n\t *\t\twriter.createUIElement( 'span' );\n\t *\t\twriter.createUIElement( 'span', { id: 'foo-1234' } );\n\t *\n\t * A custom render function can be provided as the third parameter:\n\t *\n\t *\t\twriter.createUIElement( 'span', null, function( domDocument ) {\n\t *\t\t\tconst domElement = this.toDomElement( domDocument );\n\t *\t\t\tdomElement.innerHTML = '<b>this is ui element</b>';\n\t *\n\t *\t\t\treturn domElement;\n\t *\t\t} );\n\t *\n\t * Unlike {@link #createRawElement raw elements}, UI elements are by no means editor content, for instance,\n\t * they are ignored by the editor selection system.\n\t *\n\t * You should not use UI elements as data containers. Check out {@link #createRawElement} instead.\n\t *\n\t * @param {String} name The name of the element.\n\t * @param {Object} [attributes] Element attributes.\n\t * @param {Function} [renderFunction] A custom render function.\n\t * @returns {module:engine/view/uielement~UIElement} The created element.\n\t */\n\tcreateUIElement( name, attributes, renderFunction ) {\n\t\tconst uiElement = new UIElement( this.document, name, attributes );\n\n\t\tif ( renderFunction ) {\n\t\t\tuiElement.render = renderFunction;\n\t\t}\n\n\t\treturn uiElement;\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/rawelement~RawElement}.\n\t *\n\t *\t\twriter.createRawElement( 'span', { id: 'foo-1234' }, function( domElement ) {\n\t *\t\t\tdomElement.innerHTML = '<b>This is the raw content of the raw element.</b>';\n\t *\t\t} );\n\t *\n\t * Raw elements work as data containers (\"wrappers\", \"sandboxes\") but their children are not managed or\n\t * even recognized by the editor. This encapsulation allows integrations to maintain custom DOM structures\n\t * in the editor content without, for instance, worrying about compatibility with other editor features.\n\t * Raw elements are a perfect tool for integration with external frameworks and data sources.\n\t *\n\t * Unlike {@link #createUIElement UI elements}, raw elements act like \"real\" editor content (similar to\n\t * {@link module:engine/view/containerelement~ContainerElement} or {@link module:engine/view/emptyelement~EmptyElement}),\n\t * and they are considered by the editor selection.\n\t *\n\t * You should not use raw elements to render the UI in the editor content. Check out {@link #createUIElement `#createUIElement()`}\n\t * instead.\n\t *\n\t * @param {String} name The name of the element.\n\t * @param {Object} [attributes] Element attributes.\n\t * @param {Function} [renderFunction] A custom render function.\n\t * @returns {module:engine/view/rawelement~RawElement} The created element.\n\t */\n\tcreateRawElement( name, attributes, renderFunction ) {\n\t\tconst rawElement = new RawElement( this.document, name, attributes );\n\n\t\trawElement.render = renderFunction || ( () => {} );\n\n\t\treturn rawElement;\n\t}\n\n\t/**\n\t * Adds or overwrites the element's attribute with a specified key and value.\n\t *\n\t *\t\twriter.setAttribute( 'href', 'http://ckeditor.com', linkElement );\n\t *\n\t * @param {String} key The attribute key.\n\t * @param {String} value The attribute value.\n\t * @param {module:engine/view/element~Element} element\n\t */\n\tsetAttribute( key, value, element ) {\n\t\telement._setAttribute( key, value );\n\t}\n\n\t/**\n\t * Removes attribute from the element.\n\t *\n\t *\t\twriter.removeAttribute( 'href', linkElement );\n\t *\n\t * @param {String} key Attribute key.\n\t * @param {module:engine/view/element~Element} element\n\t */\n\tremoveAttribute( key, element ) {\n\t\telement._removeAttribute( key );\n\t}\n\n\t/**\n\t * Adds specified class to the element.\n\t *\n\t *\t\twriter.addClass( 'foo', linkElement );\n\t *\t\twriter.addClass( [ 'foo', 'bar' ], linkElement );\n\t *\n\t * @param {Array.<String>|String} className\n\t * @param {module:engine/view/element~Element} element\n\t */\n\taddClass( className, element ) {\n\t\telement._addClass( className );\n\t}\n\n\t/**\n\t * Removes specified class from the element.\n\t *\n\t *\t\twriter.removeClass( 'foo', linkElement );\n\t *\t\twriter.removeClass( [ 'foo', 'bar' ], linkElement );\n\t *\n\t * @param {Array.<String>|String} className\n\t * @param {module:engine/view/element~Element} element\n\t */\n\tremoveClass( className, element ) {\n\t\telement._removeClass( className );\n\t}\n\n\t/**\n\t * Adds style to the element.\n\t *\n\t *\t\twriter.setStyle( 'color', 'red', element );\n\t *\t\twriter.setStyle( {\n\t *\t\t\tcolor: 'red',\n\t *\t\t\tposition: 'fixed'\n\t *\t\t}, element );\n\t *\n\t * **Note**: The passed style can be normalized if\n\t * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#set `StylesMap#set()`} for details.\n\t *\n\t * @param {String|Object} property Property name or object with key - value pairs.\n\t * @param {String} [value] Value to set. This parameter is ignored if object is provided as the first parameter.\n\t * @param {module:engine/view/element~Element} element Element to set styles on.\n\t */\n\tsetStyle( property, value, element ) {\n\t\tif ( isPlainObject( property ) && element === undefined ) {\n\t\t\telement = value;\n\t\t}\n\n\t\telement._setStyle( property, value );\n\t}\n\n\t/**\n\t * Removes specified style from the element.\n\t *\n\t *\t\twriter.removeStyle( 'color', element ); // Removes 'color' style.\n\t *\t\twriter.removeStyle( [ 'color', 'border-top' ], element ); // Removes both 'color' and 'border-top' styles.\n\t *\n\t * **Note**: This method can work with normalized style names if\n\t * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#remove `StylesMap#remove()`} for details.\n\t *\n\t * @param {Array.<String>|String} property\n\t * @param {module:engine/view/element~Element} element\n\t */\n\tremoveStyle( property, element ) {\n\t\telement._removeStyle( property );\n\t}\n\n\t/**\n\t * Sets a custom property on element. Unlike attributes, custom properties are not rendered to the DOM,\n\t * so they can be used to add special data to elements.\n\t *\n\t * @param {String|Symbol} key\n\t * @param {*} value\n\t * @param {module:engine/view/element~Element} element\n\t */\n\tsetCustomProperty( key, value, element ) {\n\t\telement._setCustomProperty( key, value );\n\t}\n\n\t/**\n\t * Removes a custom property stored under the given key.\n\t *\n\t * @param {String|Symbol} key\n\t * @param {module:engine/view/element~Element} element\n\t * @returns {Boolean} Returns true if property was removed.\n\t */\n\tremoveCustomProperty( key, element ) {\n\t\treturn element._removeCustomProperty( key );\n\t}\n\n\t/**\n\t * Breaks attribute elements at the provided position or at the boundaries of a provided range. It breaks attribute elements\n\t * up to their first ancestor that is a container element.\n\t *\n\t * In following examples `<p>` is a container, `<b>` and `<u>` are attribute elements:\n\t *\n\t *\t\t<p>foo<b><u>bar{}</u></b></p> -> <p>foo<b><u>bar</u></b>[]</p>\n\t *\t\t<p>foo<b><u>{}bar</u></b></p> -> <p>foo{}<b><u>bar</u></b></p>\n\t *\t\t<p>foo<b><u>b{}ar</u></b></p> -> <p>foo<b><u>b</u></b>[]<b><u>ar</u></b></p>\n\t *\t\t<p><b>fo{o</b><u>ba}r</u></p> -> <p><b>fo</b><b>o</b><u>ba</u><u>r</u></b></p>\n\t *\n\t * **Note:** {@link module:engine/view/documentfragment~DocumentFragment DocumentFragment} is treated like a container.\n\t *\n\t * **Note:** The difference between {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes breakAttributes()} and\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#breakContainer breakContainer()} is that `breakAttributes()` breaks all\n\t * {@link module:engine/view/attributeelement~AttributeElement attribute elements} that are ancestors of a given `position`,\n\t * up to the first encountered {@link module:engine/view/containerelement~ContainerElement container element}.\n\t * `breakContainer()` assumes that a given `position` is directly in the container element and breaks that container element.\n\t *\n\t * Throws the `view-writer-invalid-range-container` {@link module:utils/ckeditorerror~CKEditorError CKEditorError}\n\t * when the {@link module:engine/view/range~Range#start start}\n\t * and {@link module:engine/view/range~Range#end end} positions of a passed range are not placed inside same parent container.\n\t *\n\t * Throws the `view-writer-cannot-break-empty-element` {@link module:utils/ckeditorerror~CKEditorError CKEditorError}\n\t * when trying to break attributes inside an {@link module:engine/view/emptyelement~EmptyElement EmptyElement}.\n\t *\n\t * Throws the `view-writer-cannot-break-ui-element` {@link module:utils/ckeditorerror~CKEditorError CKEditorError}\n\t * when trying to break attributes inside a {@link module:engine/view/uielement~UIElement UIElement}.\n\t *\n\t * @see module:engine/view/attributeelement~AttributeElement\n\t * @see module:engine/view/containerelement~ContainerElement\n\t * @see module:engine/view/downcastwriter~DowncastWriter#breakContainer\n\t * @param {module:engine/view/position~Position|module:engine/view/range~Range} positionOrRange The position where\n\t * to break attribute elements.\n\t * @returns {module:engine/view/position~Position|module:engine/view/range~Range} The new position or range, after breaking the\n\t * attribute elements.\n\t */\n\tbreakAttributes( positionOrRange ) {\n\t\tif ( positionOrRange instanceof Position ) {\n\t\t\treturn this._breakAttributes( positionOrRange );\n\t\t} else {\n\t\t\treturn this._breakAttributesRange( positionOrRange );\n\t\t}\n\t}\n\n\t/**\n\t * Breaks a {@link module:engine/view/containerelement~ContainerElement container view element} into two, at the given position.\n\t * The position has to be directly inside the container element and cannot be in the root. It does not break the conrainer view element\n\t * if the position is at the beginning or at the end of its parent element.\n\t *\n\t *\t\t<p>foo^bar</p> -> <p>foo</p><p>bar</p>\n\t *\t\t<div><p>foo</p>^<p>bar</p></div> -> <div><p>foo</p></div><div><p>bar</p></div>\n\t *\t\t<p>^foobar</p> -> ^<p>foobar</p>\n\t *\t\t<p>foobar^</p> -> <p>foobar</p>^\n\t *\n\t * **Note:** The difference between {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes breakAttributes()} and\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#breakContainer breakContainer()} is that `breakAttributes()` breaks all\n\t * {@link module:engine/view/attributeelement~AttributeElement attribute elements} that are ancestors of a given `position`,\n\t * up to the first encountered {@link module:engine/view/containerelement~ContainerElement container element}.\n\t * `breakContainer()` assumes that the given `position` is directly in the container element and breaks that container element.\n\t *\n\t * @see module:engine/view/attributeelement~AttributeElement\n\t * @see module:engine/view/containerelement~ContainerElement\n\t * @see module:engine/view/downcastwriter~DowncastWriter#breakAttributes\n\t * @param {module:engine/view/position~Position} position The position where to break the element.\n\t * @returns {module:engine/view/position~Position} The position between broken elements. If an element has not been broken,\n\t * the returned position is placed either before or after it.\n\t */\n\tbreakContainer( position ) {\n\t\tconst element = position.parent;\n\n\t\tif ( !( element.is( 'containerElement' ) ) ) {\n\t\t\t/**\n\t\t\t * Trying to break an element which is not a container element.\n\t\t\t *\n\t\t\t * @error view-writer-break-non-container-element\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-break-non-container-element', this.document );\n\t\t}\n\n\t\tif ( !element.parent ) {\n\t\t\t/**\n\t\t\t * Trying to break root element.\n\t\t\t *\n\t\t\t * @error view-writer-break-root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-break-root', this.document );\n\t\t}\n\n\t\tif ( position.isAtStart ) {\n\t\t\treturn Position._createBefore( element );\n\t\t} else if ( !position.isAtEnd ) {\n\t\t\tconst newElement = element._clone( false );\n\n\t\t\tthis.insert( Position._createAfter( element ), newElement );\n\n\t\t\tconst sourceRange = new Range( position, Position._createAt( element, 'end' ) );\n\t\t\tconst targetPosition = new Position( newElement, 0 );\n\n\t\t\tthis.move( sourceRange, targetPosition );\n\t\t}\n\n\t\treturn Position._createAfter( element );\n\t}\n\n\t/**\n\t * Merges {@link module:engine/view/attributeelement~AttributeElement attribute elements}. It also merges text nodes if needed.\n\t * Only {@link module:engine/view/attributeelement~AttributeElement#isSimilar similar} attribute elements can be merged.\n\t *\n\t * In following examples `<p>` is a container and `<b>` is an attribute element:\n\t *\n\t *\t\t<p>foo[]bar</p> -> <p>foo{}bar</p>\n\t *\t\t<p><b>foo</b>[]<b>bar</b></p> -> <p><b>foo{}bar</b></p>\n\t *\t\t<p><b foo=\"bar\">a</b>[]<b foo=\"baz\">b</b></p> -> <p><b foo=\"bar\">a</b>[]<b foo=\"baz\">b</b></p>\n\t *\n\t * It will also take care about empty attributes when merging:\n\t *\n\t *\t\t<p><b>[]</b></p> -> <p>[]</p>\n\t *\t\t<p><b>foo</b><i>[]</i><b>bar</b></p> -> <p><b>foo{}bar</b></p>\n\t *\n\t * **Note:** Difference between {@link module:engine/view/downcastwriter~DowncastWriter#mergeAttributes mergeAttributes} and\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#mergeContainers mergeContainers} is that `mergeAttributes` merges two\n\t * {@link module:engine/view/attributeelement~AttributeElement attribute elements} or {@link module:engine/view/text~Text text nodes}\n\t * while `mergeContainer` merges two {@link module:engine/view/containerelement~ContainerElement container elements}.\n\t *\n\t * @see module:engine/view/attributeelement~AttributeElement\n\t * @see module:engine/view/containerelement~ContainerElement\n\t * @see module:engine/view/downcastwriter~DowncastWriter#mergeContainers\n\t * @param {module:engine/view/position~Position} position Merge position.\n\t * @returns {module:engine/view/position~Position} Position after merge.\n\t */\n\tmergeAttributes( position ) {\n\t\tconst positionOffset = position.offset;\n\t\tconst positionParent = position.parent;\n\n\t\t// When inside text node - nothing to merge.\n\t\tif ( positionParent.is( '$text' ) ) {\n\t\t\treturn position;\n\t\t}\n\n\t\t// When inside empty attribute - remove it.\n\t\tif ( positionParent.is( 'attributeElement' ) && positionParent.childCount === 0 ) {\n\t\t\tconst parent = positionParent.parent;\n\t\t\tconst offset = positionParent.index;\n\n\t\t\tpositionParent._remove();\n\t\t\tthis._removeFromClonedElementsGroup( positionParent );\n\n\t\t\treturn this.mergeAttributes( new Position( parent, offset ) );\n\t\t}\n\n\t\tconst nodeBefore = positionParent.getChild( positionOffset - 1 );\n\t\tconst nodeAfter = positionParent.getChild( positionOffset );\n\n\t\t// Position should be placed between two nodes.\n\t\tif ( !nodeBefore || !nodeAfter ) {\n\t\t\treturn position;\n\t\t}\n\n\t\t// When position is between two text nodes.\n\t\tif ( nodeBefore.is( '$text' ) && nodeAfter.is( '$text' ) ) {\n\t\t\treturn mergeTextNodes( nodeBefore, nodeAfter );\n\t\t}\n\t\t// When position is between two same attribute elements.\n\t\telse if ( nodeBefore.is( 'attributeElement' ) && nodeAfter.is( 'attributeElement' ) && nodeBefore.isSimilar( nodeAfter ) ) {\n\t\t\t// Move all children nodes from node placed after selection and remove that node.\n\t\t\tconst count = nodeBefore.childCount;\n\t\t\tnodeBefore._appendChild( nodeAfter.getChildren() );\n\n\t\t\tnodeAfter._remove();\n\t\t\tthis._removeFromClonedElementsGroup( nodeAfter );\n\n\t\t\t// New position is located inside the first node, before new nodes.\n\t\t\t// Call this method recursively to merge again if needed.\n\t\t\treturn this.mergeAttributes( new Position( nodeBefore, count ) );\n\t\t}\n\n\t\treturn position;\n\t}\n\n\t/**\n\t * Merges two {@link module:engine/view/containerelement~ContainerElement container elements} that are before and after given position.\n\t * Precisely, the element after the position is removed and it's contents are moved to element before the position.\n\t *\n\t *\t\t<p>foo</p>^<p>bar</p> -> <p>foo^bar</p>\n\t *\t\t<div>foo</div>^<p>bar</p> -> <div>foo^bar</div>\n\t *\n\t * **Note:** Difference between {@link module:engine/view/downcastwriter~DowncastWriter#mergeAttributes mergeAttributes} and\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#mergeContainers mergeContainers} is that `mergeAttributes` merges two\n\t * {@link module:engine/view/attributeelement~AttributeElement attribute elements} or {@link module:engine/view/text~Text text nodes}\n\t * while `mergeContainer` merges two {@link module:engine/view/containerelement~ContainerElement container elements}.\n\t *\n\t * @see module:engine/view/attributeelement~AttributeElement\n\t * @see module:engine/view/containerelement~ContainerElement\n\t * @see module:engine/view/downcastwriter~DowncastWriter#mergeAttributes\n\t * @param {module:engine/view/position~Position} position Merge position.\n\t * @returns {module:engine/view/position~Position} Position after merge.\n\t */\n\tmergeContainers( position ) {\n\t\tconst prev = position.nodeBefore;\n\t\tconst next = position.nodeAfter;\n\n\t\tif ( !prev || !next || !prev.is( 'containerElement' ) || !next.is( 'containerElement' ) ) {\n\t\t\t/**\n\t\t\t * Element before and after given position cannot be merged.\n\t\t\t *\n\t\t\t * @error view-writer-merge-containers-invalid-position\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-merge-containers-invalid-position', this.document );\n\t\t}\n\n\t\tconst lastChild = prev.getChild( prev.childCount - 1 );\n\t\tconst newPosition = lastChild instanceof Text ? Position._createAt( lastChild, 'end' ) : Position._createAt( prev, 'end' );\n\n\t\tthis.move( Range._createIn( next ), Position._createAt( prev, 'end' ) );\n\t\tthis.remove( Range._createOn( next ) );\n\n\t\treturn newPosition;\n\t}\n\n\t/**\n\t * Inserts a node or nodes at specified position. Takes care about breaking attributes before insertion\n\t * and merging them afterwards.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-insert-invalid-node` when nodes to insert\n\t * contains instances that are not {@link module:engine/view/text~Text Texts},\n\t * {@link module:engine/view/attributeelement~AttributeElement AttributeElements},\n\t * {@link module:engine/view/containerelement~ContainerElement ContainerElements},\n\t * {@link module:engine/view/emptyelement~EmptyElement EmptyElements},\n\t * {@link module:engine/view/rawelement~RawElement RawElements} or\n\t * {@link module:engine/view/uielement~UIElement UIElements}.\n\t *\n\t * @param {module:engine/view/position~Position} position Insertion position.\n\t * @param {module:engine/view/text~Text|module:engine/view/attributeelement~AttributeElement|\n\t * module:engine/view/containerelement~ContainerElement|module:engine/view/emptyelement~EmptyElement|\n\t * module:engine/view/rawelement~RawElement|module:engine/view/uielement~UIElement|\n\t * Iterable.<module:engine/view/text~Text|\n\t * module:engine/view/attributeelement~AttributeElement|module:engine/view/containerelement~ContainerElement|\n\t * module:engine/view/emptyelement~EmptyElement|module:engine/view/rawelement~RawElement|\n\t * module:engine/view/uielement~UIElement>} nodes Node or nodes to insert.\n\t * @returns {module:engine/view/range~Range} Range around inserted nodes.\n\t */\n\tinsert( position, nodes ) {\n\t\tnodes = isIterable( nodes ) ? [ ...nodes ] : [ nodes ];\n\n\t\t// Check if nodes to insert are instances of AttributeElements, ContainerElements, EmptyElements, UIElements or Text.\n\t\tvalidateNodesToInsert( nodes, this.document );\n\n\t\tconst container = getParentContainer( position );\n\n\t\tif ( !container ) {\n\t\t\t/**\n\t\t\t * Position's parent container cannot be found.\n\t\t\t *\n\t\t\t * @error view-writer-invalid-position-container\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-writer-invalid-position-container',\n\t\t\t\tthis.document\n\t\t\t);\n\t\t}\n\n\t\tconst insertionPosition = this._breakAttributes( position, true );\n\t\tconst length = container._insertChild( insertionPosition.offset, nodes );\n\n\t\tfor ( const node of nodes ) {\n\t\t\tthis._addToClonedElementsGroup( node );\n\t\t}\n\n\t\tconst endPosition = insertionPosition.getShiftedBy( length );\n\t\tconst start = this.mergeAttributes( insertionPosition );\n\n\t\t// When no nodes were inserted - return collapsed range.\n\t\tif ( length === 0 ) {\n\t\t\treturn new Range( start, start );\n\t\t} else {\n\t\t\t// If start position was merged - move end position.\n\t\t\tif ( !start.isEqual( insertionPosition ) ) {\n\t\t\t\tendPosition.offset--;\n\t\t\t}\n\n\t\t\tconst end = this.mergeAttributes( endPosition );\n\n\t\t\treturn new Range( start, end );\n\t\t}\n\t}\n\n\t/**\n\t * Removes provided range from the container.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when\n\t * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions are not placed inside\n\t * same parent container.\n\t *\n\t * @param {module:engine/view/range~Range|module:engine/view/item~Item} rangeOrItem Range to remove from container\n\t * or an {@link module:engine/view/item~Item item} to remove. If range is provided, after removing, it will be updated\n\t * to a collapsed range showing the new position.\n\t * @returns {module:engine/view/documentfragment~DocumentFragment} Document fragment containing removed nodes.\n\t */\n\tremove( rangeOrItem ) {\n\t\tconst range = rangeOrItem instanceof Range ? rangeOrItem : Range._createOn( rangeOrItem );\n\n\t\tvalidateRangeContainer( range, this.document );\n\n\t\t// If range is collapsed - nothing to remove.\n\t\tif ( range.isCollapsed ) {\n\t\t\treturn new DocumentFragment( this.document );\n\t\t}\n\n\t\t// Break attributes at range start and end.\n\t\tconst { start: breakStart, end: breakEnd } = this._breakAttributesRange( range, true );\n\t\tconst parentContainer = breakStart.parent;\n\n\t\tconst count = breakEnd.offset - breakStart.offset;\n\n\t\t// Remove nodes in range.\n\t\tconst removed = parentContainer._removeChildren( breakStart.offset, count );\n\n\t\tfor ( const node of removed ) {\n\t\t\tthis._removeFromClonedElementsGroup( node );\n\t\t}\n\n\t\t// Merge after removing.\n\t\tconst mergePosition = this.mergeAttributes( breakStart );\n\t\trange.start = mergePosition;\n\t\trange.end = mergePosition.clone();\n\n\t\t// Return removed nodes.\n\t\treturn new DocumentFragment( this.document, removed );\n\t}\n\n\t/**\n\t * Removes matching elements from given range.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when\n\t * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions are not placed inside\n\t * same parent container.\n\t *\n\t * @param {module:engine/view/range~Range} range Range to clear.\n\t * @param {module:engine/view/element~Element} element Element to remove.\n\t */\n\tclear( range, element ) {\n\t\tvalidateRangeContainer( range, this.document );\n\n\t\t// Create walker on given range.\n\t\t// We walk backward because when we remove element during walk it modifies range end position.\n\t\tconst walker = range.getWalker( {\n\t\t\tdirection: 'backward',\n\t\t\tignoreElementEnd: true\n\t\t} );\n\n\t\t// Let's walk.\n\t\tfor ( const current of walker ) {\n\t\t\tconst item = current.item;\n\t\t\tlet rangeToRemove;\n\n\t\t\t// When current item matches to the given element.\n\t\t\tif ( item.is( 'element' ) && element.isSimilar( item ) ) {\n\t\t\t\t// Create range on this element.\n\t\t\t\trangeToRemove = Range._createOn( item );\n\t\t\t\t// When range starts inside Text or TextProxy element.\n\t\t\t} else if ( !current.nextPosition.isAfter( range.start ) && item.is( '$textProxy' ) ) {\n\t\t\t\t// We need to check if parent of this text matches to given element.\n\t\t\t\tconst parentElement = item.getAncestors().find( ancestor => {\n\t\t\t\t\treturn ancestor.is( 'element' ) && element.isSimilar( ancestor );\n\t\t\t\t} );\n\n\t\t\t\t// If it is then create range inside this element.\n\t\t\t\tif ( parentElement ) {\n\t\t\t\t\trangeToRemove = Range._createIn( parentElement );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we have found element to remove.\n\t\t\tif ( rangeToRemove ) {\n\t\t\t\t// We need to check if element range stick out of the given range and truncate if it is.\n\t\t\t\tif ( rangeToRemove.end.isAfter( range.end ) ) {\n\t\t\t\t\trangeToRemove.end = range.end;\n\t\t\t\t}\n\n\t\t\t\tif ( rangeToRemove.start.isBefore( range.start ) ) {\n\t\t\t\t\trangeToRemove.start = range.start;\n\t\t\t\t}\n\n\t\t\t\t// At the end we remove range with found element.\n\t\t\t\tthis.remove( rangeToRemove );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Moves nodes from provided range to target position.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when\n\t * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions are not placed inside\n\t * same parent container.\n\t *\n\t * @param {module:engine/view/range~Range} sourceRange Range containing nodes to move.\n\t * @param {module:engine/view/position~Position} targetPosition Position to insert.\n\t * @returns {module:engine/view/range~Range} Range in target container. Inserted nodes are placed between\n\t * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions.\n\t */\n\tmove( sourceRange, targetPosition ) {\n\t\tlet nodes;\n\n\t\tif ( targetPosition.isAfter( sourceRange.end ) ) {\n\t\t\ttargetPosition = this._breakAttributes( targetPosition, true );\n\n\t\t\tconst parent = targetPosition.parent;\n\t\t\tconst countBefore = parent.childCount;\n\n\t\t\tsourceRange = this._breakAttributesRange( sourceRange, true );\n\n\t\t\tnodes = this.remove( sourceRange );\n\n\t\t\ttargetPosition.offset += ( parent.childCount - countBefore );\n\t\t} else {\n\t\t\tnodes = this.remove( sourceRange );\n\t\t}\n\n\t\treturn this.insert( targetPosition, nodes );\n\t}\n\n\t/**\n\t * Wraps elements within range with provided {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.\n\t * If a collapsed range is provided, it will be wrapped only if it is equal to view selection.\n\t *\n\t * If a collapsed range was passed and is same as selection, the selection\n\t * will be moved to the inside of the wrapped attribute element.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-invalid-range-container`\n\t * when {@link module:engine/view/range~Range#start}\n\t * and {@link module:engine/view/range~Range#end} positions are not placed inside same parent container.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-invalid-attribute` when passed attribute element is not\n\t * an instance of {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-nonselection-collapsed-range` when passed range\n\t * is collapsed and different than view selection.\n\t *\n\t * @param {module:engine/view/range~Range} range Range to wrap.\n\t * @param {module:engine/view/attributeelement~AttributeElement} attribute Attribute element to use as wrapper.\n\t * @returns {module:engine/view/range~Range} range Range after wrapping, spanning over wrapping attribute element.\n\t */\n\twrap( range, attribute ) {\n\t\tif ( !( attribute instanceof AttributeElement ) ) {\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-writer-wrap-invalid-attribute',\n\t\t\t\tthis.document\n\t\t\t);\n\t\t}\n\n\t\tvalidateRangeContainer( range, this.document );\n\n\t\tif ( !range.isCollapsed ) {\n\t\t\t// Non-collapsed range. Wrap it with the attribute element.\n\t\t\treturn this._wrapRange( range, attribute );\n\t\t} else {\n\t\t\t// Collapsed range. Wrap position.\n\t\t\tlet position = range.start;\n\n\t\t\tif ( position.parent.is( 'element' ) && !_hasNonUiChildren( position.parent ) ) {\n\t\t\t\tposition = position.getLastMatchingPosition( value => value.item.is( 'uiElement' ) );\n\t\t\t}\n\n\t\t\tposition = this._wrapPosition( position, attribute );\n\t\t\tconst viewSelection = this.document.selection;\n\n\t\t\t// If wrapping position is equal to view selection, move view selection inside wrapping attribute element.\n\t\t\tif ( viewSelection.isCollapsed && viewSelection.getFirstPosition().isEqual( range.start ) ) {\n\t\t\t\tthis.setSelection( position );\n\t\t\t}\n\n\t\t\treturn new Range( position );\n\t\t}\n\t}\n\n\t/**\n\t * Unwraps nodes within provided range from attribute element.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when\n\t * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions are not placed inside\n\t * same parent container.\n\t *\n\t * @param {module:engine/view/range~Range} range\n\t * @param {module:engine/view/attributeelement~AttributeElement} attribute\n\t */\n\tunwrap( range, attribute ) {\n\t\tif ( !( attribute instanceof AttributeElement ) ) {\n\t\t\t/**\n\t\t\t * The `attribute` passed to {@link module:engine/view/downcastwriter~DowncastWriter#unwrap `DowncastWriter#unwrap()`}\n\t\t\t * must be an instance of {@link module:engine/view/attributeelement~AttributeElement `AttributeElement`}.\n\t\t\t *\n\t\t\t * @error view-writer-unwrap-invalid-attribute\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-writer-unwrap-invalid-attribute',\n\t\t\t\tthis.document\n\t\t\t);\n\t\t}\n\n\t\tvalidateRangeContainer( range, this.document );\n\n\t\t// If range is collapsed - nothing to unwrap.\n\t\tif ( range.isCollapsed ) {\n\t\t\treturn range;\n\t\t}\n\n\t\t// Break attributes at range start and end.\n\t\tconst { start: breakStart, end: breakEnd } = this._breakAttributesRange( range, true );\n\t\tconst parentContainer = breakStart.parent;\n\n\t\t// Unwrap children located between break points.\n\t\tconst newRange = this._unwrapChildren( parentContainer, breakStart.offset, breakEnd.offset, attribute );\n\n\t\t// Merge attributes at the both ends and return a new range.\n\t\tconst start = this.mergeAttributes( newRange.start );\n\n\t\t// If start position was merged - move end position back.\n\t\tif ( !start.isEqual( newRange.start ) ) {\n\t\t\tnewRange.end.offset--;\n\t\t}\n\n\t\tconst end = this.mergeAttributes( newRange.end );\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Renames element by creating a copy of renamed element but with changed name and then moving contents of the\n\t * old element to the new one. Keep in mind that this will invalidate all {@link module:engine/view/position~Position positions} which\n\t * has renamed element as {@link module:engine/view/position~Position#parent a parent}.\n\t *\n\t * New element has to be created because `Element#tagName` property in DOM is readonly.\n\t *\n\t * Since this function creates a new element and removes the given one, the new element is returned to keep reference.\n\t *\n\t * @param {String} newName New name for element.\n\t * @param {module:engine/view/containerelement~ContainerElement} viewElement Element to be renamed.\n\t */\n\trename( newName, viewElement ) {\n\t\tconst newElement = new ContainerElement( this.document, newName, viewElement.getAttributes() );\n\n\t\tthis.insert( Position._createAfter( viewElement ), newElement );\n\t\tthis.move( Range._createIn( viewElement ), Position._createAt( newElement, 0 ) );\n\t\tthis.remove( Range._createOn( viewElement ) );\n\n\t\treturn newElement;\n\t}\n\n\t/**\n\t * Cleans up memory by removing obsolete cloned elements group from the writer.\n\t *\n\t * Should be used whenever all {@link module:engine/view/attributeelement~AttributeElement attribute elements}\n\t * with the same {@link module:engine/view/attributeelement~AttributeElement#id id} are going to be removed from the view and\n\t * the group will no longer be needed.\n\t *\n\t * Cloned elements group are not removed automatically in case if the group is still needed after all its elements\n\t * were removed from the view.\n\t *\n\t * Keep in mind that group names are equal to the `id` property of the attribute element.\n\t *\n\t * @param {String} groupName Name of the group to clear.\n\t */\n\tclearClonedElementsGroup( groupName ) {\n\t\tthis._cloneGroups.delete( groupName );\n\t}\n\n\t/**\n\t * Creates position at the given location. The location can be specified as:\n\t *\n\t * * a {@link module:engine/view/position~Position position},\n\t * * parent element and offset (offset defaults to `0`),\n\t * * parent element and `'end'` (sets position at the end of that element),\n\t * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).\n\t *\n\t * This method is a shortcut to other constructors such as:\n\t *\n\t * * {@link #createPositionBefore},\n\t * * {@link #createPositionAfter},\n\t *\n\t * @param {module:engine/view/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/view/item~Item view item}.\n\t */\n\tcreatePositionAt( itemOrPosition, offset ) {\n\t\treturn Position._createAt( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Creates a new position after given view item.\n\t *\n\t * @param {module:engine/view/item~Item} item View item after which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tcreatePositionAfter( item ) {\n\t\treturn Position._createAfter( item );\n\t}\n\n\t/**\n\t * Creates a new position before given view item.\n\t *\n\t * @param {module:engine/view/item~Item} item View item before which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tcreatePositionBefore( item ) {\n\t\treturn Position._createBefore( item );\n\t}\n\n\t/**\n\t * Creates a range spanning from `start` position to `end` position.\n\t *\n\t * **Note:** This factory method creates its own {@link module:engine/view/position~Position} instances basing on passed values.\n\t *\n\t * @param {module:engine/view/position~Position} start Start position.\n\t * @param {module:engine/view/position~Position} [end] End position. If not set, range will be collapsed at `start` position.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRange( start, end ) {\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.\n\t *\n\t * @param {module:engine/view/item~Item} item\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRangeOn( item ) {\n\t\treturn Range._createOn( item );\n\t}\n\n\t/**\n\t * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t * @param {module:engine/view/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRangeIn( element ) {\n\t\treturn Range._createIn( element );\n\t}\n\n\t/**\n\t Creates new {@link module:engine/view/selection~Selection} instance.\n\t *\n\t * \t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = writer.createSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tconst selection = writer.createSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tconst selection = writer.createSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tconst selection = writer.createSelection( otherSelection );\n\t *\n\t *\t\t// Creates selection from the document selection.\n\t *\t\tconst selection = writer.createSelection( editor.editing.view.document.selection );\n\t *\n\t * \t\t// Creates selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\tconst selection = writer.createSelection( position );\n\t *\n\t *\t\t// Creates collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = writer.createContainerElement( 'p' );\n\t *\t\tconst selection = writer.createSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'on' );\n\t *\n\t * `Selection`'s constructor allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = writer.createSelection( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * (and be  properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tconst selection = writer.createSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/selection~Selectable} [selectable=null]\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Offset or place when selectable is an `Item`.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t * @returns {module:engine/view/selection~Selection}\n\t */\n\tcreateSelection( selectable, placeOrOffset, options ) {\n\t\treturn new Selection( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Wraps children with provided `wrapElement`. Only children contained in `parent` element between\n\t * `startOffset` and `endOffset` will be wrapped.\n\t *\n\t * @private\n\t * @param {module:engine/view/element~Element} parent\n\t * @param {Number} startOffset\n\t * @param {Number} endOffset\n\t * @param {module:engine/view/element~Element} wrapElement\n\t */\n\t_wrapChildren( parent, startOffset, endOffset, wrapElement ) {\n\t\tlet i = startOffset;\n\t\tconst wrapPositions = [];\n\n\t\twhile ( i < endOffset ) {\n\t\t\tconst child = parent.getChild( i );\n\t\t\tconst isText = child.is( '$text' );\n\t\t\tconst isAttribute = child.is( 'attributeElement' );\n\t\t\tconst isEmpty = child.is( 'emptyElement' );\n\t\t\tconst isUI = child.is( 'uiElement' );\n\t\t\tconst isRaw = child.is( 'rawElement' );\n\n\t\t\t//\n\t\t\t// (In all examples, assume that `wrapElement` is `<span class=\"foo\">` element.)\n\t\t\t//\n\t\t\t// Check if `wrapElement` can be joined with the wrapped element. One of requirements is having same name.\n\t\t\t// If possible, join elements.\n\t\t\t//\n\t\t\t// <p><span class=\"bar\">abc</span></p>  -->  <p><span class=\"foo bar\">abc</span></p>\n\t\t\t//\n\t\t\tif ( isAttribute && this._wrapAttributeElement( wrapElement, child ) ) {\n\t\t\t\twrapPositions.push( new Position( parent, i ) );\n\t\t\t}\n\t\t\t//\n\t\t\t// Wrap the child if it is not an attribute element or if it is an attribute element that should be inside\n\t\t\t// `wrapElement` (due to priority).\n\t\t\t//\n\t\t\t// <p>abc</p>                   -->  <p><span class=\"foo\">abc</span></p>\n\t\t\t// <p><strong>abc</strong></p>  -->  <p><span class=\"foo\"><strong>abc</strong></span></p>\n\t\t\telse if ( isText || isEmpty || isUI || isRaw || ( isAttribute && shouldABeOutsideB( wrapElement, child ) ) ) {\n\t\t\t\t// Clone attribute.\n\t\t\t\tconst newAttribute = wrapElement._clone();\n\n\t\t\t\t// Wrap current node with new attribute.\n\t\t\t\tchild._remove();\n\t\t\t\tnewAttribute._appendChild( child );\n\n\t\t\t\tparent._insertChild( i, newAttribute );\n\t\t\t\tthis._addToClonedElementsGroup( newAttribute );\n\n\t\t\t\twrapPositions.push( new Position( parent, i ) );\n\t\t\t}\n\t\t\t//\n\t\t\t// If other nested attribute is found and it wasn't wrapped (see above), continue wrapping inside it.\n\t\t\t//\n\t\t\t// <p><a href=\"foo.html\">abc</a></p>  -->  <p><a href=\"foo.html\"><span class=\"foo\">abc</span></a></p>\n\t\t\t//\n\t\t\telse if ( isAttribute ) {\n\t\t\t\tthis._wrapChildren( child, 0, child.childCount, wrapElement );\n\t\t\t}\n\n\t\t\ti++;\n\t\t}\n\n\t\t// Merge at each wrap.\n\t\tlet offsetChange = 0;\n\n\t\tfor ( const position of wrapPositions ) {\n\t\t\tposition.offset -= offsetChange;\n\n\t\t\t// Do not merge with elements outside selected children.\n\t\t\tif ( position.offset == startOffset ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst newPosition = this.mergeAttributes( position );\n\n\t\t\t// If nodes were merged - other merge offsets will change.\n\t\t\tif ( !newPosition.isEqual( position ) ) {\n\t\t\t\toffsetChange++;\n\t\t\t\tendOffset--;\n\t\t\t}\n\t\t}\n\n\t\treturn Range._createFromParentsAndOffsets( parent, startOffset, parent, endOffset );\n\t}\n\n\t/**\n\t * Unwraps children from provided `unwrapElement`. Only children contained in `parent` element between\n\t * `startOffset` and `endOffset` will be unwrapped.\n\t *\n\t * @private\n\t * @param {module:engine/view/element~Element} parent\n\t * @param {Number} startOffset\n\t * @param {Number} endOffset\n\t * @param {module:engine/view/element~Element} unwrapElement\n\t */\n\t_unwrapChildren( parent, startOffset, endOffset, unwrapElement ) {\n\t\tlet i = startOffset;\n\t\tconst unwrapPositions = [];\n\n\t\t// Iterate over each element between provided offsets inside parent.\n\t\t// We don't use tree walker or range iterator because we will be removing and merging potentially multiple nodes,\n\t\t// so it could get messy. It is safer to it manually in this case.\n\t\twhile ( i < endOffset ) {\n\t\t\tconst child = parent.getChild( i );\n\n\t\t\t// Skip all text nodes. There should be no container element's here either.\n\t\t\tif ( !child.is( 'attributeElement' ) ) {\n\t\t\t\ti++;\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t//\n\t\t\t// (In all examples, assume that `unwrapElement` is `<span class=\"foo\">` element.)\n\t\t\t//\n\t\t\t// If the child is similar to the given attribute element, unwrap it - it will be completely removed.\n\t\t\t//\n\t\t\t// <p><span class=\"foo\">abc</span>xyz</p>  -->  <p>abcxyz</p>\n\t\t\t//\n\t\t\tif ( child.isSimilar( unwrapElement ) ) {\n\t\t\t\tconst unwrapped = child.getChildren();\n\t\t\t\tconst count = child.childCount;\n\n\t\t\t\t// Replace wrapper element with its children\n\t\t\t\tchild._remove();\n\t\t\t\tparent._insertChild( i, unwrapped );\n\n\t\t\t\tthis._removeFromClonedElementsGroup( child );\n\n\t\t\t\t// Save start and end position of moved items.\n\t\t\t\tunwrapPositions.push(\n\t\t\t\t\tnew Position( parent, i ),\n\t\t\t\t\tnew Position( parent, i + count )\n\t\t\t\t);\n\n\t\t\t\t// Skip elements that were unwrapped. Assuming there won't be another element to unwrap in child elements.\n\t\t\t\ti += count;\n\t\t\t\tendOffset += count - 1;\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t//\n\t\t\t// If the child is not similar but is an attribute element, try partial unwrapping - remove the same attributes/styles/classes.\n\t\t\t// Partial unwrapping will happen only if the elements have the same name.\n\t\t\t//\n\t\t\t// <p><span class=\"foo bar\">abc</span>xyz</p>  -->  <p><span class=\"bar\">abc</span>xyz</p>\n\t\t\t// <p><i class=\"foo\">abc</i>xyz</p>            -->  <p><i class=\"foo\">abc</i>xyz</p>\n\t\t\t//\n\t\t\tif ( this._unwrapAttributeElement( unwrapElement, child ) ) {\n\t\t\t\tunwrapPositions.push(\n\t\t\t\t\tnew Position( parent, i ),\n\t\t\t\t\tnew Position( parent, i + 1 )\n\t\t\t\t);\n\n\t\t\t\ti++;\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t//\n\t\t\t// If other nested attribute is found, look through it's children for elements to unwrap.\n\t\t\t//\n\t\t\t// <p><i><span class=\"foo\">abc</span></i><p>  -->  <p><i>abc</i><p>\n\t\t\t//\n\t\t\tthis._unwrapChildren( child, 0, child.childCount, unwrapElement );\n\n\t\t\ti++;\n\t\t}\n\n\t\t// Merge at each unwrap.\n\t\tlet offsetChange = 0;\n\n\t\tfor ( const position of unwrapPositions ) {\n\t\t\tposition.offset -= offsetChange;\n\n\t\t\t// Do not merge with elements outside selected children.\n\t\t\tif ( position.offset == startOffset || position.offset == endOffset ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst newPosition = this.mergeAttributes( position );\n\n\t\t\t// If nodes were merged - other merge offsets will change.\n\t\t\tif ( !newPosition.isEqual( position ) ) {\n\t\t\t\toffsetChange++;\n\t\t\t\tendOffset--;\n\t\t\t}\n\t\t}\n\n\t\treturn Range._createFromParentsAndOffsets( parent, startOffset, parent, endOffset );\n\t}\n\n\t/**\n\t * Helper function for `view.writer.wrap`. Wraps range with provided attribute element.\n\t * This method will also merge newly added attribute element with its siblings whenever possible.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-invalid-attribute` when passed attribute element is not\n\t * an instance of {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.\n\t *\n\t * @private\n\t * @param {module:engine/view/range~Range} range\n\t * @param {module:engine/view/attributeelement~AttributeElement} attribute\n\t * @returns {module:engine/view/range~Range} New range after wrapping, spanning over wrapping attribute element.\n\t */\n\t_wrapRange( range, attribute ) {\n\t\t// Break attributes at range start and end.\n\t\tconst { start: breakStart, end: breakEnd } = this._breakAttributesRange( range, true );\n\t\tconst parentContainer = breakStart.parent;\n\n\t\t// Wrap all children with attribute.\n\t\tconst newRange = this._wrapChildren( parentContainer, breakStart.offset, breakEnd.offset, attribute );\n\n\t\t// Merge attributes at the both ends and return a new range.\n\t\tconst start = this.mergeAttributes( newRange.start );\n\n\t\t// If start position was merged - move end position back.\n\t\tif ( !start.isEqual( newRange.start ) ) {\n\t\t\tnewRange.end.offset--;\n\t\t}\n\t\tconst end = this.mergeAttributes( newRange.end );\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Helper function for {@link #wrap}. Wraps position with provided attribute element.\n\t * This method will also merge newly added attribute element with its siblings whenever possible.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-invalid-attribute` when passed attribute element is not\n\t * an instance of {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.\n\t *\n\t * @private\n\t * @param {module:engine/view/position~Position} position\n\t * @param {module:engine/view/attributeelement~AttributeElement} attribute\n\t * @returns {module:engine/view/position~Position} New position after wrapping.\n\t */\n\t_wrapPosition( position, attribute ) {\n\t\t// Return same position when trying to wrap with attribute similar to position parent.\n\t\tif ( attribute.isSimilar( position.parent ) ) {\n\t\t\treturn movePositionToTextNode( position.clone() );\n\t\t}\n\n\t\t// When position is inside text node - break it and place new position between two text nodes.\n\t\tif ( position.parent.is( '$text' ) ) {\n\t\t\tposition = breakTextNode( position );\n\t\t}\n\n\t\t// Create fake element that will represent position, and will not be merged with other attributes.\n\t\tconst fakePosition = this.createAttributeElement();\n\t\tfakePosition._priority = Number.POSITIVE_INFINITY;\n\t\tfakePosition.isSimilar = () => false;\n\n\t\t// Insert fake element in position location.\n\t\tposition.parent._insertChild( position.offset, fakePosition );\n\n\t\t// Range around inserted fake attribute element.\n\t\tconst wrapRange = new Range( position, position.getShiftedBy( 1 ) );\n\n\t\t// Wrap fake element with attribute (it will also merge if possible).\n\t\tthis.wrap( wrapRange, attribute );\n\n\t\t// Remove fake element and place new position there.\n\t\tconst newPosition = new Position( fakePosition.parent, fakePosition.index );\n\t\tfakePosition._remove();\n\n\t\t// If position is placed between text nodes - merge them and return position inside.\n\t\tconst nodeBefore = newPosition.nodeBefore;\n\t\tconst nodeAfter = newPosition.nodeAfter;\n\n\t\tif ( nodeBefore instanceof Text && nodeAfter instanceof Text ) {\n\t\t\treturn mergeTextNodes( nodeBefore, nodeAfter );\n\t\t}\n\n\t\t// If position is next to text node - move position inside.\n\t\treturn movePositionToTextNode( newPosition );\n\t}\n\n\t/**\n\t * \tWraps one {@link module:engine/view/attributeelement~AttributeElement AttributeElement} into another by\n\t * \tmerging them if possible. When merging is possible - all attributes, styles and classes are moved from wrapper\n\t * \telement to element being wrapped.\n\t *\n\t * \t@private\n\t * \t@param {module:engine/view/attributeelement~AttributeElement} wrapper Wrapper AttributeElement.\n\t * \t@param {module:engine/view/attributeelement~AttributeElement} toWrap AttributeElement to wrap using wrapper element.\n\t * \t@returns {Boolean} Returns `true` if elements are merged.\n\t */\n\t_wrapAttributeElement( wrapper, toWrap ) {\n\t\tif ( !canBeJoined( wrapper, toWrap ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Can't merge if name or priority differs.\n\t\tif ( wrapper.name !== toWrap.name || wrapper.priority !== toWrap.priority ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if attributes can be merged.\n\t\tfor ( const key of wrapper.getAttributeKeys() ) {\n\t\t\t// Classes and styles should be checked separately.\n\t\t\tif ( key === 'class' || key === 'style' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If some attributes are different we cannot wrap.\n\t\t\tif ( toWrap.hasAttribute( key ) && toWrap.getAttribute( key ) !== wrapper.getAttribute( key ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Check if styles can be merged.\n\t\tfor ( const key of wrapper.getStyleNames() ) {\n\t\t\tif ( toWrap.hasStyle( key ) && toWrap.getStyle( key ) !== wrapper.getStyle( key ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Move all attributes/classes/styles from wrapper to wrapped AttributeElement.\n\t\tfor ( const key of wrapper.getAttributeKeys() ) {\n\t\t\t// Classes and styles should be checked separately.\n\t\t\tif ( key === 'class' || key === 'style' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Move only these attributes that are not present - other are similar.\n\t\t\tif ( !toWrap.hasAttribute( key ) ) {\n\t\t\t\tthis.setAttribute( key, wrapper.getAttribute( key ), toWrap );\n\t\t\t}\n\t\t}\n\n\t\tfor ( const key of wrapper.getStyleNames() ) {\n\t\t\tif ( !toWrap.hasStyle( key ) ) {\n\t\t\t\tthis.setStyle( key, wrapper.getStyle( key ), toWrap );\n\t\t\t}\n\t\t}\n\n\t\tfor ( const key of wrapper.getClassNames() ) {\n\t\t\tif ( !toWrap.hasClass( key ) ) {\n\t\t\t\tthis.addClass( key, toWrap );\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Unwraps {@link module:engine/view/attributeelement~AttributeElement AttributeElement} from another by removing\n\t * corresponding attributes, classes and styles. All attributes, classes and styles from wrapper should be present\n\t * inside element being unwrapped.\n\t *\n\t * @private\n\t * @param {module:engine/view/attributeelement~AttributeElement} wrapper Wrapper AttributeElement.\n\t * @param {module:engine/view/attributeelement~AttributeElement} toUnwrap AttributeElement to unwrap using wrapper element.\n\t * @returns {Boolean} Returns `true` if elements are unwrapped.\n\t **/\n\t_unwrapAttributeElement( wrapper, toUnwrap ) {\n\t\tif ( !canBeJoined( wrapper, toUnwrap ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Can't unwrap if name or priority differs.\n\t\tif ( wrapper.name !== toUnwrap.name || wrapper.priority !== toUnwrap.priority ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if AttributeElement has all wrapper attributes.\n\t\tfor ( const key of wrapper.getAttributeKeys() ) {\n\t\t\t// Classes and styles should be checked separately.\n\t\t\tif ( key === 'class' || key === 'style' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If some attributes are missing or different we cannot unwrap.\n\t\t\tif ( !toUnwrap.hasAttribute( key ) || toUnwrap.getAttribute( key ) !== wrapper.getAttribute( key ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Check if AttributeElement has all wrapper classes.\n\t\tif ( !toUnwrap.hasClass( ...wrapper.getClassNames() ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if AttributeElement has all wrapper styles.\n\t\tfor ( const key of wrapper.getStyleNames() ) {\n\t\t\t// If some styles are missing or different we cannot unwrap.\n\t\t\tif ( !toUnwrap.hasStyle( key ) || toUnwrap.getStyle( key ) !== wrapper.getStyle( key ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Remove all wrapper's attributes from unwrapped element.\n\t\tfor ( const key of wrapper.getAttributeKeys() ) {\n\t\t\t// Classes and styles should be checked separately.\n\t\t\tif ( key === 'class' || key === 'style' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis.removeAttribute( key, toUnwrap );\n\t\t}\n\n\t\t// Remove all wrapper's classes from unwrapped element.\n\t\tthis.removeClass( Array.from( wrapper.getClassNames() ), toUnwrap );\n\n\t\t// Remove all wrapper's styles from unwrapped element.\n\t\tthis.removeStyle( Array.from( wrapper.getStyleNames() ), toUnwrap );\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Helper function used by other `DowncastWriter` methods. Breaks attribute elements at the boundaries of given range.\n\t *\n\t * @private\n\t * @param {module:engine/view/range~Range} range Range which `start` and `end` positions will be used to break attributes.\n\t * @param {Boolean} [forceSplitText=false] If set to `true`, will break text nodes even if they are directly in container element.\n\t * This behavior will result in incorrect view state, but is needed by other view writing methods which then fixes view state.\n\t * @returns {module:engine/view/range~Range} New range with located at break positions.\n\t */\n\t_breakAttributesRange( range, forceSplitText = false ) {\n\t\tconst rangeStart = range.start;\n\t\tconst rangeEnd = range.end;\n\n\t\tvalidateRangeContainer( range, this.document );\n\n\t\t// Break at the collapsed position. Return new collapsed range.\n\t\tif ( range.isCollapsed ) {\n\t\t\tconst position = this._breakAttributes( range.start, forceSplitText );\n\n\t\t\treturn new Range( position, position );\n\t\t}\n\n\t\tconst breakEnd = this._breakAttributes( rangeEnd, forceSplitText );\n\t\tconst count = breakEnd.parent.childCount;\n\t\tconst breakStart = this._breakAttributes( rangeStart, forceSplitText );\n\n\t\t// Calculate new break end offset.\n\t\tbreakEnd.offset += breakEnd.parent.childCount - count;\n\n\t\treturn new Range( breakStart, breakEnd );\n\t}\n\n\t/**\n\t * Helper function used by other `DowncastWriter` methods. Breaks attribute elements at given position.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-cannot-break-empty-element` when break position\n\t * is placed inside {@link module:engine/view/emptyelement~EmptyElement EmptyElement}.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-cannot-break-ui-element` when break position\n\t * is placed inside {@link module:engine/view/uielement~UIElement UIElement}.\n\t *\n\t * @private\n\t * @param {module:engine/view/position~Position} position Position where to break attributes.\n\t * @param {Boolean} [forceSplitText=false] If set to `true`, will break text nodes even if they are directly in container element.\n\t * This behavior will result in incorrect view state, but is needed by other view writing methods which then fixes view state.\n\t * @returns {module:engine/view/position~Position} New position after breaking the attributes.\n\t */\n\t_breakAttributes( position, forceSplitText = false ) {\n\t\tconst positionOffset = position.offset;\n\t\tconst positionParent = position.parent;\n\n\t\t// If position is placed inside EmptyElement - throw an exception as we cannot break inside.\n\t\tif ( position.parent.is( 'emptyElement' ) ) {\n\t\t\t/**\n\t\t\t * Cannot break an `EmptyElement` instance.\n\t\t\t *\n\t\t\t * This error is thrown if\n\t\t\t * {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes `DowncastWriter#breakAttributes()`}\n\t\t\t * was executed in an incorrect position.\n\t\t\t *\n\t\t\t * @error view-writer-cannot-break-empty-element\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-cannot-break-empty-element', this.document );\n\t\t}\n\n\t\t// If position is placed inside UIElement - throw an exception as we cannot break inside.\n\t\tif ( position.parent.is( 'uiElement' ) ) {\n\t\t\t/**\n\t\t\t * Cannot break a `UIElement` instance.\n\t\t\t *\n\t\t\t * This error is thrown if\n\t\t\t * {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes `DowncastWriter#breakAttributes()`}\n\t\t\t * was executed in an incorrect position.\n\t\t\t *\n\t\t\t * @error view-writer-cannot-break-ui-element\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-cannot-break-ui-element', this.document );\n\t\t}\n\n\t\t// If position is placed inside RawElement - throw an exception as we cannot break inside.\n\t\tif ( position.parent.is( 'rawElement' ) ) {\n\t\t\t/**\n\t\t\t * Cannot break a `RawElement` instance.\n\t\t\t *\n\t\t\t * This error is thrown if\n\t\t\t * {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes `DowncastWriter#breakAttributes()`}\n\t\t\t * was executed in an incorrect position.\n\t\t\t *\n\t\t\t * @error view-writer-cannot-break-raw-element\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-cannot-break-raw-element', this.document );\n\t\t}\n\n\t\t// There are no attributes to break and text nodes breaking is not forced.\n\t\tif ( !forceSplitText && positionParent.is( '$text' ) && isContainerOrFragment( positionParent.parent ) ) {\n\t\t\treturn position.clone();\n\t\t}\n\n\t\t// Position's parent is container, so no attributes to break.\n\t\tif ( isContainerOrFragment( positionParent ) ) {\n\t\t\treturn position.clone();\n\t\t}\n\n\t\t// Break text and start again in new position.\n\t\tif ( positionParent.is( '$text' ) ) {\n\t\t\treturn this._breakAttributes( breakTextNode( position ), forceSplitText );\n\t\t}\n\n\t\tconst length = positionParent.childCount;\n\n\t\t// <p>foo<b><u>bar{}</u></b></p>\n\t\t// <p>foo<b><u>bar</u>[]</b></p>\n\t\t// <p>foo<b><u>bar</u></b>[]</p>\n\t\tif ( positionOffset == length ) {\n\t\t\tconst newPosition = new Position( positionParent.parent, positionParent.index + 1 );\n\n\t\t\treturn this._breakAttributes( newPosition, forceSplitText );\n\t\t} else {\n\t\t\t// <p>foo<b><u>{}bar</u></b></p>\n\t\t\t// <p>foo<b>[]<u>bar</u></b></p>\n\t\t\t// <p>foo{}<b><u>bar</u></b></p>\n\t\t\tif ( positionOffset === 0 ) {\n\t\t\t\tconst newPosition = new Position( positionParent.parent, positionParent.index );\n\n\t\t\t\treturn this._breakAttributes( newPosition, forceSplitText );\n\t\t\t}\n\t\t\t// <p>foo<b><u>b{}ar</u></b></p>\n\t\t\t// <p>foo<b><u>b[]ar</u></b></p>\n\t\t\t// <p>foo<b><u>b</u>[]<u>ar</u></b></p>\n\t\t\t// <p>foo<b><u>b</u></b>[]<b><u>ar</u></b></p>\n\t\t\telse {\n\t\t\t\tconst offsetAfter = positionParent.index + 1;\n\n\t\t\t\t// Break element.\n\t\t\t\tconst clonedNode = positionParent._clone();\n\n\t\t\t\t// Insert cloned node to position's parent node.\n\t\t\t\tpositionParent.parent._insertChild( offsetAfter, clonedNode );\n\t\t\t\tthis._addToClonedElementsGroup( clonedNode );\n\n\t\t\t\t// Get nodes to move.\n\t\t\t\tconst count = positionParent.childCount - positionOffset;\n\t\t\t\tconst nodesToMove = positionParent._removeChildren( positionOffset, count );\n\n\t\t\t\t// Move nodes to cloned node.\n\t\t\t\tclonedNode._appendChild( nodesToMove );\n\n\t\t\t\t// Create new position to work on.\n\t\t\t\tconst newPosition = new Position( positionParent.parent, offsetAfter );\n\n\t\t\t\treturn this._breakAttributes( newPosition, forceSplitText );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Stores the information that an {@link module:engine/view/attributeelement~AttributeElement attribute element} was\n\t * added to the tree. Saves the reference to the group in the given element and updates the group, so other elements\n\t * from the group now keep a reference to the given attribute element.\n\t *\n\t * The clones group can be obtained using {@link module:engine/view/attributeelement~AttributeElement#getElementsWithSameId}.\n\t *\n\t * Does nothing if added element has no {@link module:engine/view/attributeelement~AttributeElement#id id}.\n\t *\n\t * @private\n\t * @param {module:engine/view/attributeelement~AttributeElement} element Attribute element to save.\n\t */\n\t_addToClonedElementsGroup( element ) {\n\t\t// Add only if the element is in document tree.\n\t\tif ( !element.root.is( 'rootElement' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Traverse the element's children recursively to find other attribute elements that also might got inserted.\n\t\t// The loop is at the beginning so we can make fast returns later in the code.\n\t\tif ( element.is( 'element' ) ) {\n\t\t\tfor ( const child of element.getChildren() ) {\n\t\t\t\tthis._addToClonedElementsGroup( child );\n\t\t\t}\n\t\t}\n\n\t\tconst id = element.id;\n\n\t\tif ( !id ) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet group = this._cloneGroups.get( id );\n\n\t\tif ( !group ) {\n\t\t\tgroup = new Set();\n\t\t\tthis._cloneGroups.set( id, group );\n\t\t}\n\n\t\tgroup.add( element );\n\t\telement._clonesGroup = group;\n\t}\n\n\t/**\n\t * Removes all the information about the given {@link module:engine/view/attributeelement~AttributeElement attribute element}\n\t * from its clones group.\n\t *\n\t * Keep in mind, that the element will still keep a reference to the group (but the group will not keep a reference to it).\n\t * This allows to reference the whole group even if the element was already removed from the tree.\n\t *\n\t * Does nothing if the element has no {@link module:engine/view/attributeelement~AttributeElement#id id}.\n\t *\n\t * @private\n\t * @param {module:engine/view/attributeelement~AttributeElement} element Attribute element to remove.\n\t */\n\t_removeFromClonedElementsGroup( element ) {\n\t\t// Traverse the element's children recursively to find other attribute elements that also got removed.\n\t\t// The loop is at the beginning so we can make fast returns later in the code.\n\t\tif ( element.is( 'element' ) ) {\n\t\t\tfor ( const child of element.getChildren() ) {\n\t\t\t\tthis._removeFromClonedElementsGroup( child );\n\t\t\t}\n\t\t}\n\n\t\tconst id = element.id;\n\n\t\tif ( !id ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst group = this._cloneGroups.get( id );\n\n\t\tif ( !group ) {\n\t\t\treturn;\n\t\t}\n\n\t\tgroup.delete( element );\n\t\t// Not removing group from element on purpose!\n\t\t// If other parts of code have reference to this element, they will be able to get references to other elements from the group.\n\t}\n}\n\n// Helper function for `view.writer.wrap`. Checks if given element has any children that are not ui elements.\nfunction _hasNonUiChildren( parent ) {\n\treturn Array.from( parent.getChildren() ).some( child => !child.is( 'uiElement' ) );\n}\n\n/**\n * The `attribute` passed to {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#wrap()`}\n * must be an instance of {@link module:engine/view/attributeelement~AttributeElement `AttributeElement`}.\n *\n * @error view-writer-wrap-invalid-attribute\n */\n\n// Returns first parent container of specified {@link module:engine/view/position~Position Position}.\n// Position's parent node is checked as first, then next parents are checked.\n// Note that {@link module:engine/view/documentfragment~DocumentFragment DocumentFragment} is treated like a container.\n//\n// @param {module:engine/view/position~Position} position Position used as a start point to locate parent container.\n// @returns {module:engine/view/containerelement~ContainerElement|module:engine/view/documentfragment~DocumentFragment|undefined}\n// Parent container element or `undefined` if container is not found.\nfunction getParentContainer( position ) {\n\tlet parent = position.parent;\n\n\twhile ( !isContainerOrFragment( parent ) ) {\n\t\tif ( !parent ) {\n\t\t\treturn undefined;\n\t\t}\n\t\tparent = parent.parent;\n\t}\n\n\treturn parent;\n}\n\n// Checks if first {@link module:engine/view/attributeelement~AttributeElement AttributeElement} provided to the function\n// can be wrapped otuside second element. It is done by comparing elements'\n// {@link module:engine/view/attributeelement~AttributeElement#priority priorities}, if both have same priority\n// {@link module:engine/view/element~Element#getIdentity identities} are compared.\n//\n// @param {module:engine/view/attributeelement~AttributeElement} a\n// @param {module:engine/view/attributeelement~AttributeElement} b\n// @returns {Boolean}\nfunction shouldABeOutsideB( a, b ) {\n\tif ( a.priority < b.priority ) {\n\t\treturn true;\n\t} else if ( a.priority > b.priority ) {\n\t\treturn false;\n\t}\n\n\t// When priorities are equal and names are different - use identities.\n\treturn a.getIdentity() < b.getIdentity();\n}\n\n// Returns new position that is moved to near text node. Returns same position if there is no text node before of after\n// specified position.\n//\n//\t\t<p>foo[]</p>  ->  <p>foo{}</p>\n//\t\t<p>[]foo</p>  ->  <p>{}foo</p>\n//\n// @param {module:engine/view/position~Position} position\n// @returns {module:engine/view/position~Position} Position located inside text node or same position if there is no text nodes\n// before or after position location.\nfunction movePositionToTextNode( position ) {\n\tconst nodeBefore = position.nodeBefore;\n\n\tif ( nodeBefore && nodeBefore.is( '$text' ) ) {\n\t\treturn new Position( nodeBefore, nodeBefore.data.length );\n\t}\n\n\tconst nodeAfter = position.nodeAfter;\n\n\tif ( nodeAfter && nodeAfter.is( '$text' ) ) {\n\t\treturn new Position( nodeAfter, 0 );\n\t}\n\n\treturn position;\n}\n\n// Breaks text node into two text nodes when possible.\n//\n//\t\t<p>foo{}bar</p> -> <p>foo[]bar</p>\n//\t\t<p>{}foobar</p> -> <p>[]foobar</p>\n//\t\t<p>foobar{}</p> -> <p>foobar[]</p>\n//\n// @param {module:engine/view/position~Position} position Position that need to be placed inside text node.\n// @returns {module:engine/view/position~Position} New position after breaking text node.\nfunction breakTextNode( position ) {\n\tif ( position.offset == position.parent.data.length ) {\n\t\treturn new Position( position.parent.parent, position.parent.index + 1 );\n\t}\n\n\tif ( position.offset === 0 ) {\n\t\treturn new Position( position.parent.parent, position.parent.index );\n\t}\n\n\t// Get part of the text that need to be moved.\n\tconst textToMove = position.parent.data.slice( position.offset );\n\n\t// Leave rest of the text in position's parent.\n\tposition.parent._data = position.parent.data.slice( 0, position.offset );\n\n\t// Insert new text node after position's parent text node.\n\tposition.parent.parent._insertChild( position.parent.index + 1, new Text( position.root.document, textToMove ) );\n\n\t// Return new position between two newly created text nodes.\n\treturn new Position( position.parent.parent, position.parent.index + 1 );\n}\n\n// Merges two text nodes into first node. Removes second node and returns merge position.\n//\n// @param {module:engine/view/text~Text} t1 First text node to merge. Data from second text node will be moved at the end of\n// this text node.\n// @param {module:engine/view/text~Text} t2 Second text node to merge. This node will be removed after merging.\n// @returns {module:engine/view/position~Position} Position after merging text nodes.\nfunction mergeTextNodes( t1, t2 ) {\n\t// Merge text data into first text node and remove second one.\n\tconst nodeBeforeLength = t1.data.length;\n\tt1._data += t2.data;\n\tt2._remove();\n\n\treturn new Position( t1, nodeBeforeLength );\n}\n\n// Checks if provided nodes are valid to insert.\n//\n// Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-insert-invalid-node` when nodes to insert\n// contains instances that are not supported ones (see error description for valid ones.\n//\n// @param Iterable.<module:engine/view/text~Text|module:engine/view/element~Element> nodes\n// @param {Object} errorContext\nfunction validateNodesToInsert( nodes, errorContext ) {\n\tfor ( const node of nodes ) {\n\t\tif ( !validNodesToInsert.some( ( validNode => node instanceof validNode ) ) ) { // eslint-disable-line no-use-before-define\n\t\t\t/**\n\t\t\t * One of the nodes to be inserted is of an invalid type.\n\t\t\t *\n\t\t\t * Nodes to be inserted with {@link module:engine/view/downcastwriter~DowncastWriter#insert `DowncastWriter#insert()`} should be\n\t\t\t * of the following types:\n\t\t\t *\n\t\t\t * * {@link module:engine/view/attributeelement~AttributeElement AttributeElement},\n\t\t\t * * {@link module:engine/view/containerelement~ContainerElement ContainerElement},\n\t\t\t * * {@link module:engine/view/emptyelement~EmptyElement EmptyElement},\n\t\t\t * * {@link module:engine/view/uielement~UIElement UIElement},\n\t\t\t * * {@link module:engine/view/rawelement~RawElement RawElement},\n\t\t\t * * {@link module:engine/view/text~Text Text}.\n\t\t\t *\n\t\t\t * @error view-writer-insert-invalid-node-type\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-insert-invalid-node-type', errorContext );\n\t\t}\n\n\t\tif ( !node.is( '$text' ) ) {\n\t\t\tvalidateNodesToInsert( node.getChildren(), errorContext );\n\t\t}\n\t}\n}\n\nconst validNodesToInsert = [ Text, AttributeElement, ContainerElement, EmptyElement, RawElement, UIElement ];\n\n// Checks if node is ContainerElement or DocumentFragment, because in most cases they should be treated the same way.\n//\n// @param {module:engine/view/node~Node} node\n// @returns {Boolean} Returns `true` if node is instance of ContainerElement or DocumentFragment.\nfunction isContainerOrFragment( node ) {\n\treturn node && ( node.is( 'containerElement' ) || node.is( 'documentFragment' ) );\n}\n\n// Checks if {@link module:engine/view/range~Range#start range start} and {@link module:engine/view/range~Range#end range end} are placed\n// inside same {@link module:engine/view/containerelement~ContainerElement container element}.\n// Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when validation fails.\n//\n// @param {module:engine/view/range~Range} range\n// @param {Object} errorContext\nfunction validateRangeContainer( range, errorContext ) {\n\tconst startContainer = getParentContainer( range.start );\n\tconst endContainer = getParentContainer( range.end );\n\n\tif ( !startContainer || !endContainer || startContainer !== endContainer ) {\n\t\t/**\n\t\t * The container of the given range is invalid.\n\t\t *\n\t\t * This may happen if {@link module:engine/view/range~Range#start range start} and\n\t\t * {@link module:engine/view/range~Range#end range end} positions are not placed inside the same container element or\n\t\t * a parent container for these positions cannot be found.\n\t\t *\n\t\t * Methods like {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#remove()`},\n\t\t * {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#clean()`},\n\t\t * {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#wrap()`},\n\t\t * {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#unwrap()`} need to be called\n\t\t * on a range that has its start and end positions located in the same container element. Both positions can be\n\t\t * nested within other elements (e.g. an attribute element) but the closest container ancestor must be the same.\n\t\t *\n\t\t * @error view-writer-invalid-range-container\n\t\t */\n\t\tthrow new CKEditorError( 'view-writer-invalid-range-container', errorContext );\n\t}\n}\n\n// Checks if two attribute elements can be joined together. Elements can be joined together if, and only if\n// they do not have ids specified.\n//\n// @private\n// @param {module:engine/view/element~Element} a\n// @param {module:engine/view/element~Element} b\n// @returns {Boolean}\nfunction canBeJoined( a, b ) {\n\treturn a.id === null && b.id === null;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/istext\n */\n\n/**\n * Checks if the object is a native DOM Text node.\n *\n * @param {*} obj\n * @returns {Boolean}\n */\nexport default function isText( obj ) {\n\treturn Object.prototype.toString.call( obj ) == '[object Text]';\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport isText from '@ckeditor/ckeditor5-utils/src/dom/istext';\n\n/**\n * Set of utils related to block and inline fillers handling.\n *\n * Browsers do not allow to put caret in elements which does not have height. Because of it, we need to fill all\n * empty elements which should be selectable with elements or characters called \"fillers\". Unfortunately there is no one\n * universal filler, this is why two types are uses:\n *\n * * Block filler is an element which fill block elements, like `<p>`. CKEditor uses `<br>` as a block filler during the editing,\n * as browsers do natively. So instead of an empty `<p>` there will be `<p><br></p>`. The advantage of block filler is that\n * it is transparent for the selection, so when the caret is before the `<br>` and user presses right arrow he will be\n * moved to the next paragraph, not after the `<br>`. The disadvantage is that it breaks a block, so it can not be used\n * in the middle of a line of text. The {@link module:engine/view/filler~BR_FILLER `<br>` filler} can be replaced with any other\n * character in the data output, for instance {@link module:engine/view/filler~NBSP_FILLER non-breaking space}.\n *\n * * Inline filler is a filler which does not break a line of text, so it can be used inside the text, for instance in the empty\n * `<b>` surrendered by text: `foo<b></b>bar`, if we want to put the caret there. CKEditor uses a sequence of the zero-width\n * spaces as an {@link module:engine/view/filler~INLINE_FILLER inline filler} having the predetermined\n * {@link module:engine/view/filler~INLINE_FILLER_LENGTH length}. A sequence is used, instead of a single character to\n * avoid treating random zero-width spaces as the inline filler. Disadvantage of the inline filler is that it is not\n * transparent for the selection. The arrow key moves the caret between zero-width spaces characters, so the additional\n * code is needed to handle the caret.\n *\n * Both inline and block fillers are handled by the {@link module:engine/view/renderer~Renderer renderer} and are not present in the\n * view.\n *\n * @module engine/view/filler\n */\n\n/**\n * Non-breaking space filler creator. This is a function which creates `&nbsp;` text node.\n * It defines how the filler is created.\n *\n * @see module:engine/view/filler~BR_FILLER\n * @function\n */\nexport const NBSP_FILLER = domDocument => domDocument.createTextNode( '\\u00A0' );\n\n/**\n * `<br>` filler creator. This is a function which creates `<br data-cke-filler=\"true\">` element.\n * It defines how the filler is created.\n *\n * @see module:engine/view/filler~NBSP_FILLER\n * @function\n */\nexport const BR_FILLER = domDocument => {\n\tconst fillerBr = domDocument.createElement( 'br' );\n\tfillerBr.dataset.ckeFiller = true;\n\n\treturn fillerBr;\n};\n\n/**\n * Length of the {@link module:engine/view/filler~INLINE_FILLER INLINE_FILLER}.\n */\nexport const INLINE_FILLER_LENGTH = 7;\n\n/**\n * Inline filler which is a sequence of the zero width spaces.\n *\n * @type {String}\n */\nexport const INLINE_FILLER = ( () => {\n\tlet inlineFiller = '';\n\n\tfor ( let i = 0; i < INLINE_FILLER_LENGTH; i++ ) {\n\t\tinlineFiller += '\\u200b';\n\t}\n\n\treturn inlineFiller;\n} )(); // Usu IIF so the INLINE_FILLER appears as a constant in the docs.\n\n/**\n * Checks if the node is a text node which starts with the {@link module:engine/view/filler~INLINE_FILLER inline filler}.\n *\n *\t\tstartsWithFiller( document.createTextNode( INLINE_FILLER ) ); // true\n *\t\tstartsWithFiller( document.createTextNode( INLINE_FILLER + 'foo' ) ); // true\n *\t\tstartsWithFiller( document.createTextNode( 'foo' ) ); // false\n *\t\tstartsWithFiller( document.createElement( 'p' ) ); // false\n *\n * @param {Node} domNode DOM node.\n * @returns {Boolean} True if the text node starts with the {@link module:engine/view/filler~INLINE_FILLER inline filler}.\n */\nexport function startsWithFiller( domNode ) {\n\treturn isText( domNode ) && ( domNode.data.substr( 0, INLINE_FILLER_LENGTH ) === INLINE_FILLER );\n}\n\n/**\n * Checks if the text node contains only the {@link module:engine/view/filler~INLINE_FILLER inline filler}.\n *\n *\t\tisInlineFiller( document.createTextNode( INLINE_FILLER ) ); // true\n *\t\tisInlineFiller( document.createTextNode( INLINE_FILLER + 'foo' ) ); // false\n *\n * @param {Text} domText DOM text node.\n * @returns {Boolean} True if the text node contains only the {@link module:engine/view/filler~INLINE_FILLER inline filler}.\n */\nexport function isInlineFiller( domText ) {\n\treturn domText.data.length == INLINE_FILLER_LENGTH && startsWithFiller( domText );\n}\n\n/**\n * Get string data from the text node, removing an {@link module:engine/view/filler~INLINE_FILLER inline filler} from it,\n * if text node contains it.\n *\n *\t\tgetDataWithoutFiller( document.createTextNode( INLINE_FILLER + 'foo' ) ) == 'foo' // true\n *\t\tgetDataWithoutFiller( document.createTextNode( 'foo' ) ) == 'foo' // true\n *\n * @param {Text} domText DOM text node, possible with inline filler.\n * @returns {String} Data without filler.\n */\nexport function getDataWithoutFiller( domText ) {\n\tif ( startsWithFiller( domText ) ) {\n\t\treturn domText.data.slice( INLINE_FILLER_LENGTH );\n\t} else {\n\t\treturn domText.data;\n\t}\n}\n\n/**\n * Assign key observer which move cursor from the end of the inline filler to the beginning of it when\n * the left arrow is pressed, so the filler does not break navigation.\n *\n * @param {module:engine/view/view~View} view View controller instance we should inject quirks handling on.\n */\nexport function injectQuirksHandling( view ) {\n\tview.document.on( 'keydown', jumpOverInlineFiller );\n}\n\n// Move cursor from the end of the inline filler to the beginning of it when, so the filler does not break navigation.\nfunction jumpOverInlineFiller( evt, data ) {\n\tif ( data.keyCode == keyCodes.arrowleft ) {\n\t\tconst domSelection = data.domTarget.ownerDocument.defaultView.getSelection();\n\n\t\tif ( domSelection.rangeCount == 1 && domSelection.getRangeAt( 0 ).collapsed ) {\n\t\t\tconst domParent = domSelection.getRangeAt( 0 ).startContainer;\n\t\t\tconst domOffset = domSelection.getRangeAt( 0 ).startOffset;\n\n\t\t\tif ( startsWithFiller( domParent ) && domOffset <= INLINE_FILLER_LENGTH ) {\n\t\t\t\tdomSelection.collapse( domParent, 0 );\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/fastdiff\n */\n\n/**\n * Finds positions of the first and last change in the given string/array and generates a set of changes:\n *\n *\t\tfastDiff( '12a', '12xyza' );\n *\t\t// [ { index: 2, type: 'insert', values: [ 'x', 'y', 'z' ] } ]\n *\n *\t\tfastDiff( '12a', '12aa' );\n *\t\t// [ { index: 3, type: 'insert', values: [ 'a' ] } ]\n *\n *\t\tfastDiff( '12xyza', '12a' );\n *\t\t// [ { index: 2, type: 'delete', howMany: 3 } ]\n *\n *\t\tfastDiff( [ '1', '2', 'a', 'a' ], [ '1', '2', 'a' ] );\n *\t\t// [ { index: 3, type: 'delete', howMany: 1 } ]\n *\n *\t\tfastDiff( [ '1', '2', 'a', 'b', 'c', '3' ], [ '2', 'a', 'b' ] );\n *\t\t// [ { index: 0, type: 'insert', values: [ '2', 'a', 'b' ] }, { index: 3, type: 'delete', howMany: 6 } ]\n *\n * Passed arrays can contain any type of data, however to compare them correctly custom comparator function\n * should be passed as a third parameter:\n *\n *\t\tfastDiff( [ { value: 1 }, { value: 2 } ], [ { value: 1 }, { value: 3 } ], ( a, b ) => {\n *\t\t\treturn a.value === b.value;\n *\t\t} );\n *\t\t// [ { index: 1, type: 'insert', values: [ { value: 3 } ] }, { index: 2, type: 'delete', howMany: 1 } ]\n *\n * The resulted set of changes can be applied to the input in order to transform it into the output, for example:\n *\n *\t\tlet input = '12abc3';\n *\t\tconst output = '2ab';\n *\t\tconst changes = fastDiff( input, output );\n *\n *\t\tchanges.forEach( change => {\n *\t\t\tif ( change.type == 'insert' ) {\n *\t\t\t\tinput = input.substring( 0, change.index ) + change.values.join( '' ) + input.substring( change.index );\n *\t\t\t} else if ( change.type == 'delete' ) {\n *\t\t\t\tinput = input.substring( 0, change.index ) + input.substring( change.index + change.howMany );\n *\t\t\t}\n *\t\t} );\n *\n *\t\t// input equals output now\n *\n * or in case of arrays:\n *\n *\t\tlet input = [ '1', '2', 'a', 'b', 'c', '3' ];\n *\t\tconst output = [ '2', 'a', 'b' ];\n *\t\tconst changes = fastDiff( input, output );\n *\n *\t\tchanges.forEach( change => {\n *\t\t\tif ( change.type == 'insert' ) {\n *\t\t\t\tinput = input.slice( 0, change.index ).concat( change.values, input.slice( change.index ) );\n *\t\t\t} else if ( change.type == 'delete' ) {\n *\t\t\t\tinput = input.slice( 0, change.index ).concat( input.slice( change.index + change.howMany ) );\n *\t\t\t}\n *\t\t} );\n *\n *\t\t// input equals output now\n *\n * By passing `true` as the fourth parameter (`atomicChanges`) the output of this function will become compatible with\n * the {@link module:utils/diff~diff `diff()`} function:\n *\n *\t\tfastDiff( '12a', '12xyza' );\n *\t\t// [ 'equal', 'equal', 'insert', 'insert', 'insert', 'equal' ]\n *\n * The default output format of this function is compatible with the output format of\n * {@link module:utils/difftochanges~diffToChanges `diffToChanges()`}. The `diffToChanges()` input format is, in turn,\n * compatible with the output of {@link module:utils/diff~diff `diff()`}:\n *\n *\t\tconst a = '1234';\n *\t\tconst b = '12xyz34';\n *\n *\t\t// Both calls will return the same results (grouped changes format).\n *\t\tfastDiff( a, b );\n *\t\tdiffToChanges( diff( a, b ) );\n *\n *\t\t// Again, both calls will return the same results (atomic changes format).\n *\t\tfastDiff( a, b, null, true );\n *\t\tdiff( a, b );\n *\n *\n * @param {Array|String} a Input array or string.\n * @param {Array|String} b Input array or string.\n * @param {Function} [cmp] Optional function used to compare array values, by default `===` (strict equal operator) is used.\n * @param {Boolean} [atomicChanges=false] Whether an array of `inset|delete|equal` operations should\n * be returned instead of changes set. This makes this function compatible with {@link module:utils/diff~diff `diff()`}.\n * @returns {Array} Array of changes.\n */\nexport default function fastDiff( a, b, cmp, atomicChanges = false ) {\n\t// Set the comparator function.\n\tcmp = cmp || function( a, b ) {\n\t\treturn a === b;\n\t};\n\n\t// Convert the string (or any array-like object - eg. NodeList) to an array by using the slice() method because,\n\t// unlike Array.from(), it returns array of UTF-16 code units instead of the code points of a string.\n\t// One code point might be a surrogate pair of two code units. All text offsets are expected to be in code units.\n\t// See ckeditor/ckeditor5#3147.\n\t//\n\t// We need to make sure here that fastDiff() works identical to diff().\n\tif ( !Array.isArray( a ) ) {\n\t\ta = Array.prototype.slice.call( a );\n\t}\n\n\tif ( !Array.isArray( b ) ) {\n\t\tb = Array.prototype.slice.call( b );\n\t}\n\n\t// Find first and last change.\n\tconst changeIndexes = findChangeBoundaryIndexes( a, b, cmp );\n\n\t// Transform into changes array.\n\treturn atomicChanges ? changeIndexesToAtomicChanges( changeIndexes, b.length ) : changeIndexesToChanges( b, changeIndexes );\n}\n\n// Finds position of the first and last change in the given arrays. For example:\n//\n//\t\tconst indexes = findChangeBoundaryIndexes( [ '1', '2', '3', '4' ], [ '1', '3', '4', '2', '4' ] );\n//\t\tconsole.log( indexes ); // { firstIndex: 1, lastIndexOld: 3, lastIndexNew: 4 }\n//\n// The above indexes means that in the first array the modified part is `1[23]4` and in the second array it is `1[342]4`.\n// Based on such indexes, array with `insert`/`delete` operations which allows transforming first value into the second one\n// can be generated.\n//\n// @param {Array} arr1\n// @param {Array} arr2\n// @param {Function} cmp Comparator function.\n// @returns {Object}\n// @returns {Number} return.firstIndex Index of the first change in both values (always the same for both).\n// @returns {Number} result.lastIndexOld Index of the last common value in `arr1`.\n// @returns {Number} result.lastIndexNew Index of the last common value in `arr2`.\nfunction findChangeBoundaryIndexes( arr1, arr2, cmp ) {\n\t// Find the first difference between passed values.\n\tconst firstIndex = findFirstDifferenceIndex( arr1, arr2, cmp );\n\n\t// If arrays are equal return -1 indexes object.\n\tif ( firstIndex === -1 ) {\n\t\treturn { firstIndex: -1, lastIndexOld: -1, lastIndexNew: -1 };\n\t}\n\n\t// Remove the common part of each value and reverse them to make it simpler to find the last difference between them.\n\tconst oldArrayReversed = cutAndReverse( arr1, firstIndex );\n\tconst newArrayReversed = cutAndReverse( arr2, firstIndex );\n\n\t// Find the first difference between reversed values.\n\t// It should be treated as \"how many elements from the end the last difference occurred\".\n\t//\n\t// For example:\n\t//\n\t// \t\t\t\tinitial\t->\tafter cut\t-> reversed:\n\t// oldValue:\t'321ba'\t->\t'21ba'\t\t-> 'ab12'\n\t// newValue:\t'31xba'\t->\t'1xba'\t\t-> 'abx1'\n\t// lastIndex:\t\t\t\t\t\t\t-> 2\n\t//\n\t// So the last change occurred two characters from the end of the arrays.\n\tconst lastIndex = findFirstDifferenceIndex( oldArrayReversed, newArrayReversed, cmp );\n\n\t// Use `lastIndex` to calculate proper offset, starting from the beginning (`lastIndex` kind of starts from the end).\n\tconst lastIndexOld = arr1.length - lastIndex;\n\tconst lastIndexNew = arr2.length - lastIndex;\n\n\treturn { firstIndex, lastIndexOld, lastIndexNew };\n}\n\n// Returns a first index on which given arrays differ. If both arrays are the same, -1 is returned.\n//\n// @param {Array} arr1\n// @param {Array} arr2\n// @param {Function} cmp Comparator function.\n// @returns {Number}\nfunction findFirstDifferenceIndex( arr1, arr2, cmp ) {\n\tfor ( let i = 0; i < Math.max( arr1.length, arr2.length ); i++ ) {\n\t\tif ( arr1[ i ] === undefined || arr2[ i ] === undefined || !cmp( arr1[ i ], arr2[ i ] ) ) {\n\t\t\treturn i;\n\t\t}\n\t}\n\n\treturn -1; // Return -1 if arrays are equal.\n}\n\n// Returns a copy of the given array with `howMany` elements removed starting from the beginning and in reversed order.\n//\n// @param {Array} arr Array to be processed.\n// @param {Number} howMany How many elements from array beginning to remove.\n// @returns {Array} Shortened and reversed array.\nfunction cutAndReverse( arr, howMany ) {\n\treturn arr.slice( howMany ).reverse();\n}\n\n// Generates changes array based on change indexes from `findChangeBoundaryIndexes` function. This function will\n// generate array with 0 (no changes), 1 (deletion or insertion) or 2 records (insertion and deletion).\n//\n// @param {Array} newArray New array for which change indexes were calculated.\n// @param {Object} changeIndexes Change indexes object from `findChangeBoundaryIndexes` function.\n// @returns {Array.<Object>} Array of changes compatible with {@link module:utils/difftochanges~diffToChanges} format.\nfunction changeIndexesToChanges( newArray, changeIndexes ) {\n\tconst result = [];\n\tconst { firstIndex, lastIndexOld, lastIndexNew } = changeIndexes;\n\n\t// Order operations as 'insert', 'delete' array to keep compatibility with {@link module:utils/difftochanges~diffToChanges}\n\t// in most cases. However, 'diffToChanges' does not stick to any order so in some cases\n\t// (for example replacing '12345' with 'abcd') it will generate 'delete', 'insert' order.\n\tif ( lastIndexNew - firstIndex > 0 ) {\n\t\tresult.push( {\n\t\t\tindex: firstIndex,\n\t\t\ttype: 'insert',\n\t\t\tvalues: newArray.slice( firstIndex, lastIndexNew )\n\t\t} );\n\t}\n\n\tif ( lastIndexOld - firstIndex > 0 ) {\n\t\tresult.push( {\n\t\t\tindex: firstIndex + ( lastIndexNew - firstIndex ), // Increase index of what was inserted.\n\t\t\ttype: 'delete',\n\t\t\thowMany: lastIndexOld - firstIndex\n\t\t} );\n\t}\n\n\treturn result;\n}\n\n// Generates array with set `equal|insert|delete` operations based on change indexes from `findChangeBoundaryIndexes` function.\n//\n// @param {Object} changeIndexes Change indexes object from `findChangeBoundaryIndexes` function.\n// @param {Number} newLength Length of the new array on which `findChangeBoundaryIndexes` calculated change indexes.\n// @returns {Array.<String>} Array of changes compatible with {@link module:utils/diff~diff} format.\nfunction changeIndexesToAtomicChanges( changeIndexes, newLength ) {\n\tconst { firstIndex, lastIndexOld, lastIndexNew } = changeIndexes;\n\n\t// No changes.\n\tif ( firstIndex === -1 ) {\n\t\treturn Array( newLength ).fill( 'equal' );\n\t}\n\n\tlet result = [];\n\tif ( firstIndex > 0 ) {\n\t\tresult = result.concat( Array( firstIndex ).fill( 'equal' ) );\n\t}\n\n\tif ( lastIndexNew - firstIndex > 0 ) {\n\t\tresult = result.concat( Array( lastIndexNew - firstIndex ).fill( 'insert' ) );\n\t}\n\n\tif ( lastIndexOld - firstIndex > 0 ) {\n\t\tresult = result.concat( Array( lastIndexOld - firstIndex ).fill( 'delete' ) );\n\t}\n\n\tif ( lastIndexNew < newLength ) {\n\t\tresult = result.concat( Array( newLength - lastIndexNew ).fill( 'equal' ) );\n\t}\n\n\treturn result;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/diff\n */\n\nimport fastDiff from '../src/fastdiff';\n\n// The following code is based on the \"O(NP) Sequence Comparison Algorithm\"\n// by Sun Wu, Udi Manber, Gene Myers, Webb Miller.\n\n/**\n * Calculates the difference between two arrays or strings producing an array containing a list of changes\n * necessary to transform input into output.\n *\n *\t\tdiff( 'aba', 'acca' ); // [ 'equal', 'insert', 'insert', 'delete', 'equal' ]\n *\n * This function is based on the \"O(NP) Sequence Comparison Algorithm\" by Sun Wu, Udi Manber, Gene Myers, Webb Miller.\n * Unfortunately, while it gives the most precise results, its to complex for longer strings/arrow (above 200 items).\n * Therefore, `diff()` automatically switches to {@link module:utils/fastdiff~fastDiff `fastDiff()`} when detecting\n * such a scenario. The return formats of both functions are identical.\n *\n * @param {Array|String} a Input array or string.\n * @param {Array|String} b Output array or string.\n * @param {Function} [cmp] Optional function used to compare array values, by default === is used.\n * @returns {Array} Array of changes.\n */\nexport default function diff( a, b, cmp ) {\n\t// Set the comparator function.\n\tcmp = cmp || function( a, b ) {\n\t\treturn a === b;\n\t};\n\n\tconst aLength = a.length;\n\tconst bLength = b.length;\n\n\t// Perform `fastDiff` for longer strings/arrays (see #269).\n\tif ( aLength > 200 || bLength > 200 || aLength + bLength > 300 ) {\n\t\treturn diff.fastDiff( a, b, cmp, true );\n\t}\n\n\t// Temporary action type statics.\n\tlet _insert, _delete;\n\n\t// Swapped the arrays to use the shorter one as the first one.\n\tif ( bLength < aLength ) {\n\t\tconst tmp = a;\n\n\t\ta = b;\n\t\tb = tmp;\n\n\t\t// We swap the action types as well.\n\t\t_insert = 'delete';\n\t\t_delete = 'insert';\n\t} else {\n\t\t_insert = 'insert';\n\t\t_delete = 'delete';\n\t}\n\n\tconst m = a.length;\n\tconst n = b.length;\n\tconst delta = n - m;\n\n\t// Edit scripts, for each diagonal.\n\tconst es = {};\n\t// Furthest points, the furthest y we can get on each diagonal.\n\tconst fp = {};\n\n\tfunction snake( k ) {\n\t\t// We use -1 as an alternative below to handle initial values ( instead of filling the fp with -1 first ).\n\t\t// Furthest points (y) on the diagonal below k.\n\t\tconst y1 = ( fp[ k - 1 ] !== undefined ? fp[ k - 1 ] : -1 ) + 1;\n\t\t// Furthest points (y) on the diagonal above k.\n\t\tconst y2 = fp[ k + 1 ] !== undefined ? fp[ k + 1 ] : -1;\n\t\t// The way we should go to get further.\n\t\tconst dir = y1 > y2 ? -1 : 1;\n\n\t\t// Clone previous changes array (if any).\n\t\tif ( es[ k + dir ] ) {\n\t\t\tes[ k ] = es[ k + dir ].slice( 0 );\n\t\t}\n\n\t\t// Create changes array.\n\t\tif ( !es[ k ] ) {\n\t\t\tes[ k ] = [];\n\t\t}\n\n\t\t// Push the action.\n\t\tes[ k ].push( y1 > y2 ? _insert : _delete );\n\n\t\t// Set the beginning coordinates.\n\t\tlet y = Math.max( y1, y2 );\n\t\tlet x = y - k;\n\n\t\t// Traverse the diagonal as long as the values match.\n\t\twhile ( x < m && y < n && cmp( a[ x ], b[ y ] ) ) {\n\t\t\tx++;\n\t\t\ty++;\n\t\t\t// Push no change action.\n\t\t\tes[ k ].push( 'equal' );\n\t\t}\n\n\t\treturn y;\n\t}\n\n\tlet p = 0;\n\tlet k;\n\n\t// Traverse the graph until we reach the end of the longer string.\n\tdo {\n\t\t// Updates furthest points and edit scripts for diagonals below delta.\n\t\tfor ( k = -p; k < delta; k++ ) {\n\t\t\tfp[ k ] = snake( k );\n\t\t}\n\n\t\t// Updates furthest points and edit scripts for diagonals above delta.\n\t\tfor ( k = delta + p; k > delta; k-- ) {\n\t\t\tfp[ k ] = snake( k );\n\t\t}\n\n\t\t// Updates furthest point and edit script for the delta diagonal.\n\t\t// note that the delta diagonal is the one which goes through the sink (m, n).\n\t\tfp[ delta ] = snake( delta );\n\n\t\tp++;\n\t} while ( fp[ delta ] !== n );\n\n\t// Return the final list of edit changes.\n\t// We remove the first item that represents the action for the injected nulls.\n\treturn es[ delta ].slice( 1 );\n}\n\n// Store the API in static property to easily overwrite it in tests.\n// Too bad dependency injection does not work in Webpack + ES 6 (const) + Babel.\ndiff.fastDiff = fastDiff;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/insertat\n */\n\n/**\n * Inserts node to the parent at given index.\n *\n * @param {Element} parentElement Parent element.\n * @param {Number} index Insertions index.\n * @param {Node} nodeToInsert Node to insert.\n */\nexport default function insertAt( parentElement, index, nodeToInsert ) {\n\tparentElement.insertBefore( nodeToInsert, parentElement.childNodes[ index ] || null );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/remove\n */\n\n/**\n * Removes given node from parent.\n *\n * @param {Node} node Node to remove.\n */\nexport default function remove( node ) {\n\tconst parent = node.parentNode;\n\n\tif ( parent ) {\n\t\tparent.removeChild( node );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/isnode\n */\n\n/**\n * Checks if the object is a native DOM Node.\n *\n * @param {*} obj\n * @returns {Boolean}\n */\nexport default function isNode( obj ) {\n\tif ( obj ) {\n\t\tif ( obj.defaultView ) {\n\t\t\treturn obj instanceof obj.defaultView.Document;\n\t\t} else if ( obj.ownerDocument && obj.ownerDocument.defaultView ) {\n\t\t\treturn obj instanceof obj.ownerDocument.defaultView.Node;\n\t\t}\n\t}\n\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* globals Node */\n\n/**\n * @module engine/view/renderer\n */\n\nimport ViewText from './text';\nimport ViewPosition from './position';\nimport { INLINE_FILLER, INLINE_FILLER_LENGTH, startsWithFiller, isInlineFiller } from './filler';\n\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport diff from '@ckeditor/ckeditor5-utils/src/diff';\nimport insertAt from '@ckeditor/ckeditor5-utils/src/dom/insertat';\nimport remove from '@ckeditor/ckeditor5-utils/src/dom/remove';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport isText from '@ckeditor/ckeditor5-utils/src/dom/istext';\nimport isNode from '@ckeditor/ckeditor5-utils/src/dom/isnode';\nimport fastDiff from '@ckeditor/ckeditor5-utils/src/fastdiff';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\n/**\n * Renderer is responsible for updating the DOM structure and the DOM selection based on\n * the {@link module:engine/view/renderer~Renderer#markToSync information about updated view nodes}.\n * In other words, it renders the view to the DOM.\n *\n * Its main responsibility is to make only the necessary, minimal changes to the DOM. However, unlike in many\n * virtual DOM implementations, the primary reason for doing minimal changes is not the performance but ensuring\n * that native editing features such as text composition, autocompletion, spell checking, selection's x-index are\n * affected as little as possible.\n *\n * Renderer uses {@link module:engine/view/domconverter~DomConverter} to transform view nodes and positions\n * to and from the DOM.\n */\nexport default class Renderer {\n\t/**\n\t * Creates a renderer instance.\n\t *\n\t * @param {module:engine/view/domconverter~DomConverter} domConverter Converter instance.\n\t * @param {module:engine/view/documentselection~DocumentSelection} selection View selection.\n\t */\n\tconstructor( domConverter, selection ) {\n\t\t/**\n\t\t * Set of DOM Documents instances.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Set.<Document>}\n\t\t */\n\t\tthis.domDocuments = new Set();\n\n\t\t/**\n\t\t * Converter instance.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/domconverter~DomConverter}\n\t\t */\n\t\tthis.domConverter = domConverter;\n\n\t\t/**\n\t\t * Set of nodes which attributes changed and may need to be rendered.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Set.<module:engine/view/node~Node>}\n\t\t */\n\t\tthis.markedAttributes = new Set();\n\n\t\t/**\n\t\t * Set of elements which child lists changed and may need to be rendered.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Set.<module:engine/view/node~Node>}\n\t\t */\n\t\tthis.markedChildren = new Set();\n\n\t\t/**\n\t\t * Set of text nodes which text data changed and may need to be rendered.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Set.<module:engine/view/node~Node>}\n\t\t */\n\t\tthis.markedTexts = new Set();\n\n\t\t/**\n\t\t * View selection. Renderer updates DOM selection based on the view selection.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/documentselection~DocumentSelection}\n\t\t */\n\t\tthis.selection = selection;\n\n\t\t/**\n\t\t * Indicates if the view document is focused and selection can be rendered. Selection will not be rendered if\n\t\t * this is set to `false`.\n\t\t *\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis.isFocused = false;\n\n\t\t/**\n\t\t * The text node in which the inline filler was rendered.\n\t\t *\n\t\t * @private\n\t\t * @member {Text}\n\t\t */\n\t\tthis._inlineFiller = null;\n\n\t\t/**\n\t\t * DOM element containing fake selection.\n\t\t *\n\t\t * @private\n\t\t * @type {null|HTMLElement}\n\t\t */\n\t\tthis._fakeSelectionContainer = null;\n\t}\n\n\t/**\n\t * Marks a view node to be updated in the DOM by {@link #render `render()`}.\n\t *\n\t * Note that only view nodes whose parents have corresponding DOM elements need to be marked to be synchronized.\n\t *\n\t * @see #markedAttributes\n\t * @see #markedChildren\n\t * @see #markedTexts\n\t *\n\t * @param {module:engine/view/document~ChangeType} type Type of the change.\n\t * @param {module:engine/view/node~Node} node Node to be marked.\n\t */\n\tmarkToSync( type, node ) {\n\t\tif ( type === 'text' ) {\n\t\t\tif ( this.domConverter.mapViewToDom( node.parent ) ) {\n\t\t\t\tthis.markedTexts.add( node );\n\t\t\t}\n\t\t} else {\n\t\t\t// If the node has no DOM element it is not rendered yet,\n\t\t\t// its children/attributes do not need to be marked to be sync.\n\t\t\tif ( !this.domConverter.mapViewToDom( node ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( type === 'attributes' ) {\n\t\t\t\tthis.markedAttributes.add( node );\n\t\t\t} else if ( type === 'children' ) {\n\t\t\t\tthis.markedChildren.add( node );\n\t\t\t} else {\n\t\t\t\t/**\n\t\t\t\t * Unknown type passed to Renderer.markToSync.\n\t\t\t\t *\n\t\t\t\t * @error view-renderer-unknown-type\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'view-renderer-unknown-type', this );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Renders all buffered changes ({@link #markedAttributes}, {@link #markedChildren} and {@link #markedTexts}) and\n\t * the current view selection (if needed) to the DOM by applying a minimal set of changes to it.\n\t *\n\t * Renderer tries not to break the text composition (e.g. IME) and x-index of the selection,\n\t * so it does as little as it is needed to update the DOM.\n\t *\n\t * Renderer also handles {@link module:engine/view/filler fillers}. Especially, it checks if the inline filler is needed\n\t * at the selection position and adds or removes it. To prevent breaking text composition inline filler will not be\n\t * removed as long as the selection is in the text node which needed it at first.\n\t */\n\trender() {\n\t\tlet inlineFillerPosition;\n\n\t\t// Refresh mappings.\n\t\tfor ( const element of this.markedChildren ) {\n\t\t\tthis._updateChildrenMappings( element );\n\t\t}\n\n\t\t// There was inline filler rendered in the DOM but it's not\n\t\t// at the selection position any more, so we can remove it\n\t\t// (cause even if it's needed, it must be placed in another location).\n\t\tif ( this._inlineFiller && !this._isSelectionInInlineFiller() ) {\n\t\t\tthis._removeInlineFiller();\n\t\t}\n\n\t\t// If we've got the filler, let's try to guess its position in the view.\n\t\tif ( this._inlineFiller ) {\n\t\t\tinlineFillerPosition = this._getInlineFillerPosition();\n\t\t}\n\t\t// Otherwise, if it's needed, create it at the selection position.\n\t\telse if ( this._needsInlineFillerAtSelection() ) {\n\t\t\tinlineFillerPosition = this.selection.getFirstPosition();\n\n\t\t\t// Do not use `markToSync` so it will be added even if the parent is already added.\n\t\t\tthis.markedChildren.add( inlineFillerPosition.parent );\n\t\t}\n\n\t\tfor ( const element of this.markedAttributes ) {\n\t\t\tthis._updateAttrs( element );\n\t\t}\n\n\t\tfor ( const element of this.markedChildren ) {\n\t\t\tthis._updateChildren( element, { inlineFillerPosition } );\n\t\t}\n\n\t\tfor ( const node of this.markedTexts ) {\n\t\t\tif ( !this.markedChildren.has( node.parent ) && this.domConverter.mapViewToDom( node.parent ) ) {\n\t\t\t\tthis._updateText( node, { inlineFillerPosition } );\n\t\t\t}\n\t\t}\n\n\t\t// Check whether the inline filler is required and where it really is in the DOM.\n\t\t// At this point in most cases it will be in the DOM, but there are exceptions.\n\t\t// For example, if the inline filler was deep in the created DOM structure, it will not be created.\n\t\t// Similarly, if it was removed at the beginning of this function and then neither text nor children were updated,\n\t\t// it will not be present.\n\t\t// Fix those and similar scenarios.\n\t\tif ( inlineFillerPosition ) {\n\t\t\tconst fillerDomPosition = this.domConverter.viewPositionToDom( inlineFillerPosition );\n\t\t\tconst domDocument = fillerDomPosition.parent.ownerDocument;\n\n\t\t\tif ( !startsWithFiller( fillerDomPosition.parent ) ) {\n\t\t\t\t// Filler has not been created at filler position. Create it now.\n\t\t\t\tthis._inlineFiller = addInlineFiller( domDocument, fillerDomPosition.parent, fillerDomPosition.offset );\n\t\t\t} else {\n\t\t\t\t// Filler has been found, save it.\n\t\t\t\tthis._inlineFiller = fillerDomPosition.parent;\n\t\t\t}\n\t\t} else {\n\t\t\t// There is no filler needed.\n\t\t\tthis._inlineFiller = null;\n\t\t}\n\n\t\tthis._updateSelection();\n\t\tthis._updateFocus();\n\n\t\tthis.markedTexts.clear();\n\t\tthis.markedAttributes.clear();\n\t\tthis.markedChildren.clear();\n\t}\n\n\t/**\n\t * Updates mappings of view element's children.\n\t *\n\t * Children that were replaced in the view structure by similar elements (same tag name) are treated as 'replaced'.\n\t * This means that their mappings can be updated so the new view elements are mapped to the existing DOM elements.\n\t * Thanks to that these elements do not need to be re-rendered completely.\n\t *\n\t * @private\n\t * @param {module:engine/view/node~Node} viewElement The view element whose children mappings will be updated.\n\t */\n\t_updateChildrenMappings( viewElement ) {\n\t\tconst domElement = this.domConverter.mapViewToDom( viewElement );\n\n\t\tif ( !domElement ) {\n\t\t\t// If there is no `domElement` it means that it was already removed from DOM and there is no need to process it.\n\t\t\treturn;\n\t\t}\n\n\t\tconst actualDomChildren = this.domConverter.mapViewToDom( viewElement ).childNodes;\n\t\tconst expectedDomChildren = Array.from(\n\t\t\tthis.domConverter.viewChildrenToDom( viewElement, domElement.ownerDocument, { withChildren: false } )\n\t\t);\n\t\tconst diff = this._diffNodeLists( actualDomChildren, expectedDomChildren );\n\t\tconst actions = this._findReplaceActions( diff, actualDomChildren, expectedDomChildren );\n\n\t\tif ( actions.indexOf( 'replace' ) !== -1 ) {\n\t\t\tconst counter = { equal: 0, insert: 0, delete: 0 };\n\n\t\t\tfor ( const action of actions ) {\n\t\t\t\tif ( action === 'replace' ) {\n\t\t\t\t\tconst insertIndex = counter.equal + counter.insert;\n\t\t\t\t\tconst deleteIndex = counter.equal + counter.delete;\n\t\t\t\t\tconst viewChild = viewElement.getChild( insertIndex );\n\n\t\t\t\t\t// UIElement and RawElement are special cases. Their children are not stored in a view (#799)\n\t\t\t\t\t// so we cannot use them with replacing flow (since they use view children during rendering\n\t\t\t\t\t// which will always result in rendering empty elements).\n\t\t\t\t\tif ( viewChild && !( viewChild.is( 'uiElement' ) || viewChild.is( 'rawElement' ) ) ) {\n\t\t\t\t\t\tthis._updateElementMappings( viewChild, actualDomChildren[ deleteIndex ] );\n\t\t\t\t\t}\n\n\t\t\t\t\tremove( expectedDomChildren[ insertIndex ] );\n\t\t\t\t\tcounter.equal++;\n\t\t\t\t} else {\n\t\t\t\t\tcounter[ action ]++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Updates mappings of a given view element.\n\t *\n\t * @private\n\t * @param {module:engine/view/node~Node} viewElement The view element whose mappings will be updated.\n\t * @param {Node} domElement The DOM element representing the given view element.\n\t */\n\t_updateElementMappings( viewElement, domElement ) {\n\t\t// Remap 'DomConverter' bindings.\n\t\tthis.domConverter.unbindDomElement( domElement );\n\t\tthis.domConverter.bindElements( domElement, viewElement );\n\n\t\t// View element may have children which needs to be updated, but are not marked, mark them to update.\n\t\tthis.markedChildren.add( viewElement );\n\n\t\t// Because we replace new view element mapping with the existing one, the corresponding DOM element\n\t\t// will not be rerendered. The new view element may have different attributes than the previous one.\n\t\t// Since its corresponding DOM element will not be rerendered, new attributes will not be added\n\t\t// to the DOM, so we need to mark it here to make sure its attributes gets updated. See #1427 for more\n\t\t// detailed case study.\n\t\t// Also there are cases where replaced element is removed from the view structure and then has\n\t\t// its attributes changed or removed. In such cases the element will not be present in `markedAttributes`\n\t\t// and also may be the same (`element.isSimilar()`) as the reused element not having its attributes updated.\n\t\t// To prevent such situations we always mark reused element to have its attributes rerenderd (#1560).\n\t\tthis.markedAttributes.add( viewElement );\n\t}\n\n\t/**\n\t * Gets the position of the inline filler based on the current selection.\n\t * Here, we assume that we know that the filler is needed and\n\t * {@link #_isSelectionInInlineFiller is at the selection position}, and, since it is needed,\n\t * it is somewhere at the selection position.\n\t *\n\t * Note: The filler position cannot be restored based on the filler's DOM text node, because\n\t * when this method is called (before rendering), the bindings will often be broken. View-to-DOM\n\t * bindings are only dependable after rendering.\n\t *\n\t * @private\n\t * @returns {module:engine/view/position~Position}\n\t */\n\t_getInlineFillerPosition() {\n\t\tconst firstPos = this.selection.getFirstPosition();\n\n\t\tif ( firstPos.parent.is( '$text' ) ) {\n\t\t\treturn ViewPosition._createBefore( this.selection.getFirstPosition().parent );\n\t\t} else {\n\t\t\treturn firstPos;\n\t\t}\n\t}\n\n\t/**\n\t * Returns `true` if the selection has not left the inline filler's text node.\n\t * If it is `true`, it means that the filler had been added for a reason and the selection did not\n\t * leave the filler's text node. For example, the user can be in the middle of a composition so it should not be touched.\n\t *\n\t * @private\n\t * @returns {Boolean} `true` if the inline filler and selection are in the same place.\n\t */\n\t_isSelectionInInlineFiller() {\n\t\tif ( this.selection.rangeCount != 1 || !this.selection.isCollapsed ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Note, we can't check if selection's position equals position of the\n\t\t// this._inlineFiller node, because of #663. We may not be able to calculate\n\t\t// the filler's position in the view at this stage.\n\t\t// Instead, we check it the other way – whether selection is anchored in\n\t\t// that text node or next to it.\n\n\t\t// Possible options are:\n\t\t// \"FILLER{}\"\n\t\t// \"FILLERadded-text{}\"\n\t\tconst selectionPosition = this.selection.getFirstPosition();\n\t\tconst position = this.domConverter.viewPositionToDom( selectionPosition );\n\n\t\tif ( position && isText( position.parent ) && startsWithFiller( position.parent ) ) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Removes the inline filler.\n\t *\n\t * @private\n\t */\n\t_removeInlineFiller() {\n\t\tconst domFillerNode = this._inlineFiller;\n\n\t\t// Something weird happened and the stored node doesn't contain the filler's text.\n\t\tif ( !startsWithFiller( domFillerNode ) ) {\n\t\t\t/**\n\t\t\t * The inline filler node was lost. Most likely, something overwrote the filler text node\n\t\t\t * in the DOM.\n\t\t\t *\n\t\t\t * @error view-renderer-filler-was-lost\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-renderer-filler-was-lost', this );\n\t\t}\n\n\t\tif ( isInlineFiller( domFillerNode ) ) {\n\t\t\tdomFillerNode.parentNode.removeChild( domFillerNode );\n\t\t} else {\n\t\t\tdomFillerNode.data = domFillerNode.data.substr( INLINE_FILLER_LENGTH );\n\t\t}\n\n\t\tthis._inlineFiller = null;\n\t}\n\n\t/**\n\t * Checks if the inline {@link module:engine/view/filler filler} should be added.\n\t *\n\t * @private\n\t * @returns {Boolean} `true` if the inline filler should be added.\n\t */\n\t_needsInlineFillerAtSelection() {\n\t\tif ( this.selection.rangeCount != 1 || !this.selection.isCollapsed ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst selectionPosition = this.selection.getFirstPosition();\n\t\tconst selectionParent = selectionPosition.parent;\n\t\tconst selectionOffset = selectionPosition.offset;\n\n\t\t// If there is no DOM root we do not care about fillers.\n\t\tif ( !this.domConverter.mapViewToDom( selectionParent.root ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( !( selectionParent.is( 'element' ) ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Prevent adding inline filler inside elements with contenteditable=false.\n\t\t// https://github.com/ckeditor/ckeditor5-engine/issues/1170\n\t\tif ( !isEditable( selectionParent ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// We have block filler, we do not need inline one.\n\t\tif ( selectionOffset === selectionParent.getFillerOffset() ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst nodeBefore = selectionPosition.nodeBefore;\n\t\tconst nodeAfter = selectionPosition.nodeAfter;\n\n\t\tif ( nodeBefore instanceof ViewText || nodeAfter instanceof ViewText ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Checks if text needs to be updated and possibly updates it.\n\t *\n\t * @private\n\t * @param {module:engine/view/text~Text} viewText View text to update.\n\t * @param {Object} options\n\t * @param {module:engine/view/position~Position} options.inlineFillerPosition The position where the inline\n\t * filler should be rendered.\n\t */\n\t_updateText( viewText, options ) {\n\t\tconst domText = this.domConverter.findCorrespondingDomText( viewText );\n\t\tconst newDomText = this.domConverter.viewToDom( viewText, domText.ownerDocument );\n\n\t\tconst actualText = domText.data;\n\t\tlet expectedText = newDomText.data;\n\n\t\tconst filler = options.inlineFillerPosition;\n\n\t\tif ( filler && filler.parent == viewText.parent && filler.offset == viewText.index ) {\n\t\t\texpectedText = INLINE_FILLER + expectedText;\n\t\t}\n\n\t\tif ( actualText != expectedText ) {\n\t\t\tconst actions = fastDiff( actualText, expectedText );\n\n\t\t\tfor ( const action of actions ) {\n\t\t\t\tif ( action.type === 'insert' ) {\n\t\t\t\t\tdomText.insertData( action.index, action.values.join( '' ) );\n\t\t\t\t} else { // 'delete'\n\t\t\t\t\tdomText.deleteData( action.index, action.howMany );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks if attribute list needs to be updated and possibly updates it.\n\t *\n\t * @private\n\t * @param {module:engine/view/element~Element} viewElement The view element to update.\n\t */\n\t_updateAttrs( viewElement ) {\n\t\tconst domElement = this.domConverter.mapViewToDom( viewElement );\n\n\t\tif ( !domElement ) {\n\t\t\t// If there is no `domElement` it means that 'viewElement' is outdated as its mapping was updated\n\t\t\t// in 'this._updateChildrenMappings()'. There is no need to process it as new view element which\n\t\t\t// replaced old 'viewElement' mapping was also added to 'this.markedAttributes'\n\t\t\t// in 'this._updateChildrenMappings()' so it will be processed separately.\n\t\t\treturn;\n\t\t}\n\n\t\tconst domAttrKeys = Array.from( domElement.attributes ).map( attr => attr.name );\n\t\tconst viewAttrKeys = viewElement.getAttributeKeys();\n\n\t\t// Add or overwrite attributes.\n\t\tfor ( const key of viewAttrKeys ) {\n\t\t\tdomElement.setAttribute( key, viewElement.getAttribute( key ) );\n\t\t}\n\n\t\t// Remove from DOM attributes which do not exists in the view.\n\t\tfor ( const key of domAttrKeys ) {\n\t\t\tif ( !viewElement.hasAttribute( key ) ) {\n\t\t\t\tdomElement.removeAttribute( key );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks if elements child list needs to be updated and possibly updates it.\n\t *\n\t * @private\n\t * @param {module:engine/view/element~Element} viewElement View element to update.\n\t * @param {Object} options\n\t * @param {module:engine/view/position~Position} options.inlineFillerPosition The position where the inline\n\t * filler should be rendered.\n\t */\n\t_updateChildren( viewElement, options ) {\n\t\tconst domElement = this.domConverter.mapViewToDom( viewElement );\n\n\t\tif ( !domElement ) {\n\t\t\t// If there is no `domElement` it means that it was already removed from DOM.\n\t\t\t// There is no need to process it. It will be processed when re-inserted.\n\t\t\treturn;\n\t\t}\n\n\t\tconst inlineFillerPosition = options.inlineFillerPosition;\n\t\tconst actualDomChildren = this.domConverter.mapViewToDom( viewElement ).childNodes;\n\t\tconst expectedDomChildren = Array.from(\n\t\t\tthis.domConverter.viewChildrenToDom( viewElement, domElement.ownerDocument, { bind: true, inlineFillerPosition } )\n\t\t);\n\n\t\t// Inline filler element has to be created as it is present in the DOM, but not in the view. It is required\n\t\t// during diffing so text nodes could be compared correctly and also during rendering to maintain\n\t\t// proper order and indexes while updating the DOM.\n\t\tif ( inlineFillerPosition && inlineFillerPosition.parent === viewElement ) {\n\t\t\taddInlineFiller( domElement.ownerDocument, expectedDomChildren, inlineFillerPosition.offset );\n\t\t}\n\n\t\tconst diff = this._diffNodeLists( actualDomChildren, expectedDomChildren );\n\n\t\tlet i = 0;\n\t\tconst nodesToUnbind = new Set();\n\n\t\t// Handle deletions first.\n\t\t// This is to prevent a situation where an element that already exists in `actualDomChildren` is inserted at a different\n\t\t// index in `actualDomChildren`. Since `actualDomChildren` is a `NodeList`, this works like move, not like an insert,\n\t\t// and it disrupts the whole algorithm. See https://github.com/ckeditor/ckeditor5/issues/6367.\n\t\t//\n\t\t// It doesn't matter in what order we remove or add nodes, as long as we remove and add correct nodes at correct indexes.\n\t\tfor ( const action of diff ) {\n\t\t\tif ( action === 'delete' ) {\n\t\t\t\tnodesToUnbind.add( actualDomChildren[ i ] );\n\t\t\t\tremove( actualDomChildren[ i ] );\n\t\t\t} else if ( action === 'equal' ) {\n\t\t\t\ti++;\n\t\t\t}\n\t\t}\n\n\t\ti = 0;\n\n\t\tfor ( const action of diff ) {\n\t\t\tif ( action === 'insert' ) {\n\t\t\t\tinsertAt( domElement, i, expectedDomChildren[ i ] );\n\t\t\t\ti++;\n\t\t\t} else if ( action === 'equal' ) {\n\t\t\t\t// Force updating text nodes inside elements which did not change and do not need to be re-rendered (#1125).\n\t\t\t\t// Do it here (not in the loop above) because only after insertions the `i` index is correct.\n\t\t\t\tthis._markDescendantTextToSync( this.domConverter.domToView( expectedDomChildren[ i ] ) );\n\t\t\t\ti++;\n\t\t\t}\n\t\t}\n\n\t\t// Unbind removed nodes. When node does not have a parent it means that it was removed from DOM tree during\n\t\t// comparison with the expected DOM. We don't need to check child nodes, because if child node was reinserted,\n\t\t// it was moved to DOM tree out of the removed node.\n\t\tfor ( const node of nodesToUnbind ) {\n\t\t\tif ( !node.parentNode ) {\n\t\t\t\tthis.domConverter.unbindDomElement( node );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Shorthand for diffing two arrays or node lists of DOM nodes.\n\t *\n\t * @private\n\t * @param {Array.<Node>|NodeList} actualDomChildren Actual DOM children\n\t * @param {Array.<Node>|NodeList} expectedDomChildren Expected DOM children.\n\t * @returns {Array.<String>} The list of actions based on the {@link module:utils/diff~diff} function.\n\t */\n\t_diffNodeLists( actualDomChildren, expectedDomChildren ) {\n\t\tactualDomChildren = filterOutFakeSelectionContainer( actualDomChildren, this._fakeSelectionContainer );\n\n\t\treturn diff( actualDomChildren, expectedDomChildren, sameNodes.bind( null, this.domConverter ) );\n\t}\n\n\t/**\n\t * Finds DOM nodes that were replaced with the similar nodes (same tag name) in the view. All nodes are compared\n\t * within one `insert`/`delete` action group, for example:\n\t *\n\t * \t\tActual DOM:\t\t<p><b>Foo</b>Bar<i>Baz</i><b>Bax</b></p>\n\t * \t\tExpected DOM:\t<p>Bar<b>123</b><i>Baz</i><b>456</b></p>\n\t * \t\tInput actions:\t[ insert, insert, delete, delete, equal, insert, delete ]\n\t * \t\tOutput actions:\t[ insert, replace, delete, equal, replace ]\n\t *\n\t * @private\n\t * @param {Array.<String>} actions Actions array which is a result of the {@link module:utils/diff~diff} function.\n\t * @param {Array.<Node>|NodeList} actualDom Actual DOM children\n\t * @param {Array.<Node>} expectedDom Expected DOM children.\n\t * @returns {Array.<String>} Actions array modified with the `replace` actions.\n\t */\n\t_findReplaceActions( actions, actualDom, expectedDom ) {\n\t\t// If there is no both 'insert' and 'delete' actions, no need to check for replaced elements.\n\t\tif ( actions.indexOf( 'insert' ) === -1 || actions.indexOf( 'delete' ) === -1 ) {\n\t\t\treturn actions;\n\t\t}\n\n\t\tlet newActions = [];\n\t\tlet actualSlice = [];\n\t\tlet expectedSlice = [];\n\n\t\tconst counter = { equal: 0, insert: 0, delete: 0 };\n\n\t\tfor ( const action of actions ) {\n\t\t\tif ( action === 'insert' ) {\n\t\t\t\texpectedSlice.push( expectedDom[ counter.equal + counter.insert ] );\n\t\t\t} else if ( action === 'delete' ) {\n\t\t\t\tactualSlice.push( actualDom[ counter.equal + counter.delete ] );\n\t\t\t} else { // equal\n\t\t\t\tnewActions = newActions.concat( diff( actualSlice, expectedSlice, areSimilar ).map( x => x === 'equal' ? 'replace' : x ) );\n\t\t\t\tnewActions.push( 'equal' );\n\t\t\t\t// Reset stored elements on 'equal'.\n\t\t\t\tactualSlice = [];\n\t\t\t\texpectedSlice = [];\n\t\t\t}\n\t\t\tcounter[ action ]++;\n\t\t}\n\n\t\treturn newActions.concat( diff( actualSlice, expectedSlice, areSimilar ).map( x => x === 'equal' ? 'replace' : x ) );\n\t}\n\n\t/**\n\t * Marks text nodes to be synchronized.\n\t *\n\t * If a text node is passed, it will be marked. If an element is passed, all descendant text nodes inside it will be marked.\n\t *\n\t * @private\n\t * @param {module:engine/view/node~Node} viewNode View node to sync.\n\t */\n\t_markDescendantTextToSync( viewNode ) {\n\t\tif ( !viewNode ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( viewNode.is( '$text' ) ) {\n\t\t\tthis.markedTexts.add( viewNode );\n\t\t} else if ( viewNode.is( 'element' ) ) {\n\t\t\tfor ( const child of viewNode.getChildren() ) {\n\t\t\t\tthis._markDescendantTextToSync( child );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks if the selection needs to be updated and possibly updates it.\n\t *\n\t * @private\n\t */\n\t_updateSelection() {\n\t\t// If there is no selection - remove DOM and fake selections.\n\t\tif ( this.selection.rangeCount === 0 ) {\n\t\t\tthis._removeDomSelection();\n\t\t\tthis._removeFakeSelection();\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst domRoot = this.domConverter.mapViewToDom( this.selection.editableElement );\n\n\t\t// Do nothing if there is no focus, or there is no DOM element corresponding to selection's editable element.\n\t\tif ( !this.isFocused || !domRoot ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Render selection.\n\t\tif ( this.selection.isFake ) {\n\t\t\tthis._updateFakeSelection( domRoot );\n\t\t} else {\n\t\t\tthis._removeFakeSelection();\n\t\t\tthis._updateDomSelection( domRoot );\n\t\t}\n\t}\n\n\t/**\n\t * Updates the fake selection.\n\t *\n\t * @private\n\t * @param {HTMLElement} domRoot A valid DOM root where the fake selection container should be added.\n\t */\n\t_updateFakeSelection( domRoot ) {\n\t\tconst domDocument = domRoot.ownerDocument;\n\n\t\tif ( !this._fakeSelectionContainer ) {\n\t\t\tthis._fakeSelectionContainer = createFakeSelectionContainer( domDocument );\n\t\t}\n\n\t\tconst container = this._fakeSelectionContainer;\n\n\t\t// Bind fake selection container with the current selection *position*.\n\t\tthis.domConverter.bindFakeSelection( container, this.selection );\n\n\t\tif ( !this._fakeSelectionNeedsUpdate( domRoot ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !container.parentElement || container.parentElement != domRoot ) {\n\t\t\tdomRoot.appendChild( container );\n\t\t}\n\n\t\tcontainer.textContent = this.selection.fakeSelectionLabel || '\\u00A0';\n\n\t\tconst domSelection = domDocument.getSelection();\n\t\tconst domRange = domDocument.createRange();\n\n\t\tdomSelection.removeAllRanges();\n\t\tdomRange.selectNodeContents( container );\n\t\tdomSelection.addRange( domRange );\n\t}\n\n\t/**\n\t * Updates the DOM selection.\n\t *\n\t * @private\n\t * @param {HTMLElement} domRoot A valid DOM root where the DOM selection should be rendered.\n\t */\n\t_updateDomSelection( domRoot ) {\n\t\tconst domSelection = domRoot.ownerDocument.defaultView.getSelection();\n\n\t\t// Let's check whether DOM selection needs updating at all.\n\t\tif ( !this._domSelectionNeedsUpdate( domSelection ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Multi-range selection is not available in most browsers, and, at least in Chrome, trying to\n\t\t// set such selection, that is not continuous, throws an error. Because of that, we will just use anchor\n\t\t// and focus of view selection.\n\t\t// Since we are not supporting multi-range selection, we also do not need to check if proper editable is\n\t\t// selected. If there is any editable selected, it is okay (editable is taken from selection anchor).\n\t\tconst anchor = this.domConverter.viewPositionToDom( this.selection.anchor );\n\t\tconst focus = this.domConverter.viewPositionToDom( this.selection.focus );\n\n\t\t// Focus the new editing host.\n\t\t// Otherwise, FF may throw an error (https://github.com/ckeditor/ckeditor5/issues/721).\n\t\tdomRoot.focus();\n\n\t\tdomSelection.collapse( anchor.parent, anchor.offset );\n\t\tdomSelection.extend( focus.parent, focus.offset );\n\n\t\t// Firefox–specific hack (https://github.com/ckeditor/ckeditor5-engine/issues/1439).\n\t\tif ( env.isGecko ) {\n\t\t\tfixGeckoSelectionAfterBr( focus, domSelection );\n\t\t}\n\t}\n\n\t/**\n\t * Checks whether a given DOM selection needs to be updated.\n\t *\n\t * @private\n\t * @param {Selection} domSelection The DOM selection to check.\n\t * @returns {Boolean}\n\t */\n\t_domSelectionNeedsUpdate( domSelection ) {\n\t\tif ( !this.domConverter.isDomSelectionCorrect( domSelection ) ) {\n\t\t\t// Current DOM selection is in incorrect position. We need to update it.\n\t\t\treturn true;\n\t\t}\n\n\t\tconst oldViewSelection = domSelection && this.domConverter.domSelectionToView( domSelection );\n\n\t\tif ( oldViewSelection && this.selection.isEqual( oldViewSelection ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// If selection is not collapsed, it does not need to be updated if it is similar.\n\t\tif ( !this.selection.isCollapsed && this.selection.isSimilar( oldViewSelection ) ) {\n\t\t\t// Selection did not changed and is correct, do not update.\n\t\t\treturn false;\n\t\t}\n\n\t\t// Selections are not similar.\n\t\treturn true;\n\t}\n\n\t/**\n\t * Checks whether the fake selection needs to be updated.\n\t *\n\t * @private\n\t * @param {HTMLElement} domRoot A valid DOM root where a new fake selection container should be added.\n\t * @returns {Boolean}\n\t */\n\t_fakeSelectionNeedsUpdate( domRoot ) {\n\t\tconst container = this._fakeSelectionContainer;\n\t\tconst domSelection = domRoot.ownerDocument.getSelection();\n\n\t\t// Fake selection needs to be updated if there's no fake selection container, or the container currently sits\n\t\t// in a different root.\n\t\tif ( !container || container.parentElement !== domRoot ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Make sure that the selection actually is within the fake selection.\n\t\tif ( domSelection.anchorNode !== container && !container.contains( domSelection.anchorNode ) ) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn container.textContent !== this.selection.fakeSelectionLabel;\n\t}\n\n\t/**\n\t * Removes the DOM selection.\n\t *\n\t * @private\n\t */\n\t_removeDomSelection() {\n\t\tfor ( const doc of this.domDocuments ) {\n\t\t\tconst domSelection = doc.getSelection();\n\n\t\t\tif ( domSelection.rangeCount ) {\n\t\t\t\tconst activeDomElement = doc.activeElement;\n\t\t\t\tconst viewElement = this.domConverter.mapDomToView( activeDomElement );\n\n\t\t\t\tif ( activeDomElement && viewElement ) {\n\t\t\t\t\tdoc.getSelection().removeAllRanges();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Removes the fake selection.\n\t *\n\t * @private\n\t */\n\t_removeFakeSelection() {\n\t\tconst container = this._fakeSelectionContainer;\n\n\t\tif ( container ) {\n\t\t\tcontainer.remove();\n\t\t}\n\t}\n\n\t/**\n\t * Checks if focus needs to be updated and possibly updates it.\n\t *\n\t * @private\n\t */\n\t_updateFocus() {\n\t\tif ( this.isFocused ) {\n\t\t\tconst editable = this.selection.editableElement;\n\n\t\t\tif ( editable ) {\n\t\t\t\tthis.domConverter.focus( editable );\n\t\t\t}\n\t\t}\n\t}\n}\n\nmix( Renderer, ObservableMixin );\n\n// Checks if provided element is editable.\n//\n// @private\n// @param {module:engine/view/element~Element} element\n// @returns {Boolean}\nfunction isEditable( element ) {\n\tif ( element.getAttribute( 'contenteditable' ) == 'false' ) {\n\t\treturn false;\n\t}\n\n\tconst parent = element.findAncestor( element => element.hasAttribute( 'contenteditable' ) );\n\n\treturn !parent || parent.getAttribute( 'contenteditable' ) == 'true';\n}\n\n// Adds inline filler at a given position.\n//\n// The position can be given as an array of DOM nodes and an offset in that array,\n// or a DOM parent element and an offset in that element.\n//\n// @private\n// @param {Document} domDocument\n// @param {Element|Array.<Node>} domParentOrArray\n// @param {Number} offset\n// @returns {Text} The DOM text node that contains an inline filler.\nfunction addInlineFiller( domDocument, domParentOrArray, offset ) {\n\tconst childNodes = domParentOrArray instanceof Array ? domParentOrArray : domParentOrArray.childNodes;\n\tconst nodeAfterFiller = childNodes[ offset ];\n\n\tif ( isText( nodeAfterFiller ) ) {\n\t\tnodeAfterFiller.data = INLINE_FILLER + nodeAfterFiller.data;\n\n\t\treturn nodeAfterFiller;\n\t} else {\n\t\tconst fillerNode = domDocument.createTextNode( INLINE_FILLER );\n\n\t\tif ( Array.isArray( domParentOrArray ) ) {\n\t\t\tchildNodes.splice( offset, 0, fillerNode );\n\t\t} else {\n\t\t\tinsertAt( domParentOrArray, offset, fillerNode );\n\t\t}\n\n\t\treturn fillerNode;\n\t}\n}\n\n// Whether two DOM nodes should be considered as similar.\n// Nodes are considered similar if they have the same tag name.\n//\n// @private\n// @param {Node} node1\n// @param {Node} node2\n// @returns {Boolean}\nfunction areSimilar( node1, node2 ) {\n\treturn isNode( node1 ) && isNode( node2 ) &&\n\t\t!isText( node1 ) && !isText( node2 ) &&\n\t\tnode1.nodeType !== Node.COMMENT_NODE && node2.nodeType !== Node.COMMENT_NODE &&\n\t\tnode1.tagName.toLowerCase() === node2.tagName.toLowerCase();\n}\n\n// Whether two dom nodes should be considered as the same.\n// Two nodes which are considered the same are:\n//\n//\t\t* Text nodes with the same text.\n//\t\t* Element nodes represented by the same object.\n//\t\t* Two block filler elements.\n//\n// @private\n// @param {String} blockFillerMode Block filler mode, see {@link module:engine/view/domconverter~DomConverter#blockFillerMode}.\n// @param {Node} node1\n// @param {Node} node2\n// @returns {Boolean}\nfunction sameNodes( domConverter, actualDomChild, expectedDomChild ) {\n\t// Elements.\n\tif ( actualDomChild === expectedDomChild ) {\n\t\treturn true;\n\t}\n\t// Texts.\n\telse if ( isText( actualDomChild ) && isText( expectedDomChild ) ) {\n\t\treturn actualDomChild.data === expectedDomChild.data;\n\t}\n\t// Block fillers.\n\telse if ( domConverter.isBlockFiller( actualDomChild ) &&\n\t\tdomConverter.isBlockFiller( expectedDomChild ) ) {\n\t\treturn true;\n\t}\n\n\t// Not matching types.\n\treturn false;\n}\n\n// The following is a Firefox–specific hack (https://github.com/ckeditor/ckeditor5-engine/issues/1439).\n// When the native DOM selection is at the end of the block and preceded by <br /> e.g.\n//\n//\t\t<p>foo<br/>[]</p>\n//\n// which happens a lot when using the soft line break, the browser fails to (visually) move the\n// caret to the new line. A quick fix is as simple as force–refreshing the selection with the same range.\nfunction fixGeckoSelectionAfterBr( focus, domSelection ) {\n\tconst parent = focus.parent;\n\n\t// This fix works only when the focus point is at the very end of an element.\n\t// There is no point in running it in cases unrelated to the browser bug.\n\tif ( parent.nodeType != Node.ELEMENT_NODE || focus.offset != parent.childNodes.length - 1 ) {\n\t\treturn;\n\t}\n\n\tconst childAtOffset = parent.childNodes[ focus.offset ];\n\n\t// To stay on the safe side, the fix being as specific as possible, it targets only the\n\t// selection which is at the very end of the element and preceded by <br />.\n\tif ( childAtOffset && childAtOffset.tagName == 'BR' ) {\n\t\tdomSelection.addRange( domSelection.getRangeAt( 0 ) );\n\t}\n}\n\nfunction filterOutFakeSelectionContainer( domChildList, fakeSelectionContainer ) {\n\tconst childList = Array.from( domChildList );\n\n\tif ( childList.length == 0 || !fakeSelectionContainer ) {\n\t\treturn childList;\n\t}\n\n\tconst last = childList[ childList.length - 1 ];\n\n\tif ( last == fakeSelectionContainer ) {\n\t\tchildList.pop();\n\t}\n\n\treturn childList;\n}\n\n// Creates a fake selection container for a given document.\n//\n// @private\n// @param {Document} domDocument\n// @returns {HTMLElement}\nfunction createFakeSelectionContainer( domDocument ) {\n\tconst container = domDocument.createElement( 'div' );\n\n\tcontainer.className = 'ck-fake-selection-container';\n\n\tObject.assign( container.style, {\n\t\tposition: 'fixed',\n\t\ttop: 0,\n\t\tleft: '-9999px',\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/752.\n\t\twidth: '42px'\n\t} );\n\n\t// Fill it with a text node so we can update it later.\n\tcontainer.textContent = '\\u00A0';\n\n\treturn container;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* globals window, document */\n\n/**\n * @module utils/dom/global\n */\n\n/**\n * A helper (module) giving an access to the global DOM objects such as `window` and\n * `document`. Accessing these objects using this helper allows easy and bulletproof\n * testing, i.e. stubbing native properties:\n *\n *\t\timport global from 'ckeditor5/utils/dom/global.js';\n *\n *\t\t// This stub will work for any code using global module.\n *\t\ttestUtils.sinon.stub( global, 'window', {\n *\t\t\tinnerWidth: 10000\n *\t\t} );\n *\n *\t\tconsole.log( global.window.innerWidth );\n */\nexport default { window, document };\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/indexof\n */\n\n/**\n * Returns index of the node in the parent element.\n *\n * @param {Node} node Node which index is tested.\n * @returns {Number} Index of the node in the parent element. Returns 0 if node has no parent.\n */\nexport default function indexOf( node ) {\n\tlet index = 0;\n\n\twhile ( node.previousSibling ) {\n\t\tnode = node.previousSibling;\n\t\tindex++;\n\t}\n\n\treturn index;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* globals Node */\n\n/**\n * @module utils/dom/getancestors\n */\n\n/**\n * Returns all ancestors of given DOM node, starting from the top-most (root). Includes the given node itself. If the\n * node is a part of `DocumentFragment` that `DocumentFragment` will be returned. In contrary, if the node is\n * appended to a `Document`, that `Document` will not be returned (algorithms operating on DOM tree care for `Document#documentElement`\n * at most, which will be returned).\n *\n * @param {Node} node DOM node.\n * @returns {Array.<Node|DocumentFragment>} Array of given `node` parents.\n */\nexport default function getAncestors( node ) {\n\tconst nodes = [];\n\n\t// We are interested in `Node`s `DocumentFragment`s only.\n\twhile ( node && node.nodeType != Node.DOCUMENT_NODE ) {\n\t\tnodes.unshift( node );\n\t\tnode = node.parentNode;\n\t}\n\n\treturn nodes;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/domconverter\n */\n\n/* globals document, Node, NodeFilter, Text */\n\nimport ViewText from './text';\nimport ViewElement from './element';\nimport ViewPosition from './position';\nimport ViewRange from './range';\nimport ViewSelection from './selection';\nimport ViewDocumentFragment from './documentfragment';\nimport ViewTreeWalker from './treewalker';\nimport Matcher from './matcher';\nimport { BR_FILLER, getDataWithoutFiller, INLINE_FILLER_LENGTH, isInlineFiller, NBSP_FILLER, startsWithFiller } from './filler';\n\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport indexOf from '@ckeditor/ckeditor5-utils/src/dom/indexof';\nimport getAncestors from '@ckeditor/ckeditor5-utils/src/dom/getancestors';\nimport getCommonAncestor from '@ckeditor/ckeditor5-utils/src/dom/getcommonancestor';\nimport isText from '@ckeditor/ckeditor5-utils/src/dom/istext';\nimport { isElement } from 'lodash-es';\n\n// eslint-disable-next-line new-cap\nconst BR_FILLER_REF = BR_FILLER( document );\n\n/**\n * `DomConverter` is a set of tools to do transformations between DOM nodes and view nodes. It also handles\n * {@link module:engine/view/domconverter~DomConverter#bindElements bindings} between these nodes.\n *\n * An instance of the DOM converter is available under\n * {@link module:engine/view/view~View#domConverter `editor.editing.view.domConverter`}.\n *\n * The DOM converter does not check which nodes should be rendered (use {@link module:engine/view/renderer~Renderer}), does not keep the\n * state of a tree nor keeps the synchronization between the tree view and the DOM tree (use {@link module:engine/view/document~Document}).\n *\n * The DOM converter keeps DOM elements to view element bindings, so when the converter gets destroyed, the bindings are lost.\n * Two converters will keep separate binding maps, so one tree view can be bound with two DOM trees.\n */\nexport default class DomConverter {\n\t/**\n\t * Creates a DOM converter.\n\t *\n\t * @param {module:engine/view/document~Document} document The view document instance.\n\t * @param {Object} options An object with configuration options.\n\t * @param {module:engine/view/filler~BlockFillerMode} [options.blockFillerMode='br'] The type of the block filler to use.\n\t */\n\tconstructor( document, options = {} ) {\n\t\t/**\n\t\t * @readonly\n\t\t * @type {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = document;\n\n\t\t/**\n\t\t * The mode of a block filler used by the DOM converter.\n\t\t *\n\t\t * @readonly\n\t\t * @member {'br'|'nbsp'} module:engine/view/domconverter~DomConverter#blockFillerMode\n\t\t */\n\t\tthis.blockFillerMode = options.blockFillerMode || 'br';\n\n\t\t/**\n\t\t * Elements which are considered pre-formatted elements.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<String>} module:engine/view/domconverter~DomConverter#preElements\n\t\t */\n\t\tthis.preElements = [ 'pre' ];\n\n\t\t/**\n\t\t * Elements which are considered block elements (and hence should be filled with a\n\t\t * {@link #isBlockFiller block filler}).\n\t\t *\n\t\t * Whether an element is considered a block element also affects handling of trailing whitespaces.\n\t\t *\n\t\t * You can extend this array if you introduce support for block elements which are not yet recognized here.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<String>} module:engine/view/domconverter~DomConverter#blockElements\n\t\t */\n\t\tthis.blockElements = [ 'p', 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'li', 'dd', 'dt', 'figcaption', 'td', 'th' ];\n\n\t\t/**\n\t\t * Block {@link module:engine/view/filler filler} creator, which is used to create all block fillers during the\n\t\t * view-to-DOM conversion and to recognize block fillers during the DOM-to-view conversion.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @member {Function} module:engine/view/domconverter~DomConverter#_blockFiller\n\t\t */\n\t\tthis._blockFiller = this.blockFillerMode == 'br' ? BR_FILLER : NBSP_FILLER;\n\n\t\t/**\n\t\t * The DOM-to-view mapping.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap} module:engine/view/domconverter~DomConverter#_domToViewMapping\n\t\t */\n\t\tthis._domToViewMapping = new WeakMap();\n\n\t\t/**\n\t\t * The view-to-DOM mapping.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap} module:engine/view/domconverter~DomConverter#_viewToDomMapping\n\t\t */\n\t\tthis._viewToDomMapping = new WeakMap();\n\n\t\t/**\n\t\t * Holds the mapping between fake selection containers and corresponding view selections.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap} module:engine/view/domconverter~DomConverter#_fakeSelectionMapping\n\t\t */\n\t\tthis._fakeSelectionMapping = new WeakMap();\n\n\t\t/**\n\t\t * Matcher for view elements whose content should be treated as a raw data\n\t\t * and not processed during conversion from DOM nodes to view elements.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/view/matcher~Matcher}\n\t\t */\n\t\tthis._rawContentElementMatcher = new Matcher();\n\n\t\t/**\n\t\t * Set of encountered raw content DOM nodes. It is used for preventing left trimming of the following text node.\n\t\t *\n\t\t * @private\n\t\t * @type {WeakSet.<Node>}\n\t\t */\n\t\tthis._encounteredRawContentDomNodes = new WeakSet();\n\t}\n\n\t/**\n\t * Binds given DOM element that represents fake selection to a **position** of a\n\t * {@link module:engine/view/documentselection~DocumentSelection document selection}.\n\t * Document selection copy is stored and can be retrieved by\n\t * {@link module:engine/view/domconverter~DomConverter#fakeSelectionToView} method.\n\t *\n\t * @param {HTMLElement} domElement\n\t * @param {module:engine/view/documentselection~DocumentSelection} viewDocumentSelection\n\t */\n\tbindFakeSelection( domElement, viewDocumentSelection ) {\n\t\tthis._fakeSelectionMapping.set( domElement, new ViewSelection( viewDocumentSelection ) );\n\t}\n\n\t/**\n\t * Returns {@link module:engine/view/selection~Selection view selection} instance corresponding to\n\t * given DOM element that represents fake selection. Returns `undefined` if binding to given DOM element does not exists.\n\t *\n\t * @param {HTMLElement} domElement\n\t * @returns {module:engine/view/selection~Selection|undefined}\n\t */\n\tfakeSelectionToView( domElement ) {\n\t\treturn this._fakeSelectionMapping.get( domElement );\n\t}\n\n\t/**\n\t * Binds DOM and View elements, so it will be possible to get corresponding elements using\n\t * {@link module:engine/view/domconverter~DomConverter#mapDomToView} and\n\t * {@link module:engine/view/domconverter~DomConverter#mapViewToDom}.\n\t *\n\t * @param {HTMLElement} domElement DOM element to bind.\n\t * @param {module:engine/view/element~Element} viewElement View element to bind.\n\t */\n\tbindElements( domElement, viewElement ) {\n\t\tthis._domToViewMapping.set( domElement, viewElement );\n\t\tthis._viewToDomMapping.set( viewElement, domElement );\n\t}\n\n\t/**\n\t * Unbinds given `domElement` from the view element it was bound to. Unbinding is deep, meaning that all children of\n\t * `domElement` will be unbound too.\n\t *\n\t * @param {HTMLElement} domElement DOM element to unbind.\n\t */\n\tunbindDomElement( domElement ) {\n\t\tconst viewElement = this._domToViewMapping.get( domElement );\n\n\t\tif ( viewElement ) {\n\t\t\tthis._domToViewMapping.delete( domElement );\n\t\t\tthis._viewToDomMapping.delete( viewElement );\n\n\t\t\tfor ( const child of domElement.childNodes ) {\n\t\t\t\tthis.unbindDomElement( child );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Binds DOM and View document fragments, so it will be possible to get corresponding document fragments using\n\t * {@link module:engine/view/domconverter~DomConverter#mapDomToView} and\n\t * {@link module:engine/view/domconverter~DomConverter#mapViewToDom}.\n\t *\n\t * @param {DocumentFragment} domFragment DOM document fragment to bind.\n\t * @param {module:engine/view/documentfragment~DocumentFragment} viewFragment View document fragment to bind.\n\t */\n\tbindDocumentFragments( domFragment, viewFragment ) {\n\t\tthis._domToViewMapping.set( domFragment, viewFragment );\n\t\tthis._viewToDomMapping.set( viewFragment, domFragment );\n\t}\n\n\t/**\n\t * Converts view to DOM. For all text nodes, not bound elements and document fragments new items will\n\t * be created. For bound elements and document fragments function will return corresponding items.\n\t *\n\t * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} viewNode\n\t * View node or document fragment to transform.\n\t * @param {Document} domDocument Document which will be used to create DOM nodes.\n\t * @param {Object} [options] Conversion options.\n\t * @param {Boolean} [options.bind=false] Determines whether new elements will be bound.\n\t * @param {Boolean} [options.withChildren=true] If `true`, node's and document fragment's children will be converted too.\n\t * @returns {Node|DocumentFragment} Converted node or DocumentFragment.\n\t */\n\tviewToDom( viewNode, domDocument, options = {} ) {\n\t\tif ( viewNode.is( '$text' ) ) {\n\t\t\tconst textData = this._processDataFromViewText( viewNode );\n\n\t\t\treturn domDocument.createTextNode( textData );\n\t\t} else {\n\t\t\tif ( this.mapViewToDom( viewNode ) ) {\n\t\t\t\treturn this.mapViewToDom( viewNode );\n\t\t\t}\n\n\t\t\tlet domElement;\n\n\t\t\tif ( viewNode.is( 'documentFragment' ) ) {\n\t\t\t\t// Create DOM document fragment.\n\t\t\t\tdomElement = domDocument.createDocumentFragment();\n\n\t\t\t\tif ( options.bind ) {\n\t\t\t\t\tthis.bindDocumentFragments( domElement, viewNode );\n\t\t\t\t}\n\t\t\t} else if ( viewNode.is( 'uiElement' ) ) {\n\t\t\t\t// UIElement has its own render() method (see #799).\n\t\t\t\tdomElement = viewNode.render( domDocument );\n\n\t\t\t\tif ( options.bind ) {\n\t\t\t\t\tthis.bindElements( domElement, viewNode );\n\t\t\t\t}\n\n\t\t\t\treturn domElement;\n\t\t\t} else {\n\t\t\t\t// Create DOM element.\n\t\t\t\tif ( viewNode.hasAttribute( 'xmlns' ) ) {\n\t\t\t\t\tdomElement = domDocument.createElementNS( viewNode.getAttribute( 'xmlns' ), viewNode.name );\n\t\t\t\t} else {\n\t\t\t\t\tdomElement = domDocument.createElement( viewNode.name );\n\t\t\t\t}\n\n\t\t\t\t// RawElement take care of their children in RawElement#render() method which can be customized\n\t\t\t\t// (see https://github.com/ckeditor/ckeditor5/issues/4469).\n\t\t\t\tif ( viewNode.is( 'rawElement' ) ) {\n\t\t\t\t\tviewNode.render( domElement );\n\t\t\t\t}\n\n\t\t\t\tif ( options.bind ) {\n\t\t\t\t\tthis.bindElements( domElement, viewNode );\n\t\t\t\t}\n\n\t\t\t\t// Copy element's attributes.\n\t\t\t\tfor ( const key of viewNode.getAttributeKeys() ) {\n\t\t\t\t\tdomElement.setAttribute( key, viewNode.getAttribute( key ) );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( options.withChildren !== false ) {\n\t\t\t\tfor ( const child of this.viewChildrenToDom( viewNode, domDocument, options ) ) {\n\t\t\t\t\tdomElement.appendChild( child );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn domElement;\n\t\t}\n\t}\n\n\t/**\n\t * Converts children of the view element to DOM using the\n\t * {@link module:engine/view/domconverter~DomConverter#viewToDom} method.\n\t * Additionally, this method adds block {@link module:engine/view/filler filler} to the list of children, if needed.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} viewElement Parent view element.\n\t * @param {Document} domDocument Document which will be used to create DOM nodes.\n\t * @param {Object} options See {@link module:engine/view/domconverter~DomConverter#viewToDom} options parameter.\n\t * @returns {Iterable.<Node>} DOM nodes.\n\t */\n\t* viewChildrenToDom( viewElement, domDocument, options = {} ) {\n\t\tconst fillerPositionOffset = viewElement.getFillerOffset && viewElement.getFillerOffset();\n\t\tlet offset = 0;\n\n\t\tfor ( const childView of viewElement.getChildren() ) {\n\t\t\tif ( fillerPositionOffset === offset ) {\n\t\t\t\tyield this._blockFiller( domDocument );\n\t\t\t}\n\n\t\t\tyield this.viewToDom( childView, domDocument, options );\n\n\t\t\toffset++;\n\t\t}\n\n\t\tif ( fillerPositionOffset === offset ) {\n\t\t\tyield this._blockFiller( domDocument );\n\t\t}\n\t}\n\n\t/**\n\t * Converts view {@link module:engine/view/range~Range} to DOM range.\n\t * Inline and block {@link module:engine/view/filler fillers} are handled during the conversion.\n\t *\n\t * @param {module:engine/view/range~Range} viewRange View range.\n\t * @returns {Range} DOM range.\n\t */\n\tviewRangeToDom( viewRange ) {\n\t\tconst domStart = this.viewPositionToDom( viewRange.start );\n\t\tconst domEnd = this.viewPositionToDom( viewRange.end );\n\n\t\tconst domRange = document.createRange();\n\t\tdomRange.setStart( domStart.parent, domStart.offset );\n\t\tdomRange.setEnd( domEnd.parent, domEnd.offset );\n\n\t\treturn domRange;\n\t}\n\n\t/**\n\t * Converts view {@link module:engine/view/position~Position} to DOM parent and offset.\n\t *\n\t * Inline and block {@link module:engine/view/filler fillers} are handled during the conversion.\n\t * If the converted position is directly before inline filler it is moved inside the filler.\n\t *\n\t * @param {module:engine/view/position~Position} viewPosition View position.\n\t * @returns {Object|null} position DOM position or `null` if view position could not be converted to DOM.\n\t * @returns {Node} position.parent DOM position parent.\n\t * @returns {Number} position.offset DOM position offset.\n\t */\n\tviewPositionToDom( viewPosition ) {\n\t\tconst viewParent = viewPosition.parent;\n\n\t\tif ( viewParent.is( '$text' ) ) {\n\t\t\tconst domParent = this.findCorrespondingDomText( viewParent );\n\n\t\t\tif ( !domParent ) {\n\t\t\t\t// Position is in a view text node that has not been rendered to DOM yet.\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tlet offset = viewPosition.offset;\n\n\t\t\tif ( startsWithFiller( domParent ) ) {\n\t\t\t\toffset += INLINE_FILLER_LENGTH;\n\t\t\t}\n\n\t\t\treturn { parent: domParent, offset };\n\t\t} else {\n\t\t\t// viewParent is instance of ViewElement.\n\t\t\tlet domParent, domBefore, domAfter;\n\n\t\t\tif ( viewPosition.offset === 0 ) {\n\t\t\t\tdomParent = this.mapViewToDom( viewParent );\n\n\t\t\t\tif ( !domParent ) {\n\t\t\t\t\t// Position is in a view element that has not been rendered to DOM yet.\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tdomAfter = domParent.childNodes[ 0 ];\n\t\t\t} else {\n\t\t\t\tconst nodeBefore = viewPosition.nodeBefore;\n\n\t\t\t\tdomBefore = nodeBefore.is( '$text' ) ?\n\t\t\t\t\tthis.findCorrespondingDomText( nodeBefore ) :\n\t\t\t\t\tthis.mapViewToDom( viewPosition.nodeBefore );\n\n\t\t\t\tif ( !domBefore ) {\n\t\t\t\t\t// Position is after a view element that has not been rendered to DOM yet.\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tdomParent = domBefore.parentNode;\n\t\t\t\tdomAfter = domBefore.nextSibling;\n\t\t\t}\n\n\t\t\t// If there is an inline filler at position return position inside the filler. We should never return\n\t\t\t// the position before the inline filler.\n\t\t\tif ( isText( domAfter ) && startsWithFiller( domAfter ) ) {\n\t\t\t\treturn { parent: domAfter, offset: INLINE_FILLER_LENGTH };\n\t\t\t}\n\n\t\t\tconst offset = domBefore ? indexOf( domBefore ) + 1 : 0;\n\n\t\t\treturn { parent: domParent, offset };\n\t\t}\n\t}\n\n\t/**\n\t * Converts DOM to view. For all text nodes, not bound elements and document fragments new items will\n\t * be created. For bound elements and document fragments function will return corresponding items. For\n\t * {@link module:engine/view/filler fillers} `null` will be returned.\n\t * For all DOM elements rendered by {@link module:engine/view/uielement~UIElement} that UIElement will be returned.\n\t *\n\t * @param {Node|DocumentFragment} domNode DOM node or document fragment to transform.\n\t * @param {Object} [options] Conversion options.\n\t * @param {Boolean} [options.bind=false] Determines whether new elements will be bound.\n\t * @param {Boolean} [options.withChildren=true] If `true`, node's and document fragment's children will be converted too.\n\t * @param {Boolean} [options.keepOriginalCase=false] If `false`, node's tag name will be converter to lower case.\n\t * @returns {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment|null} Converted node or document fragment\n\t * or `null` if DOM node is a {@link module:engine/view/filler filler} or the given node is an empty text node.\n\t */\n\tdomToView( domNode, options = {} ) {\n\t\tif ( this.isBlockFiller( domNode, this.blockFillerMode ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// When node is inside a UIElement or a RawElement return that parent as it's view representation.\n\t\tconst hostElement = this.getHostViewElement( domNode );\n\n\t\tif ( hostElement ) {\n\t\t\treturn hostElement;\n\t\t}\n\n\t\tif ( isText( domNode ) ) {\n\t\t\tif ( isInlineFiller( domNode ) ) {\n\t\t\t\treturn null;\n\t\t\t} else {\n\t\t\t\tconst textData = this._processDataFromDomText( domNode );\n\n\t\t\t\treturn textData === '' ? null : new ViewText( this.document, textData );\n\t\t\t}\n\t\t} else if ( this.isComment( domNode ) ) {\n\t\t\treturn null;\n\t\t} else {\n\t\t\tif ( this.mapDomToView( domNode ) ) {\n\t\t\t\treturn this.mapDomToView( domNode );\n\t\t\t}\n\n\t\t\tlet viewElement;\n\n\t\t\tif ( this.isDocumentFragment( domNode ) ) {\n\t\t\t\t// Create view document fragment.\n\t\t\t\tviewElement = new ViewDocumentFragment( this.document );\n\n\t\t\t\tif ( options.bind ) {\n\t\t\t\t\tthis.bindDocumentFragments( domNode, viewElement );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Create view element.\n\t\t\t\tconst viewName = options.keepOriginalCase ? domNode.tagName : domNode.tagName.toLowerCase();\n\t\t\t\tviewElement = new ViewElement( this.document, viewName );\n\n\t\t\t\tif ( options.bind ) {\n\t\t\t\t\tthis.bindElements( domNode, viewElement );\n\t\t\t\t}\n\n\t\t\t\t// Copy element's attributes.\n\t\t\t\tconst attrs = domNode.attributes;\n\n\t\t\t\tfor ( let i = attrs.length - 1; i >= 0; i-- ) {\n\t\t\t\t\tviewElement._setAttribute( attrs[ i ].name, attrs[ i ].value );\n\t\t\t\t}\n\n\t\t\t\t// Treat this element's content as a raw data if it was registered as such.\n\t\t\t\tif ( options.withChildren !== false && this._rawContentElementMatcher.match( viewElement ) ) {\n\t\t\t\t\tviewElement._setCustomProperty( '$rawContent', domNode.innerHTML );\n\n\t\t\t\t\t// Store a DOM node to prevent left trimming of the following text node.\n\t\t\t\t\tthis._encounteredRawContentDomNodes.add( domNode );\n\n\t\t\t\t\treturn viewElement;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( options.withChildren !== false ) {\n\t\t\t\tfor ( const child of this.domChildrenToView( domNode, options ) ) {\n\t\t\t\t\tviewElement._appendChild( child );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn viewElement;\n\t\t}\n\t}\n\n\t/**\n\t * Converts children of the DOM element to view nodes using\n\t * the {@link module:engine/view/domconverter~DomConverter#domToView} method.\n\t * Additionally this method omits block {@link module:engine/view/filler filler}, if it exists in the DOM parent.\n\t *\n\t * @param {HTMLElement} domElement Parent DOM element.\n\t * @param {Object} options See {@link module:engine/view/domconverter~DomConverter#domToView} options parameter.\n\t * @returns {Iterable.<module:engine/view/node~Node>} View nodes.\n\t */\n\t* domChildrenToView( domElement, options = {} ) {\n\t\tfor ( let i = 0; i < domElement.childNodes.length; i++ ) {\n\t\t\tconst domChild = domElement.childNodes[ i ];\n\t\t\tconst viewChild = this.domToView( domChild, options );\n\n\t\t\tif ( viewChild !== null ) {\n\t\t\t\tyield viewChild;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Converts DOM selection to view {@link module:engine/view/selection~Selection}.\n\t * Ranges which cannot be converted will be omitted.\n\t *\n\t * @param {Selection} domSelection DOM selection.\n\t * @returns {module:engine/view/selection~Selection} View selection.\n\t */\n\tdomSelectionToView( domSelection ) {\n\t\t// DOM selection might be placed in fake selection container.\n\t\t// If container contains fake selection - return corresponding view selection.\n\t\tif ( domSelection.rangeCount === 1 ) {\n\t\t\tlet container = domSelection.getRangeAt( 0 ).startContainer;\n\n\t\t\t// The DOM selection might be moved to the text node inside the fake selection container.\n\t\t\tif ( isText( container ) ) {\n\t\t\t\tcontainer = container.parentNode;\n\t\t\t}\n\n\t\t\tconst viewSelection = this.fakeSelectionToView( container );\n\n\t\t\tif ( viewSelection ) {\n\t\t\t\treturn viewSelection;\n\t\t\t}\n\t\t}\n\n\t\tconst isBackward = this.isDomSelectionBackward( domSelection );\n\n\t\tconst viewRanges = [];\n\n\t\tfor ( let i = 0; i < domSelection.rangeCount; i++ ) {\n\t\t\t// DOM Range have correct start and end, no matter what is the DOM Selection direction. So we don't have to fix anything.\n\t\t\tconst domRange = domSelection.getRangeAt( i );\n\t\t\tconst viewRange = this.domRangeToView( domRange );\n\n\t\t\tif ( viewRange ) {\n\t\t\t\tviewRanges.push( viewRange );\n\t\t\t}\n\t\t}\n\n\t\treturn new ViewSelection( viewRanges, { backward: isBackward } );\n\t}\n\n\t/**\n\t * Converts DOM Range to view {@link module:engine/view/range~Range}.\n\t * If the start or end position can not be converted `null` is returned.\n\t *\n\t * @param {Range} domRange DOM range.\n\t * @returns {module:engine/view/range~Range|null} View range.\n\t */\n\tdomRangeToView( domRange ) {\n\t\tconst viewStart = this.domPositionToView( domRange.startContainer, domRange.startOffset );\n\t\tconst viewEnd = this.domPositionToView( domRange.endContainer, domRange.endOffset );\n\n\t\tif ( viewStart && viewEnd ) {\n\t\t\treturn new ViewRange( viewStart, viewEnd );\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Converts DOM parent and offset to view {@link module:engine/view/position~Position}.\n\t *\n\t * If the position is inside a {@link module:engine/view/filler filler} which has no corresponding view node,\n\t * position of the filler will be converted and returned.\n\t *\n\t * If the position is inside DOM element rendered by {@link module:engine/view/uielement~UIElement}\n\t * that position will be converted to view position before that UIElement.\n\t *\n\t * If structures are too different and it is not possible to find corresponding position then `null` will be returned.\n\t *\n\t * @param {Node} domParent DOM position parent.\n\t * @param {Number} domOffset DOM position offset.\n\t * @returns {module:engine/view/position~Position} viewPosition View position.\n\t */\n\tdomPositionToView( domParent, domOffset ) {\n\t\tif ( this.isBlockFiller( domParent, this.blockFillerMode ) ) {\n\t\t\treturn this.domPositionToView( domParent.parentNode, indexOf( domParent ) );\n\t\t}\n\n\t\t// If position is somewhere inside UIElement or a RawElement - return position before that element.\n\t\tconst viewElement = this.mapDomToView( domParent );\n\n\t\tif ( viewElement && ( viewElement.is( 'uiElement' ) || viewElement.is( 'rawElement' ) ) ) {\n\t\t\treturn ViewPosition._createBefore( viewElement );\n\t\t}\n\n\t\tif ( isText( domParent ) ) {\n\t\t\tif ( isInlineFiller( domParent ) ) {\n\t\t\t\treturn this.domPositionToView( domParent.parentNode, indexOf( domParent ) );\n\t\t\t}\n\n\t\t\tconst viewParent = this.findCorrespondingViewText( domParent );\n\t\t\tlet offset = domOffset;\n\n\t\t\tif ( !viewParent ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif ( startsWithFiller( domParent ) ) {\n\t\t\t\toffset -= INLINE_FILLER_LENGTH;\n\t\t\t\toffset = offset < 0 ? 0 : offset;\n\t\t\t}\n\n\t\t\treturn new ViewPosition( viewParent, offset );\n\t\t}\n\t\t// domParent instanceof HTMLElement.\n\t\telse {\n\t\t\tif ( domOffset === 0 ) {\n\t\t\t\tconst viewParent = this.mapDomToView( domParent );\n\n\t\t\t\tif ( viewParent ) {\n\t\t\t\t\treturn new ViewPosition( viewParent, 0 );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst domBefore = domParent.childNodes[ domOffset - 1 ];\n\t\t\t\tconst viewBefore = isText( domBefore ) ?\n\t\t\t\t\tthis.findCorrespondingViewText( domBefore ) :\n\t\t\t\t\tthis.mapDomToView( domBefore );\n\n\t\t\t\t// TODO #663\n\t\t\t\tif ( viewBefore && viewBefore.parent ) {\n\t\t\t\t\treturn new ViewPosition( viewBefore.parent, viewBefore.index + 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Returns corresponding view {@link module:engine/view/element~Element Element} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment} for provided DOM element or\n\t * document fragment. If there is no view item {@link module:engine/view/domconverter~DomConverter#bindElements bound}\n\t * to the given DOM - `undefined` is returned.\n\t *\n\t * For all DOM elements rendered by a {@link module:engine/view/uielement~UIElement} or\n\t * a {@link module:engine/view/rawelement~RawElement}, the parent `UIElement` or `RawElement` will be returned.\n\t *\n\t * @param {DocumentFragment|Element} domElementOrDocumentFragment DOM element or document fragment.\n\t * @returns {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment|undefined}\n\t * Corresponding view element, document fragment or `undefined` if no element was bound.\n\t */\n\tmapDomToView( domElementOrDocumentFragment ) {\n\t\tconst hostElement = this.getHostViewElement( domElementOrDocumentFragment );\n\n\t\treturn hostElement || this._domToViewMapping.get( domElementOrDocumentFragment );\n\t}\n\n\t/**\n\t * Finds corresponding text node. Text nodes are not {@link module:engine/view/domconverter~DomConverter#bindElements bound},\n\t * corresponding text node is returned based on the sibling or parent.\n\t *\n\t * If the directly previous sibling is a {@link module:engine/view/domconverter~DomConverter#bindElements bound} element, it is used\n\t * to find the corresponding text node.\n\t *\n\t * If this is a first child in the parent and the parent is a {@link module:engine/view/domconverter~DomConverter#bindElements bound}\n\t * element, it is used to find the corresponding text node.\n\t *\n\t * For all text nodes rendered by a {@link module:engine/view/uielement~UIElement} or\n\t * a {@link module:engine/view/rawelement~RawElement}, the parent `UIElement` or `RawElement` will be returned.\n\t *\n\t * Otherwise `null` is returned.\n\t *\n\t * Note that for the block or inline {@link module:engine/view/filler filler} this method returns `null`.\n\t *\n\t * @param {Text} domText DOM text node.\n\t * @returns {module:engine/view/text~Text|null} Corresponding view text node or `null`, if it was not possible to find a\n\t * corresponding node.\n\t */\n\tfindCorrespondingViewText( domText ) {\n\t\tif ( isInlineFiller( domText ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// If DOM text was rendered by a UIElement or a RawElement - return this parent element.\n\t\tconst hostElement = this.getHostViewElement( domText );\n\n\t\tif ( hostElement ) {\n\t\t\treturn hostElement;\n\t\t}\n\n\t\tconst previousSibling = domText.previousSibling;\n\n\t\t// Try to use previous sibling to find the corresponding text node.\n\t\tif ( previousSibling ) {\n\t\t\tif ( !( this.isElement( previousSibling ) ) ) {\n\t\t\t\t// The previous is text or comment.\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst viewElement = this.mapDomToView( previousSibling );\n\n\t\t\tif ( viewElement ) {\n\t\t\t\tconst nextSibling = viewElement.nextSibling;\n\n\t\t\t\t// It might be filler which has no corresponding view node.\n\t\t\t\tif ( nextSibling instanceof ViewText ) {\n\t\t\t\t\treturn viewElement.nextSibling;\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Try to use parent to find the corresponding text node.\n\t\telse {\n\t\t\tconst viewElement = this.mapDomToView( domText.parentNode );\n\n\t\t\tif ( viewElement ) {\n\t\t\t\tconst firstChild = viewElement.getChild( 0 );\n\n\t\t\t\t// It might be filler which has no corresponding view node.\n\t\t\t\tif ( firstChild instanceof ViewText ) {\n\t\t\t\t\treturn firstChild;\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns corresponding DOM item for provided {@link module:engine/view/element~Element Element} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment DocumentFragment}.\n\t * To find a corresponding text for {@link module:engine/view/text~Text view Text instance}\n\t * use {@link #findCorrespondingDomText}.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} viewNode\n\t * View element or document fragment.\n\t * @returns {Node|DocumentFragment|undefined} Corresponding DOM node or document fragment.\n\t */\n\tmapViewToDom( documentFragmentOrElement ) {\n\t\treturn this._viewToDomMapping.get( documentFragmentOrElement );\n\t}\n\n\t/**\n\t * Finds corresponding text node. Text nodes are not {@link module:engine/view/domconverter~DomConverter#bindElements bound},\n\t * corresponding text node is returned based on the sibling or parent.\n\t *\n\t * If the directly previous sibling is a {@link module:engine/view/domconverter~DomConverter#bindElements bound} element, it is used\n\t * to find the corresponding text node.\n\t *\n\t * If this is a first child in the parent and the parent is a {@link module:engine/view/domconverter~DomConverter#bindElements bound}\n\t * element, it is used to find the corresponding text node.\n\t *\n\t * Otherwise `null` is returned.\n\t *\n\t * @param {module:engine/view/text~Text} viewText View text node.\n\t * @returns {Text|null} Corresponding DOM text node or `null`, if it was not possible to find a corresponding node.\n\t */\n\tfindCorrespondingDomText( viewText ) {\n\t\tconst previousSibling = viewText.previousSibling;\n\n\t\t// Try to use previous sibling to find the corresponding text node.\n\t\tif ( previousSibling && this.mapViewToDom( previousSibling ) ) {\n\t\t\treturn this.mapViewToDom( previousSibling ).nextSibling;\n\t\t}\n\n\t\t// If this is a first node, try to use parent to find the corresponding text node.\n\t\tif ( !previousSibling && viewText.parent && this.mapViewToDom( viewText.parent ) ) {\n\t\t\treturn this.mapViewToDom( viewText.parent ).childNodes[ 0 ];\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Focuses DOM editable that is corresponding to provided {@link module:engine/view/editableelement~EditableElement}.\n\t *\n\t * @param {module:engine/view/editableelement~EditableElement} viewEditable\n\t */\n\tfocus( viewEditable ) {\n\t\tconst domEditable = this.mapViewToDom( viewEditable );\n\n\t\tif ( domEditable && domEditable.ownerDocument.activeElement !== domEditable ) {\n\t\t\t// Save the scrollX and scrollY positions before the focus.\n\t\t\tconst { scrollX, scrollY } = global.window;\n\t\t\tconst scrollPositions = [];\n\n\t\t\t// Save all scrollLeft and scrollTop values starting from domEditable up to\n\t\t\t// document#documentElement.\n\t\t\tforEachDomNodeAncestor( domEditable, node => {\n\t\t\t\tconst { scrollLeft, scrollTop } = node;\n\n\t\t\t\tscrollPositions.push( [ scrollLeft, scrollTop ] );\n\t\t\t} );\n\n\t\t\tdomEditable.focus();\n\n\t\t\t// Restore scrollLeft and scrollTop values starting from domEditable up to\n\t\t\t// document#documentElement.\n\t\t\t// https://github.com/ckeditor/ckeditor5-engine/issues/951\n\t\t\t// https://github.com/ckeditor/ckeditor5-engine/issues/957\n\t\t\tforEachDomNodeAncestor( domEditable, node => {\n\t\t\t\tconst [ scrollLeft, scrollTop ] = scrollPositions.shift();\n\n\t\t\t\tnode.scrollLeft = scrollLeft;\n\t\t\t\tnode.scrollTop = scrollTop;\n\t\t\t} );\n\n\t\t\t// Restore the scrollX and scrollY positions after the focus.\n\t\t\t// https://github.com/ckeditor/ckeditor5-engine/issues/951\n\t\t\tglobal.window.scrollTo( scrollX, scrollY );\n\t\t}\n\t}\n\n\t/**\n\t * Returns `true` when `node.nodeType` equals `Node.ELEMENT_NODE`.\n\t *\n\t * @param {Node} node Node to check.\n\t * @returns {Boolean}\n\t */\n\tisElement( node ) {\n\t\treturn node && node.nodeType == Node.ELEMENT_NODE;\n\t}\n\n\t/**\n\t * Returns `true` when `node.nodeType` equals `Node.DOCUMENT_FRAGMENT_NODE`.\n\t *\n\t * @param {Node} node Node to check.\n\t * @returns {Boolean}\n\t */\n\tisDocumentFragment( node ) {\n\t\treturn node && node.nodeType == Node.DOCUMENT_FRAGMENT_NODE;\n\t}\n\n\t/**\n\t * Returns `true` when `node.nodeType` equals `Node.COMMENT_NODE`.\n\t *\n\t * @param {Node} node Node to check.\n\t * @returns {Boolean}\n\t */\n\tisComment( node ) {\n\t\treturn node && node.nodeType == Node.COMMENT_NODE;\n\t}\n\n\t/**\n\t * Checks if the node is an instance of the block filler for this DOM converter.\n\t *\n\t *\t\tconst converter = new DomConverter( viewDocument, { blockFillerMode: 'br' } );\n\t *\n\t *\t\tconverter.isBlockFiller( BR_FILLER( document ) ); // true\n\t *\t\tconverter.isBlockFiller( NBSP_FILLER( document ) ); // false\n\t *\n\t * **Note:**: For the `'nbsp'` mode the method also checks context of a node so it cannot be a detached node.\n\t *\n\t * **Note:** A special case in the `'nbsp'` mode exists where the `<br>` in `<p><br></p>` is treated as a block filler.\n\t *\n\t * @param {Node} domNode DOM node to check.\n\t * @returns {Boolean} True if a node is considered a block filler for given mode.\n\t */\n\tisBlockFiller( domNode ) {\n\t\tif ( this.blockFillerMode == 'br' ) {\n\t\t\treturn domNode.isEqualNode( BR_FILLER_REF );\n\t\t}\n\n\t\t// Special case for <p><br></p> in which case the <br> should be treated as filler even\n\t\t// when we're in the 'nbsp' mode. See ckeditor5#5564.\n\t\tif ( domNode.tagName === 'BR' && hasBlockParent( domNode, this.blockElements ) && domNode.parentNode.childNodes.length === 1 ) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn isNbspBlockFiller( domNode, this.blockElements );\n\t}\n\n\t/**\n\t * Returns `true` if given selection is a backward selection, that is, if it's `focus` is before `anchor`.\n\t *\n\t * @param {Selection} DOM Selection instance to check.\n\t * @returns {Boolean}\n\t */\n\tisDomSelectionBackward( selection ) {\n\t\tif ( selection.isCollapsed ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Since it takes multiple lines of code to check whether a \"DOM Position\" is before/after another \"DOM Position\",\n\t\t// we will use the fact that range will collapse if it's end is before it's start.\n\t\tconst range = document.createRange();\n\n\t\trange.setStart( selection.anchorNode, selection.anchorOffset );\n\t\trange.setEnd( selection.focusNode, selection.focusOffset );\n\n\t\tconst backward = range.collapsed;\n\n\t\trange.detach();\n\n\t\treturn backward;\n\t}\n\n\t/**\n\t * Returns a parent {@link module:engine/view/uielement~UIElement} or {@link module:engine/view/rawelement~RawElement}\n\t * that hosts the provided DOM node. Returns `null` if there is no such parent.\n\t *\n\t * @param {Node} domNode\n\t * @returns {module:engine/view/uielement~UIElement|module:engine/view/rawelement~RawElement|null}\n\t */\n\tgetHostViewElement( domNode ) {\n\t\tconst ancestors = getAncestors( domNode );\n\n\t\t// Remove domNode from the list.\n\t\tancestors.pop();\n\n\t\twhile ( ancestors.length ) {\n\t\t\tconst domNode = ancestors.pop();\n\t\t\tconst viewNode = this._domToViewMapping.get( domNode );\n\n\t\t\tif ( viewNode && ( viewNode.is( 'uiElement' ) || viewNode.is( 'rawElement' ) ) ) {\n\t\t\t\treturn viewNode;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Checks if the given selection's boundaries are at correct places.\n\t *\n\t * The following places are considered as incorrect for selection boundaries:\n\t *\n\t * * before or in the middle of an inline filler sequence,\n\t * * inside a DOM element which represents {@link module:engine/view/uielement~UIElement a view UI element},\n\t * * inside a DOM element which represents {@link module:engine/view/rawelement~RawElement a view raw element}.\n\t *\n\t * @param {Selection} domSelection The DOM selection object to be checked.\n\t * @returns {Boolean} `true` if the given selection is at a correct place, `false` otherwise.\n\t */\n\tisDomSelectionCorrect( domSelection ) {\n\t\treturn this._isDomSelectionPositionCorrect( domSelection.anchorNode, domSelection.anchorOffset ) &&\n\t\t\tthis._isDomSelectionPositionCorrect( domSelection.focusNode, domSelection.focusOffset );\n\t}\n\n\t/**\n\t * Registers a {@link module:engine/view/matcher~MatcherPattern} for view elements whose content should be treated as a raw data\n\t * and not processed during conversion from DOM nodes to view elements.\n\t *\n\t * This is affecting how {@link module:engine/view/domconverter~DomConverter#domToView} and\n\t * {@link module:engine/view/domconverter~DomConverter#domChildrenToView} processes DOM nodes.\n\t *\n\t * The raw data can be later accessed by {@link module:engine/view/element~Element#getCustomProperty view element custom property}\n\t * `\"$rawContent\"`.\n\t *\n\t * @param {module:engine/view/matcher~MatcherPattern} pattern Pattern matching view element which content should\n\t * be treated as a raw data.\n\t */\n\tregisterRawContentMatcher( pattern ) {\n\t\tthis._rawContentElementMatcher.add( pattern );\n\t}\n\n\t/**\n\t * Checks if the given DOM position is a correct place for selection boundary. See {@link #isDomSelectionCorrect}.\n\t *\n\t * @private\n\t * @param {Element} domParent Position parent.\n\t * @param {Number} offset Position offset.\n\t * @returns {Boolean} `true` if given position is at a correct place for selection boundary, `false` otherwise.\n\t */\n\t_isDomSelectionPositionCorrect( domParent, offset ) {\n\t\t// If selection is before or in the middle of inline filler string, it is incorrect.\n\t\tif ( isText( domParent ) && startsWithFiller( domParent ) && offset < INLINE_FILLER_LENGTH ) {\n\t\t\t// Selection in a text node, at wrong position (before or in the middle of filler).\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( this.isElement( domParent ) && startsWithFiller( domParent.childNodes[ offset ] ) ) {\n\t\t\t// Selection in an element node, before filler text node.\n\t\t\treturn false;\n\t\t}\n\n\t\tconst viewParent = this.mapDomToView( domParent );\n\n\t\t// The position is incorrect when anchored inside a UIElement or a RawElement.\n\t\t// Note: In case of UIElement and RawElement, mapDomToView() returns a parent element for any DOM child\n\t\t// so there's no need to perform any additional checks.\n\t\tif ( viewParent && ( viewParent.is( 'uiElement' ) || viewParent.is( 'rawElement' ) ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Takes text data from a given {@link module:engine/view/text~Text#data} and processes it so\n\t * it is correctly displayed in the DOM.\n\t *\n\t * Following changes are done:\n\t *\n\t * * a space at the beginning is changed to `&nbsp;` if this is the first text node in its container\n\t * element or if a previous text node ends with a space character,\n\t * * space at the end of the text node is changed to `&nbsp;` if there are two spaces at the end of a node or if next node\n\t * starts with a space or if it is the last text node in its container,\n\t * * remaining spaces are replaced to a chain of spaces and `&nbsp;` (e.g. `'x   x'` becomes `'x &nbsp; x'`).\n\t *\n\t * Content of {@link #preElements} is not processed.\n\t *\n\t * @private\n\t * @param {module:engine/view/text~Text} node View text node to process.\n\t * @returns {String} Processed text data.\n\t */\n\t_processDataFromViewText( node ) {\n\t\tlet data = node.data;\n\n\t\t// If any of node ancestors has a name which is in `preElements` array, then currently processed\n\t\t// view text node is (will be) in preformatted element. We should not change whitespaces then.\n\t\tif ( node.getAncestors().some( parent => this.preElements.includes( parent.name ) ) ) {\n\t\t\treturn data;\n\t\t}\n\n\t\t// 1. Replace the first space with a nbsp if the previous node ends with a space or there is no previous node\n\t\t// (container element boundary).\n\t\tif ( data.charAt( 0 ) == ' ' ) {\n\t\t\tconst prevNode = this._getTouchingViewTextNode( node, false );\n\t\t\tconst prevEndsWithSpace = prevNode && this._nodeEndsWithSpace( prevNode );\n\n\t\t\tif ( prevEndsWithSpace || !prevNode ) {\n\t\t\t\tdata = '\\u00A0' + data.substr( 1 );\n\t\t\t}\n\t\t}\n\n\t\t// 2. Replace the last space with nbsp if there are two spaces at the end or if the next node starts with space or there is no\n\t\t// next node (container element boundary).\n\t\t//\n\t\t// Keep in mind that Firefox prefers $nbsp; before tag, not inside it:\n\t\t//\n\t\t// Foo <span>&nbsp;bar</span>  <-- bad.\n\t\t// Foo&nbsp;<span> bar</span>  <-- good.\n\t\t//\n\t\t// More here: https://github.com/ckeditor/ckeditor5-engine/issues/1747.\n\t\tif ( data.charAt( data.length - 1 ) == ' ' ) {\n\t\t\tconst nextNode = this._getTouchingViewTextNode( node, true );\n\n\t\t\tif ( data.charAt( data.length - 2 ) == ' ' || !nextNode || nextNode.data.charAt( 0 ) == ' ' ) {\n\t\t\t\tdata = data.substr( 0, data.length - 1 ) + '\\u00A0';\n\t\t\t}\n\t\t}\n\n\t\t// 3. Create space+nbsp pairs.\n\t\treturn data.replace( / {2}/g, ' \\u00A0' );\n\t}\n\n\t/**\n\t * Checks whether given node ends with a space character after changing appropriate space characters to `&nbsp;`s.\n\t *\n\t * @private\n\t * @param {module:engine/view/text~Text} node Node to check.\n\t * @returns {Boolean} `true` if given `node` ends with space, `false` otherwise.\n\t */\n\t_nodeEndsWithSpace( node ) {\n\t\tif ( node.getAncestors().some( parent => this.preElements.includes( parent.name ) ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst data = this._processDataFromViewText( node );\n\n\t\treturn data.charAt( data.length - 1 ) == ' ';\n\t}\n\n\t/**\n\t * Takes text data from native `Text` node and processes it to a correct {@link module:engine/view/text~Text view text node} data.\n\t *\n\t * Following changes are done:\n\t *\n\t * * multiple whitespaces are replaced to a single space,\n\t * * space at the beginning of a text node is removed if it is the first text node in its container\n\t * element or if the previous text node ends with a space character,\n\t * * space at the end of the text node is removed if there are two spaces at the end of a node or if next node\n\t * starts with a space or if it is the last text node in its container\n\t * * nbsps are converted to spaces.\n\t *\n\t * @param {Node} node DOM text node to process.\n\t * @returns {String} Processed data.\n\t * @private\n\t */\n\t_processDataFromDomText( node ) {\n\t\tlet data = node.data;\n\n\t\tif ( _hasDomParentOfType( node, this.preElements ) ) {\n\t\t\treturn getDataWithoutFiller( node );\n\t\t}\n\n\t\t// Change all consecutive whitespace characters (from the [ \\n\\t\\r] set –\n\t\t// see https://github.com/ckeditor/ckeditor5-engine/issues/822#issuecomment-311670249) to a single space character.\n\t\t// That's how multiple whitespaces are treated when rendered, so we normalize those whitespaces.\n\t\t// We're replacing 1+ (and not 2+) to also normalize singular \\n\\t\\r characters (#822).\n\t\tdata = data.replace( /[ \\n\\t\\r]{1,}/g, ' ' );\n\n\t\tconst prevNode = this._getTouchingInlineDomNode( node, false );\n\t\tconst nextNode = this._getTouchingInlineDomNode( node, true );\n\n\t\tconst shouldLeftTrim = this._checkShouldLeftTrimDomText( node, prevNode );\n\t\tconst shouldRightTrim = this._checkShouldRightTrimDomText( node, nextNode );\n\n\t\t// If the previous dom text node does not exist or it ends by whitespace character, remove space character from the beginning\n\t\t// of this text node. Such space character is treated as a whitespace.\n\t\tif ( shouldLeftTrim ) {\n\t\t\tdata = data.replace( /^ /, '' );\n\t\t}\n\n\t\t// If the next text node does not exist remove space character from the end of this text node.\n\t\tif ( shouldRightTrim ) {\n\t\t\tdata = data.replace( / $/, '' );\n\t\t}\n\n\t\t// At the beginning and end of a block element, Firefox inserts normal space + <br> instead of non-breaking space.\n\t\t// This means that the text node starts/end with normal space instead of non-breaking space.\n\t\t// This causes a problem because the normal space would be removed in `.replace` calls above. To prevent that,\n\t\t// the inline filler is removed only after the data is initially processed (by the `.replace` above). See ckeditor5#692.\n\t\tdata = getDataWithoutFiller( new Text( data ) );\n\n\t\t// At this point we should have removed all whitespaces from DOM text data.\n\t\t//\n\t\t// Now, We will reverse the process that happens in `_processDataFromViewText`.\n\t\t//\n\t\t// We have to change &nbsp; chars, that were in DOM text data because of rendering reasons, to spaces.\n\t\t// First, change all ` \\u00A0` pairs (space + &nbsp;) to two spaces. DOM converter changes two spaces from model/view to\n\t\t// ` \\u00A0` to ensure proper rendering. Since here we convert back, we recognize those pairs and change them back to `  `.\n\t\tdata = data.replace( / \\u00A0/g, '  ' );\n\n\t\t// Then, let's change the last nbsp to a space.\n\t\tif ( /( |\\u00A0)\\u00A0$/.test( data ) || !nextNode || ( nextNode.data && nextNode.data.charAt( 0 ) == ' ' ) ) {\n\t\t\tdata = data.replace( /\\u00A0$/, ' ' );\n\t\t}\n\n\t\t// Then, change &nbsp; character that is at the beginning of the text node to space character.\n\t\t// We do that replacement only if this is the first node or the previous node ends on whitespace character.\n\t\tif ( shouldLeftTrim ) {\n\t\t\tdata = data.replace( /^\\u00A0/, ' ' );\n\t\t}\n\n\t\t// At this point, all whitespaces should be removed and all &nbsp; created for rendering reasons should be\n\t\t// changed to normal space. All left &nbsp; are &nbsp; inserted intentionally.\n\t\treturn data;\n\t}\n\n\t/**\n\t * Helper function which checks if a DOM text node, preceded by the given `prevNode` should\n\t * be trimmed from the left side.\n\t *\n\t * @private\n\t * @param {Node} node\n\t * @param {Node} prevNode\n\t */\n\t_checkShouldLeftTrimDomText( node, prevNode ) {\n\t\tif ( !prevNode ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif ( isElement( prevNode ) ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Shouldn't left trim if previous node is a node that was encountered as a raw content node.\n\t\tif ( this._encounteredRawContentDomNodes.has( node.previousSibling ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn /[^\\S\\u00A0]/.test( prevNode.data.charAt( prevNode.data.length - 1 ) );\n\t}\n\n\t/**\n\t * Helper function which checks if a DOM text node, succeeded by the given `nextNode` should\n\t * be trimmed from the right side.\n\t *\n\t * @private\n\t * @param {Node} node\n\t * @param {Node} nextNode\n\t */\n\t_checkShouldRightTrimDomText( node, nextNode ) {\n\t\tif ( nextNode ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !startsWithFiller( node );\n\t}\n\n\t/**\n\t * Helper function. For given {@link module:engine/view/text~Text view text node}, it finds previous or next sibling\n\t * that is contained in the same container element. If there is no such sibling, `null` is returned.\n\t *\n\t * @private\n\t * @param {module:engine/view/text~Text} node Reference node.\n\t * @param {Boolean} getNext\n\t * @returns {module:engine/view/text~Text|null} Touching text node or `null` if there is no next or previous touching text node.\n\t */\n\t_getTouchingViewTextNode( node, getNext ) {\n\t\tconst treeWalker = new ViewTreeWalker( {\n\t\t\tstartPosition: getNext ? ViewPosition._createAfter( node ) : ViewPosition._createBefore( node ),\n\t\t\tdirection: getNext ? 'forward' : 'backward'\n\t\t} );\n\n\t\tfor ( const value of treeWalker ) {\n\t\t\t// ViewContainerElement is found on a way to next ViewText node, so given `node` was first/last\n\t\t\t// text node in its container element.\n\t\t\tif ( value.item.is( 'containerElement' ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t// <br> found – it works like a block boundary, so do not scan further.\n\t\t\telse if ( value.item.is( 'element', 'br' ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t// Found a text node in the same container element.\n\t\t\telse if ( value.item.is( '$textProxy' ) ) {\n\t\t\t\treturn value.item;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Helper function. For the given text node, it finds the closest touching node which is either\n\t * a text node or a `<br>`. The search is terminated at block element boundaries and if a matching node\n\t * wasn't found so far, `null` is returned.\n\t *\n\t * In the following DOM structure:\n\t *\n\t *\t\t<p>foo<b>bar</b><br>bom</p>\n\t *\n\t * * `foo` doesn't have its previous touching inline node (`null` is returned),\n\t * * `foo`'s next touching inline node is `bar`\n\t * * `bar`'s next touching inline node is `<br>`\n\t *\n\t * This method returns text nodes and `<br>` elements because these types of nodes affect how\n\t * spaces in the given text node need to be converted.\n\t *\n\t * @private\n\t * @param {Text} node\n\t * @param {Boolean} getNext\n\t * @returns {Text|Element|null}\n\t */\n\t_getTouchingInlineDomNode( node, getNext ) {\n\t\tif ( !node.parentNode ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst direction = getNext ? 'nextNode' : 'previousNode';\n\t\tconst document = node.ownerDocument;\n\t\tconst topmostParent = getAncestors( node )[ 0 ];\n\n\t\tconst treeWalker = document.createTreeWalker( topmostParent, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, {\n\t\t\tacceptNode( node ) {\n\t\t\t\tif ( isText( node ) ) {\n\t\t\t\t\treturn NodeFilter.FILTER_ACCEPT;\n\t\t\t\t}\n\n\t\t\t\tif ( node.tagName == 'BR' ) {\n\t\t\t\t\treturn NodeFilter.FILTER_ACCEPT;\n\t\t\t\t}\n\n\t\t\t\treturn NodeFilter.FILTER_SKIP;\n\t\t\t}\n\t\t} );\n\n\t\ttreeWalker.currentNode = node;\n\n\t\tconst touchingNode = treeWalker[ direction ]();\n\n\t\tif ( touchingNode !== null ) {\n\t\t\tconst lca = getCommonAncestor( node, touchingNode );\n\n\t\t\t// If there is common ancestor between the text node and next/prev text node,\n\t\t\t// and there are no block elements on a way from the text node to that ancestor,\n\t\t\t// and there are no block elements on a way from next/prev text node to that ancestor...\n\t\t\tif (\n\t\t\t\tlca &&\n\t\t\t\t!_hasDomParentOfType( node, this.blockElements, lca ) &&\n\t\t\t\t!_hasDomParentOfType( touchingNode, this.blockElements, lca )\n\t\t\t) {\n\t\t\t\t// Then they are in the same container element.\n\t\t\t\treturn touchingNode;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n}\n\n// Helper function.\n// Used to check if given native `Element` or `Text` node has parent with tag name from `types` array.\n//\n// @param {Node} node\n// @param {Array.<String>} types\n// @param {Boolean} [boundaryParent] Can be given if parents should be checked up to a given element (excluding that element).\n// @returns {Boolean} `true` if such parent exists or `false` if it does not.\nfunction _hasDomParentOfType( node, types, boundaryParent ) {\n\tlet parents = getAncestors( node );\n\n\tif ( boundaryParent ) {\n\t\tparents = parents.slice( parents.indexOf( boundaryParent ) + 1 );\n\t}\n\n\treturn parents.some( parent => parent.tagName && types.includes( parent.tagName.toLowerCase() ) );\n}\n\n// A helper that executes given callback for each DOM node's ancestor, starting from the given node\n// and ending in document#documentElement.\n//\n// @param {Node} node\n// @param {Function} callback A callback to be executed for each ancestor.\nfunction forEachDomNodeAncestor( node, callback ) {\n\twhile ( node && node != global.document ) {\n\t\tcallback( node );\n\t\tnode = node.parentNode;\n\t}\n}\n\n// Checks if given node is a nbsp block filler.\n//\n// A &nbsp; is a block filler only if it is a single child of a block element.\n//\n// @param {Node} domNode DOM node.\n// @returns {Boolean}\nfunction isNbspBlockFiller( domNode, blockElements ) {\n\tconst isNBSP = isText( domNode ) && domNode.data == '\\u00A0';\n\n\treturn isNBSP && hasBlockParent( domNode, blockElements ) && domNode.parentNode.childNodes.length === 1;\n}\n\n// Checks if domNode has block parent.\n//\n// @param {Node} domNode DOM node.\n// @returns {Boolean}\nfunction hasBlockParent( domNode, blockElements ) {\n\tconst parent = domNode.parentNode;\n\n\treturn parent && parent.tagName && blockElements.includes( parent.tagName.toLowerCase() );\n}\n\n/**\n * Enum representing type of the block filler.\n *\n * Possible values:\n *\n * * `br` - for `<br>` block filler used in editing view,\n * * `nbsp` - for `&nbsp;` block fillers used in the data.\n *\n * @typedef {String} module:engine/view/filler~BlockFillerMode\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/getcommonancestor\n */\n\nimport getAncestors from './getancestors';\n\n/**\n * Searches and returns the lowest common ancestor of two given nodes.\n *\n * @param {Node} nodeA First node.\n * @param {Node} nodeB Second node.\n * @returns {Node|DocumentFragment|Document|null} Lowest common ancestor of both nodes or `null` if nodes do not have a common ancestor.\n */\nexport default function getCommonAncestor( nodeA, nodeB ) {\n\tconst ancestorsA = getAncestors( nodeA );\n\tconst ancestorsB = getAncestors( nodeB );\n\n\tlet i = 0;\n\n\t// It does not matter which array is shorter.\n\twhile ( ancestorsA[ i ] == ancestorsB[ i ] && ancestorsA[ i ] ) {\n\t\ti++;\n\t}\n\n\treturn i === 0 ? null : ancestorsA[ i - 1 ];\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/iswindow\n */\n\n/**\n * Checks if the object is a native DOM Window.\n *\n * @param {*} obj\n * @returns {Boolean}\n */\nexport default function isWindow( obj ) {\n\tconst stringifiedObject = Object.prototype.toString.apply( obj );\n\n\t// Returns `true` for the `window` object in browser environments.\n\tif ( stringifiedObject == '[object Window]' ) {\n\t\treturn true;\n\t}\n\n\t// Returns `true` for the `window` object in the Electron environment.\n\tif ( stringifiedObject == '[object global]' ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/emittermixin\n */\n\nimport { default as EmitterMixin, _getEmitterListenedTo, _setEmitterId } from '../emittermixin';\nimport uid from '../uid';\nimport isNode from './isnode';\nimport isWindow from './iswindow';\nimport { extend } from 'lodash-es';\n\n/**\n * Mixin that injects the DOM events API into its host. It provides the API\n * compatible with {@link module:utils/emittermixin~EmitterMixin}.\n *\n * DOM emitter mixin is by default available in the {@link module:ui/view~View} class,\n * but it can also be mixed into any other class:\n *\n *\t\timport mix from '../utils/mix.js';\n *\t\timport DomEmitterMixin from '../utils/dom/emittermixin.js';\n *\n *\t\tclass SomeView {}\n *\t\tmix( SomeView, DomEmitterMixin );\n *\n *\t\tconst view = new SomeView();\n *\t\tview.listenTo( domElement, ( evt, domEvt ) => {\n *\t\t\tconsole.log( evt, domEvt );\n *\t\t} );\n *\n * @mixin EmitterMixin\n * @mixes module:utils/emittermixin~EmitterMixin\n * @implements module:utils/dom/emittermixin~Emitter\n */\nconst DomEmitterMixin = extend( {}, EmitterMixin, {\n\t/**\n\t * Registers a callback function to be executed when an event is fired in a specific Emitter or DOM Node.\n\t * It is backwards compatible with {@link module:utils/emittermixin~EmitterMixin#listenTo}.\n\t *\n\t * @param {module:utils/emittermixin~Emitter|Node} emitter The object that fires the event.\n\t * @param {String} event The name of the event.\n\t * @param {Function} callback The function to be called on event.\n\t * @param {Object} [options={}] Additional options.\n\t * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher\n\t * the priority value the sooner the callback will be fired. Events having the same priority are called in the\n\t * order they were added.\n\t * @param {Boolean} [options.useCapture=false] Indicates that events of this type will be dispatched to the registered\n\t * listener before being dispatched to any EventTarget beneath it in the DOM tree.\n\t * @param {Boolean} [options.usePassive=false] Indicates that the function specified by listener will never call preventDefault()\n\t * and prevents blocking browser's main thread by this event handler.\n\t */\n\tlistenTo( emitter, ...rest ) {\n\t\t// Check if emitter is an instance of DOM Node. If so, replace the argument with\n\t\t// corresponding ProxyEmitter (or create one if not existing).\n\t\tif ( isNode( emitter ) || isWindow( emitter ) ) {\n\t\t\tconst proxy = this._getProxyEmitter( emitter ) || new ProxyEmitter( emitter );\n\n\t\t\tproxy.attach( ...rest );\n\n\t\t\temitter = proxy;\n\t\t}\n\n\t\t// Execute parent class method with Emitter (or ProxyEmitter) instance.\n\t\tEmitterMixin.listenTo.call( this, emitter, ...rest );\n\t},\n\n\t/**\n\t * Stops listening for events. It can be used at different levels:\n\t * It is backwards compatible with {@link module:utils/emittermixin~EmitterMixin#listenTo}.\n\t *\n\t * * To stop listening to a specific callback.\n\t * * To stop listening to a specific event.\n\t * * To stop listening to all events fired by a specific object.\n\t * * To stop listening to all events fired by all object.\n\t *\n\t * @param {module:utils/emittermixin~Emitter|Node} [emitter] The object to stop listening to. If omitted, stops it for all objects.\n\t * @param {String} [event] (Requires the `emitter`) The name of the event to stop listening to. If omitted, stops it\n\t * for all events from `emitter`.\n\t * @param {Function} [callback] (Requires the `event`) The function to be removed from the call list for the given\n\t * `event`.\n\t */\n\tstopListening( emitter, event, callback ) {\n\t\t// Check if emitter is an instance of DOM Node. If so, replace the argument with corresponding ProxyEmitter.\n\t\tif ( isNode( emitter ) || isWindow( emitter ) ) {\n\t\t\tconst proxy = this._getProxyEmitter( emitter );\n\n\t\t\t// Element has no listeners.\n\t\t\tif ( !proxy ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\temitter = proxy;\n\t\t}\n\n\t\t// Execute parent class method with Emitter (or ProxyEmitter) instance.\n\t\tEmitterMixin.stopListening.call( this, emitter, event, callback );\n\n\t\tif ( emitter instanceof ProxyEmitter ) {\n\t\t\temitter.detach( event );\n\t\t}\n\t},\n\n\t/**\n\t * Retrieves ProxyEmitter instance for given DOM Node residing in this Host.\n\t *\n\t * @private\n\t * @param {Node} node DOM Node of the ProxyEmitter.\n\t * @returns {module:utils/dom/emittermixin~ProxyEmitter} ProxyEmitter instance or null.\n\t */\n\t_getProxyEmitter( node ) {\n\t\treturn _getEmitterListenedTo( this, getNodeUID( node ) );\n\t}\n} );\n\nexport default DomEmitterMixin;\n\n/**\n * Creates a ProxyEmitter instance. Such an instance is a bridge between a DOM Node firing events\n * and any Host listening to them. It is backwards compatible with {@link module:utils/emittermixin~EmitterMixin#on}.\n *\n *                                  listenTo( click, ... )\n *                    +-----------------------------------------+\n *                    |              stopListening( ... )       |\n *     +----------------------------+                           |             addEventListener( click, ... )\n *     | Host                       |                           |   +---------------------------------------------+\n *     +----------------------------+                           |   |       removeEventListener( click, ... )     |\n *     | _listeningTo: {            |                +----------v-------------+                                   |\n *     |   UID: {                   |                | ProxyEmitter           |                                   |\n *     |     emitter: ProxyEmitter, |                +------------------------+                      +------------v----------+\n *     |     callbacks: {           |                | events: {              |                      | Node (HTMLElement)    |\n *     |       click: [ callbacks ] |                |   click: [ callbacks ] |                      +-----------------------+\n *     |     }                      |                | },                     |                      | data-ck-expando: UID  |\n *     |   }                        |                | _domNode: Node,        |                      +-----------------------+\n *     | }                          |                | _domListeners: {},     |                                   |\n *     | +------------------------+ |                | _emitterId: UID        |                                   |\n *     | | DomEmitterMixin        | |                +--------------^---------+                                   |\n *     | +------------------------+ |                           |   |                                             |\n *     +--------------^-------------+                           |   +---------------------------------------------+\n *                    |                                         |                  click (DOM Event)\n *                    +-----------------------------------------+\n *                                fire( click, DOM Event )\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n * @implements module:utils/dom/emittermixin~Emitter\n * @private\n */\nclass ProxyEmitter {\n\t/**\n\t * @param {Node} node DOM Node that fires events.\n\t * @returns {Object} ProxyEmitter instance bound to the DOM Node.\n\t */\n\tconstructor( node ) {\n\t\t// Set emitter ID to match DOM Node \"expando\" property.\n\t\t_setEmitterId( this, getNodeUID( node ) );\n\n\t\t// Remember the DOM Node this ProxyEmitter is bound to.\n\t\tthis._domNode = node;\n\t}\n}\n\nextend( ProxyEmitter.prototype, EmitterMixin, {\n\t/**\n\t * Collection of native DOM listeners.\n\t *\n\t * @private\n\t * @member {Object} module:utils/dom/emittermixin~ProxyEmitter#_domListeners\n\t */\n\n\t/**\n\t * Registers a callback function to be executed when an event is fired.\n\t *\n\t * It attaches a native DOM listener to the DOM Node. When fired,\n\t * a corresponding Emitter event will also fire with DOM Event object as an argument.\n\t *\n\t * @method module:utils/dom/emittermixin~ProxyEmitter#attach\n\t * @param {String} event The name of the event.\n\t * @param {Function} callback The function to be called on event.\n\t * @param {Object} [options={}] Additional options.\n\t * @param {Boolean} [options.useCapture=false] Indicates that events of this type will be dispatched to the registered\n\t * listener before being dispatched to any EventTarget beneath it in the DOM tree.\n\t * @param {Boolean} [options.usePassive=false] Indicates that the function specified by listener will never call preventDefault()\n\t * and prevents blocking browser's main thread by this event handler.\n\t */\n\tattach( event, callback, options = {} ) {\n\t\t// If the DOM Listener for given event already exist it is pointless\n\t\t// to attach another one.\n\t\tif ( this._domListeners && this._domListeners[ event ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst listenerOptions = {\n\t\t\tcapture: !!options.useCapture,\n\t\t\tpassive: !!options.usePassive\n\t\t};\n\n\t\tconst domListener = this._createDomListener( event, listenerOptions );\n\n\t\t// Attach the native DOM listener to DOM Node.\n\t\tthis._domNode.addEventListener( event, domListener, listenerOptions );\n\n\t\tif ( !this._domListeners ) {\n\t\t\tthis._domListeners = {};\n\t\t}\n\n\t\t// Store the native DOM listener in this ProxyEmitter. It will be helpful\n\t\t// when stopping listening to the event.\n\t\tthis._domListeners[ event ] = domListener;\n\t},\n\n\t/**\n\t * Stops executing the callback on the given event.\n\t *\n\t * @method module:utils/dom/emittermixin~ProxyEmitter#detach\n\t * @param {String} event The name of the event.\n\t */\n\tdetach( event ) {\n\t\tlet events;\n\n\t\t// Remove native DOM listeners which are orphans. If no callbacks\n\t\t// are awaiting given event, detach native DOM listener from DOM Node.\n\t\t// See: {@link attach}.\n\n\t\tif ( this._domListeners[ event ] && ( !( events = this._events[ event ] ) || !events.callbacks.length ) ) {\n\t\t\tthis._domListeners[ event ].removeListener();\n\t\t}\n\t},\n\n\t/**\n\t * Creates a native DOM listener callback. When the native DOM event\n\t * is fired it will fire corresponding event on this ProxyEmitter.\n\t * Note: A native DOM Event is passed as an argument.\n\t *\n\t * @private\n\t * @method module:utils/dom/emittermixin~ProxyEmitter#_createDomListener\n\t * @param {String} event The name of the event.\n\t * @param {Object} [options] Additional options.\n\t * @param {Boolean} [options.capture=false] Indicates whether the listener was created for capturing event.\n\t * @param {Boolean} [options.passive=false] Indicates that the function specified by listener will never call preventDefault()\n\t * and prevents blocking browser's main thread by this event handler.\n\t * @returns {Function} The DOM listener callback.\n\t */\n\t_createDomListener( event, options ) {\n\t\tconst domListener = domEvt => {\n\t\t\tthis.fire( event, domEvt );\n\t\t};\n\n\t\t// Supply the DOM listener callback with a function that will help\n\t\t// detach it from the DOM Node, when it is no longer necessary.\n\t\t// See: {@link detach}.\n\t\tdomListener.removeListener = () => {\n\t\t\tthis._domNode.removeEventListener( event, domListener, options );\n\t\t\tdelete this._domListeners[ event ];\n\t\t};\n\n\t\treturn domListener;\n\t}\n} );\n\n// Gets an unique DOM Node identifier. The identifier will be set if not defined.\n//\n// @private\n// @param {Node} node\n// @returns {String} UID for given DOM Node.\nfunction getNodeUID( node ) {\n\treturn node[ 'data-ck-expando' ] || ( node[ 'data-ck-expando' ] = uid() );\n}\n\n/**\n * Interface representing classes which mix in {@link module:utils/dom/emittermixin~EmitterMixin}.\n *\n * @interface Emitter\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/observer/observer\n */\n\nimport DomEmitterMixin from '@ckeditor/ckeditor5-utils/src/dom/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Abstract base observer class. Observers are classes which listen to DOM events, do the preliminary\n * processing and fire events on the {@link module:engine/view/document~Document} objects.\n * Observers can also add features to the view, for instance by updating its status or marking elements\n * which need a refresh on DOM events.\n *\n * @abstract\n */\nexport default class Observer {\n\t/**\n\t * Creates an instance of the observer.\n\t *\n\t * @param {module:engine/view/view~View} view\n\t */\n\tconstructor( view ) {\n\t\t/**\n\t\t * An instance of the view controller.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/view~View}\n\t\t */\n\t\tthis.view = view;\n\n\t\t/**\n\t\t * A reference to the {@link module:engine/view/document~Document} object.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = view.document;\n\n\t\t/**\n\t\t * State of the observer. If it is disabled no events will be fired.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis.isEnabled = false;\n\t}\n\n\t/**\n\t * Enables the observer. This method is called when the observer is registered to the\n\t * {@link module:engine/view/view~View} and after {@link module:engine/view/view~View#forceRender rendering}\n\t * (all observers are {@link #disable disabled} before rendering).\n\t *\n\t * A typical use case for disabling observers is that mutation observers need to be disabled for the rendering.\n\t * However, a child class may not need to be disabled, so it can implement an empty method.\n\t *\n\t * @see module:engine/view/observer/observer~Observer#disable\n\t */\n\tenable() {\n\t\tthis.isEnabled = true;\n\t}\n\n\t/**\n\t * Disables the observer. This method is called before\n\t * {@link module:engine/view/view~View#forceRender rendering} to prevent firing events during rendering.\n\t *\n\t * @see module:engine/view/observer/observer~Observer#enable\n\t */\n\tdisable() {\n\t\tthis.isEnabled = false;\n\t}\n\n\t/**\n\t * Disables and destroys the observer, among others removes event listeners created by the observer.\n\t */\n\tdestroy() {\n\t\tthis.disable();\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Checks whether a given DOM event should be ignored (should not be turned into a synthetic view document event).\n\t *\n\t * Currently, an event will be ignored only if its target or any of its ancestors has the `data-cke-ignore-events` attribute.\n\t * This attribute can be used inside the structures generated by\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement `DowncastWriter#createUIElement()`} to ignore events\n\t * fired within a UI that should be excluded from CKEditor 5's realms.\n\t *\n\t * @param {Node} domTarget The DOM event target to check (usually an element, sometimes a text node and\n\t * potentially sometimes a document, too).\n\t * @returns {Boolean} Whether this event should be ignored by the observer.\n\t */\n\tcheckShouldIgnoreEventFromTarget( domTarget ) {\n\t\tif ( domTarget && domTarget.nodeType === 3 ) {\n\t\t\tdomTarget = domTarget.parentNode;\n\t\t}\n\n\t\tif ( !domTarget || domTarget.nodeType !== 1 ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn domTarget.matches( '[data-cke-ignore-events], [data-cke-ignore-events] *' );\n\t}\n\n\t/**\n\t * Starts observing the given root element.\n\t *\n\t * @method #observe\n\t * @param {HTMLElement} domElement\n\t * @param {String} name The name of the root element.\n\t */\n}\n\nmix( Observer, DomEmitterMixin );\n","/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/**\n * Adds `value` to the array cache.\n *\n * @private\n * @name add\n * @memberOf SetCache\n * @alias push\n * @param {*} value The value to cache.\n * @returns {Object} Returns the cache instance.\n */\nfunction setCacheAdd(value) {\n  this.__data__.set(value, HASH_UNDEFINED);\n  return this;\n}\n\nexport default setCacheAdd;\n","/**\n * Checks if `value` is in the array cache.\n *\n * @private\n * @name has\n * @memberOf SetCache\n * @param {*} value The value to search for.\n * @returns {number} Returns `true` if `value` is found, else `false`.\n */\nfunction setCacheHas(value) {\n  return this.__data__.has(value);\n}\n\nexport default setCacheHas;\n","import MapCache from './_MapCache.js';\nimport setCacheAdd from './_setCacheAdd.js';\nimport setCacheHas from './_setCacheHas.js';\n\n/**\n *\n * Creates an array cache object to store unique values.\n *\n * @private\n * @constructor\n * @param {Array} [values] The values to cache.\n */\nfunction SetCache(values) {\n  var index = -1,\n      length = values == null ? 0 : values.length;\n\n  this.__data__ = new MapCache;\n  while (++index < length) {\n    this.add(values[index]);\n  }\n}\n\n// Add methods to `SetCache`.\nSetCache.prototype.add = SetCache.prototype.push = setCacheAdd;\nSetCache.prototype.has = setCacheHas;\n\nexport default SetCache;\n","/**\n * A specialized version of `_.some` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {boolean} Returns `true` if any element passes the predicate check,\n *  else `false`.\n */\nfunction arraySome(array, predicate) {\n  var index = -1,\n      length = array == null ? 0 : array.length;\n\n  while (++index < length) {\n    if (predicate(array[index], index, array)) {\n      return true;\n    }\n  }\n  return false;\n}\n\nexport default arraySome;\n","/**\n * Checks if a `cache` value for `key` exists.\n *\n * @private\n * @param {Object} cache The cache to query.\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 */\nfunction cacheHas(cache, key) {\n  return cache.has(key);\n}\n\nexport default cacheHas;\n","import SetCache from './_SetCache.js';\nimport arraySome from './_arraySome.js';\nimport cacheHas from './_cacheHas.js';\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1,\n    COMPARE_UNORDERED_FLAG = 2;\n\n/**\n * A specialized version of `baseIsEqualDeep` for arrays with support for\n * partial deep comparisons.\n *\n * @private\n * @param {Array} array The array to compare.\n * @param {Array} other The other array to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed `array` and `other` objects.\n * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.\n */\nfunction equalArrays(array, other, bitmask, customizer, equalFunc, stack) {\n  var isPartial = bitmask & COMPARE_PARTIAL_FLAG,\n      arrLength = array.length,\n      othLength = other.length;\n\n  if (arrLength != othLength && !(isPartial && othLength > arrLength)) {\n    return false;\n  }\n  // Assume cyclic values are equal.\n  var stacked = stack.get(array);\n  if (stacked && stack.get(other)) {\n    return stacked == other;\n  }\n  var index = -1,\n      result = true,\n      seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined;\n\n  stack.set(array, other);\n  stack.set(other, array);\n\n  // Ignore non-index properties.\n  while (++index < arrLength) {\n    var arrValue = array[index],\n        othValue = other[index];\n\n    if (customizer) {\n      var compared = isPartial\n        ? customizer(othValue, arrValue, index, other, array, stack)\n        : customizer(arrValue, othValue, index, array, other, stack);\n    }\n    if (compared !== undefined) {\n      if (compared) {\n        continue;\n      }\n      result = false;\n      break;\n    }\n    // Recursively compare arrays (susceptible to call stack limits).\n    if (seen) {\n      if (!arraySome(other, function(othValue, othIndex) {\n            if (!cacheHas(seen, othIndex) &&\n                (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) {\n              return seen.push(othIndex);\n            }\n          })) {\n        result = false;\n        break;\n      }\n    } else if (!(\n          arrValue === othValue ||\n            equalFunc(arrValue, othValue, bitmask, customizer, stack)\n        )) {\n      result = false;\n      break;\n    }\n  }\n  stack['delete'](array);\n  stack['delete'](other);\n  return result;\n}\n\nexport default equalArrays;\n","/**\n * Converts `map` to its key-value pairs.\n *\n * @private\n * @param {Object} map The map to convert.\n * @returns {Array} Returns the key-value pairs.\n */\nfunction mapToArray(map) {\n  var index = -1,\n      result = Array(map.size);\n\n  map.forEach(function(value, key) {\n    result[++index] = [key, value];\n  });\n  return result;\n}\n\nexport default mapToArray;\n","/**\n * Converts `set` to an array of its values.\n *\n * @private\n * @param {Object} set The set to convert.\n * @returns {Array} Returns the values.\n */\nfunction setToArray(set) {\n  var index = -1,\n      result = Array(set.size);\n\n  set.forEach(function(value) {\n    result[++index] = value;\n  });\n  return result;\n}\n\nexport default setToArray;\n","import Symbol from './_Symbol.js';\nimport Uint8Array from './_Uint8Array.js';\nimport eq from './eq.js';\nimport equalArrays from './_equalArrays.js';\nimport mapToArray from './_mapToArray.js';\nimport setToArray from './_setToArray.js';\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1,\n    COMPARE_UNORDERED_FLAG = 2;\n\n/** `Object#toString` result references. */\nvar boolTag = '[object Boolean]',\n    dateTag = '[object Date]',\n    errorTag = '[object Error]',\n    mapTag = '[object Map]',\n    numberTag = '[object Number]',\n    regexpTag = '[object RegExp]',\n    setTag = '[object Set]',\n    stringTag = '[object String]',\n    symbolTag = '[object Symbol]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n    dataViewTag = '[object DataView]';\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n    symbolValueOf = symbolProto ? symbolProto.valueOf : undefined;\n\n/**\n * A specialized version of `baseIsEqualDeep` for comparing objects of\n * the same `toStringTag`.\n *\n * **Note:** This function only supports comparing values with tags of\n * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {string} tag The `toStringTag` of the objects to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed `object` and `other` objects.\n * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.\n */\nfunction equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {\n  switch (tag) {\n    case dataViewTag:\n      if ((object.byteLength != other.byteLength) ||\n          (object.byteOffset != other.byteOffset)) {\n        return false;\n      }\n      object = object.buffer;\n      other = other.buffer;\n\n    case arrayBufferTag:\n      if ((object.byteLength != other.byteLength) ||\n          !equalFunc(new Uint8Array(object), new Uint8Array(other))) {\n        return false;\n      }\n      return true;\n\n    case boolTag:\n    case dateTag:\n    case numberTag:\n      // Coerce booleans to `1` or `0` and dates to milliseconds.\n      // Invalid dates are coerced to `NaN`.\n      return eq(+object, +other);\n\n    case errorTag:\n      return object.name == other.name && object.message == other.message;\n\n    case regexpTag:\n    case stringTag:\n      // Coerce regexes to strings and treat strings, primitives and objects,\n      // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring\n      // for more details.\n      return object == (other + '');\n\n    case mapTag:\n      var convert = mapToArray;\n\n    case setTag:\n      var isPartial = bitmask & COMPARE_PARTIAL_FLAG;\n      convert || (convert = setToArray);\n\n      if (object.size != other.size && !isPartial) {\n        return false;\n      }\n      // Assume cyclic values are equal.\n      var stacked = stack.get(object);\n      if (stacked) {\n        return stacked == other;\n      }\n      bitmask |= COMPARE_UNORDERED_FLAG;\n\n      // Recursively compare objects (susceptible to call stack limits).\n      stack.set(object, other);\n      var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack);\n      stack['delete'](object);\n      return result;\n\n    case symbolTag:\n      if (symbolValueOf) {\n        return symbolValueOf.call(object) == symbolValueOf.call(other);\n      }\n  }\n  return false;\n}\n\nexport default equalByTag;\n","import getAllKeys from './_getAllKeys.js';\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1;\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * A specialized version of `baseIsEqualDeep` for objects with support for\n * partial deep comparisons.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed `object` and `other` objects.\n * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.\n */\nfunction equalObjects(object, other, bitmask, customizer, equalFunc, stack) {\n  var isPartial = bitmask & COMPARE_PARTIAL_FLAG,\n      objProps = getAllKeys(object),\n      objLength = objProps.length,\n      othProps = getAllKeys(other),\n      othLength = othProps.length;\n\n  if (objLength != othLength && !isPartial) {\n    return false;\n  }\n  var index = objLength;\n  while (index--) {\n    var key = objProps[index];\n    if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) {\n      return false;\n    }\n  }\n  // Assume cyclic values are equal.\n  var stacked = stack.get(object);\n  if (stacked && stack.get(other)) {\n    return stacked == other;\n  }\n  var result = true;\n  stack.set(object, other);\n  stack.set(other, object);\n\n  var skipCtor = isPartial;\n  while (++index < objLength) {\n    key = objProps[index];\n    var objValue = object[key],\n        othValue = other[key];\n\n    if (customizer) {\n      var compared = isPartial\n        ? customizer(othValue, objValue, key, other, object, stack)\n        : customizer(objValue, othValue, key, object, other, stack);\n    }\n    // Recursively compare objects (susceptible to call stack limits).\n    if (!(compared === undefined\n          ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack))\n          : compared\n        )) {\n      result = false;\n      break;\n    }\n    skipCtor || (skipCtor = key == 'constructor');\n  }\n  if (result && !skipCtor) {\n    var objCtor = object.constructor,\n        othCtor = other.constructor;\n\n    // Non `Object` object instances with different constructors are not equal.\n    if (objCtor != othCtor &&\n        ('constructor' in object && 'constructor' in other) &&\n        !(typeof objCtor == 'function' && objCtor instanceof objCtor &&\n          typeof othCtor == 'function' && othCtor instanceof othCtor)) {\n      result = false;\n    }\n  }\n  stack['delete'](object);\n  stack['delete'](other);\n  return result;\n}\n\nexport default equalObjects;\n","import Stack from './_Stack.js';\nimport equalArrays from './_equalArrays.js';\nimport equalByTag from './_equalByTag.js';\nimport equalObjects from './_equalObjects.js';\nimport getTag from './_getTag.js';\nimport isArray from './isArray.js';\nimport isBuffer from './isBuffer.js';\nimport isTypedArray from './isTypedArray.js';\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1;\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n    arrayTag = '[object Array]',\n    objectTag = '[object Object]';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * A specialized version of `baseIsEqual` for arrays and objects which performs\n * deep comparisons and tracks traversed objects enabling objects with circular\n * references to be compared.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} [stack] Tracks traversed `object` and `other` objects.\n * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.\n */\nfunction baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {\n  var objIsArr = isArray(object),\n      othIsArr = isArray(other),\n      objTag = objIsArr ? arrayTag : getTag(object),\n      othTag = othIsArr ? arrayTag : getTag(other);\n\n  objTag = objTag == argsTag ? objectTag : objTag;\n  othTag = othTag == argsTag ? objectTag : othTag;\n\n  var objIsObj = objTag == objectTag,\n      othIsObj = othTag == objectTag,\n      isSameTag = objTag == othTag;\n\n  if (isSameTag && isBuffer(object)) {\n    if (!isBuffer(other)) {\n      return false;\n    }\n    objIsArr = true;\n    objIsObj = false;\n  }\n  if (isSameTag && !objIsObj) {\n    stack || (stack = new Stack);\n    return (objIsArr || isTypedArray(object))\n      ? equalArrays(object, other, bitmask, customizer, equalFunc, stack)\n      : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);\n  }\n  if (!(bitmask & COMPARE_PARTIAL_FLAG)) {\n    var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),\n        othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');\n\n    if (objIsWrapped || othIsWrapped) {\n      var objUnwrapped = objIsWrapped ? object.value() : object,\n          othUnwrapped = othIsWrapped ? other.value() : other;\n\n      stack || (stack = new Stack);\n      return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);\n    }\n  }\n  if (!isSameTag) {\n    return false;\n  }\n  stack || (stack = new Stack);\n  return equalObjects(object, other, bitmask, customizer, equalFunc, stack);\n}\n\nexport default baseIsEqualDeep;\n","import baseIsEqualDeep from './_baseIsEqualDeep.js';\nimport isObjectLike from './isObjectLike.js';\n\n/**\n * The base implementation of `_.isEqual` which supports partial comparisons\n * and tracks traversed objects.\n *\n * @private\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @param {boolean} bitmask The bitmask flags.\n *  1 - Unordered comparison\n *  2 - Partial comparison\n * @param {Function} [customizer] The function to customize comparisons.\n * @param {Object} [stack] Tracks traversed `value` and `other` objects.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n */\nfunction baseIsEqual(value, other, bitmask, customizer, stack) {\n  if (value === other) {\n    return true;\n  }\n  if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) {\n    return value !== value && other !== other;\n  }\n  return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);\n}\n\nexport default baseIsEqual;\n","import baseIsEqual from './_baseIsEqual.js';\n\n/**\n * This method is like `_.isEqual` except that it accepts `customizer` which\n * is invoked to compare values. If `customizer` returns `undefined`, comparisons\n * are handled by the method instead. The `customizer` is invoked with up to\n * six arguments: (objValue, othValue [, index|key, object, other, stack]).\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 * @param {Function} [customizer] The function to customize comparisons.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * function isGreeting(value) {\n *   return /^h(?:i|ello)$/.test(value);\n * }\n *\n * function customizer(objValue, othValue) {\n *   if (isGreeting(objValue) && isGreeting(othValue)) {\n *     return true;\n *   }\n * }\n *\n * var array = ['hello', 'goodbye'];\n * var other = ['hi', 'goodbye'];\n *\n * _.isEqualWith(array, other, customizer);\n * // => true\n */\nfunction isEqualWith(value, other, customizer) {\n  customizer = typeof customizer == 'function' ? customizer : undefined;\n  var result = customizer ? customizer(value, other) : undefined;\n  return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result;\n}\n\nexport default isEqualWith;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/observer/mutationobserver\n */\n\n/* globals window */\n\nimport Observer from './observer';\nimport ViewSelection from '../selection';\nimport { startsWithFiller, getDataWithoutFiller } from '../filler';\nimport { isEqualWith } from 'lodash-es';\n\n/**\n * Mutation observer class observes changes in the DOM, fires {@link module:engine/view/document~Document#event:mutations} event, mark view\n * elements as changed and call {@link module:engine/view/renderer~Renderer#render}.\n * Because all mutated nodes are marked as \"to be rendered\" and the\n * {@link module:engine/view/renderer~Renderer#render} is called, all changes will be reverted, unless the mutation will be handled by the\n * {@link module:engine/view/document~Document#event:mutations} event listener. It means user will see only handled changes, and the editor\n * will block all changes which are not handled.\n *\n * Mutation Observer also take care of reducing number of mutations which are fired. It removes duplicates and\n * mutations on elements which do not have corresponding view elements. Also\n * {@link module:engine/view/observer/mutationobserver~MutatedText text mutation} is fired only if parent element do not change child list.\n *\n * Note that this observer is attached by the {@link module:engine/view/view~View} and is available by default.\n *\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class MutationObserver extends Observer {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\t/**\n\t\t * Native mutation observer config.\n\t\t *\n\t\t * @private\n\t\t * @member {Object}\n\t\t */\n\t\tthis._config = {\n\t\t\tchildList: true,\n\t\t\tcharacterData: true,\n\t\t\tcharacterDataOldValue: true,\n\t\t\tsubtree: true\n\t\t};\n\n\t\t/**\n\t\t * Reference to the {@link module:engine/view/view~View#domConverter}.\n\t\t *\n\t\t * @member {module:engine/view/domconverter~DomConverter}\n\t\t */\n\t\tthis.domConverter = view.domConverter;\n\n\t\t/**\n\t\t * Reference to the {@link module:engine/view/view~View#_renderer}.\n\t\t *\n\t\t * @member {module:engine/view/renderer~Renderer}\n\t\t */\n\t\tthis.renderer = view._renderer;\n\n\t\t/**\n\t\t * Observed DOM elements.\n\t\t *\n\t\t * @private\n\t\t * @member {Array.<HTMLElement>}\n\t\t */\n\t\tthis._domElements = [];\n\n\t\t/**\n\t\t * Native mutation observer.\n\t\t *\n\t\t * @private\n\t\t * @member {MutationObserver}\n\t\t */\n\t\tthis._mutationObserver = new window.MutationObserver( this._onMutations.bind( this ) );\n\t}\n\n\t/**\n\t * Synchronously fires {@link module:engine/view/document~Document#event:mutations} event with all mutations in record queue.\n\t * At the same time empties the queue so mutations will not be fired twice.\n\t */\n\tflush() {\n\t\tthis._onMutations( this._mutationObserver.takeRecords() );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve( domElement ) {\n\t\tthis._domElements.push( domElement );\n\n\t\tif ( this.isEnabled ) {\n\t\t\tthis._mutationObserver.observe( domElement, this._config );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tenable() {\n\t\tsuper.enable();\n\n\t\tfor ( const domElement of this._domElements ) {\n\t\t\tthis._mutationObserver.observe( domElement, this._config );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdisable() {\n\t\tsuper.disable();\n\n\t\tthis._mutationObserver.disconnect();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tthis._mutationObserver.disconnect();\n\t}\n\n\t/**\n\t * Handles mutations. Deduplicates, mark view elements to sync, fire event and call render.\n\t *\n\t * @private\n\t * @param {Array.<Object>} domMutations Array of native mutations.\n\t */\n\t_onMutations( domMutations ) {\n\t\t// As a result of this.flush() we can have an empty collection.\n\t\tif ( domMutations.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst domConverter = this.domConverter;\n\n\t\t// Use map and set for deduplication.\n\t\tconst mutatedTexts = new Map();\n\t\tconst mutatedElements = new Set();\n\n\t\t// Handle `childList` mutations first, so we will be able to check if the `characterData` mutation is in the\n\t\t// element with changed structure anyway.\n\t\tfor ( const mutation of domMutations ) {\n\t\t\tif ( mutation.type === 'childList' ) {\n\t\t\t\tconst element = domConverter.mapDomToView( mutation.target );\n\n\t\t\t\t// Do not collect mutations from UIElements and RawElements.\n\t\t\t\tif ( element && ( element.is( 'uiElement' ) || element.is( 'rawElement' ) ) ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif ( element && !this._isBogusBrMutation( mutation ) ) {\n\t\t\t\t\tmutatedElements.add( element );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Handle `characterData` mutations later, when we have the full list of nodes which changed structure.\n\t\tfor ( const mutation of domMutations ) {\n\t\t\tconst element = domConverter.mapDomToView( mutation.target );\n\n\t\t\t// Do not collect mutations from UIElements and RawElements.\n\t\t\tif ( element && ( element.is( 'uiElement' ) || element.is( 'rawElement' ) ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ( mutation.type === 'characterData' ) {\n\t\t\t\tconst text = domConverter.findCorrespondingViewText( mutation.target );\n\n\t\t\t\tif ( text && !mutatedElements.has( text.parent ) ) {\n\t\t\t\t\t// Use text as a key, for deduplication. If there will be another mutation on the same text element\n\t\t\t\t\t// we will have only one in the map.\n\t\t\t\t\tmutatedTexts.set( text, {\n\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\toldText: text.data,\n\t\t\t\t\t\tnewText: getDataWithoutFiller( mutation.target ),\n\t\t\t\t\t\tnode: text\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\t// When we added first letter to the text node which had only inline filler, for the DOM it is mutation\n\t\t\t\t// on text, but for the view, where filler text node did not existed, new text node was created, so we\n\t\t\t\t// need to fire 'children' mutation instead of 'text'.\n\t\t\t\telse if ( !text && startsWithFiller( mutation.target ) ) {\n\t\t\t\t\tmutatedElements.add( domConverter.mapDomToView( mutation.target.parentNode ) );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Now we build the list of mutations to fire and mark elements. We did not do it earlier to avoid marking the\n\t\t// same node multiple times in case of duplication.\n\n\t\t// List of mutations we will fire.\n\t\tconst viewMutations = [];\n\n\t\tfor ( const mutatedText of mutatedTexts.values() ) {\n\t\t\tthis.renderer.markToSync( 'text', mutatedText.node );\n\t\t\tviewMutations.push( mutatedText );\n\t\t}\n\n\t\tfor ( const viewElement of mutatedElements ) {\n\t\t\tconst domElement = domConverter.mapViewToDom( viewElement );\n\t\t\tconst viewChildren = Array.from( viewElement.getChildren() );\n\t\t\tconst newViewChildren = Array.from( domConverter.domChildrenToView( domElement, { withChildren: false } ) );\n\n\t\t\t// It may happen that as a result of many changes (sth was inserted and then removed),\n\t\t\t// both elements haven't really changed. #1031\n\t\t\tif ( !isEqualWith( viewChildren, newViewChildren, sameNodes ) ) {\n\t\t\t\tthis.renderer.markToSync( 'children', viewElement );\n\n\t\t\t\tviewMutations.push( {\n\t\t\t\t\ttype: 'children',\n\t\t\t\t\toldChildren: viewChildren,\n\t\t\t\t\tnewChildren: newViewChildren,\n\t\t\t\t\tnode: viewElement\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\n\t\t// Retrieve `domSelection` using `ownerDocument` of one of mutated nodes.\n\t\t// There should not be simultaneous mutation in multiple documents, so it's fine.\n\t\tconst domSelection = domMutations[ 0 ].target.ownerDocument.getSelection();\n\n\t\tlet viewSelection = null;\n\n\t\tif ( domSelection && domSelection.anchorNode ) {\n\t\t\t// If `domSelection` is inside a dom node that is already bound to a view node from view tree, get\n\t\t\t// corresponding selection in the view and pass it together with `viewMutations`. The `viewSelection` may\n\t\t\t// be used by features handling mutations.\n\t\t\t// Only one range is supported.\n\n\t\t\tconst viewSelectionAnchor = domConverter.domPositionToView( domSelection.anchorNode, domSelection.anchorOffset );\n\t\t\tconst viewSelectionFocus = domConverter.domPositionToView( domSelection.focusNode, domSelection.focusOffset );\n\n\t\t\t// Anchor and focus has to be properly mapped to view.\n\t\t\tif ( viewSelectionAnchor && viewSelectionFocus ) {\n\t\t\t\tviewSelection = new ViewSelection( viewSelectionAnchor );\n\t\t\t\tviewSelection.setFocus( viewSelectionFocus );\n\t\t\t}\n\t\t}\n\n\t\t// In case only non-relevant mutations were recorded it skips the event and force render (#5600).\n\t\tif ( viewMutations.length ) {\n\t\t\tthis.document.fire( 'mutations', viewMutations, viewSelection );\n\n\t\t\t// If nothing changes on `mutations` event, at this point we have \"dirty DOM\" (changed) and de-synched\n\t\t\t// view (which has not been changed). In order to \"reset DOM\" we render the view again.\n\t\t\tthis.view.forceRender();\n\t\t}\n\n\t\tfunction sameNodes( child1, child2 ) {\n\t\t\t// First level of comparison (array of children vs array of children) – use the Lodash's default behavior.\n\t\t\tif ( Array.isArray( child1 ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Elements.\n\t\t\tif ( child1 === child2 ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// Texts.\n\t\t\telse if ( child1.is( '$text' ) && child2.is( '$text' ) ) {\n\t\t\t\treturn child1.data === child2.data;\n\t\t\t}\n\n\t\t\t// Not matching types.\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Checks if mutation was generated by the browser inserting bogus br on the end of the block element.\n\t * Such mutations are generated while pressing space or performing native spellchecker correction\n\t * on the end of the block element in Firefox browser.\n\t *\n\t * @private\n\t * @param {Object} mutation Native mutation object.\n\t * @returns {Boolean}\n\t */\n\t_isBogusBrMutation( mutation ) {\n\t\tlet addedNode = null;\n\n\t\t// Check if mutation added only one node on the end of its parent.\n\t\tif ( mutation.nextSibling === null && mutation.removedNodes.length === 0 && mutation.addedNodes.length == 1 ) {\n\t\t\taddedNode = this.domConverter.domToView( mutation.addedNodes[ 0 ], {\n\t\t\t\twithChildren: false\n\t\t\t} );\n\t\t}\n\n\t\treturn addedNode && addedNode.is( 'element', 'br' );\n\t}\n}\n\n/**\n * Fired when mutation occurred. If tree view is not changed on this event, DOM will be reverted to the state before\n * mutation, so all changes which should be applied, should be handled on this event.\n *\n * Introduced by {@link module:engine/view/observer/mutationobserver~MutationObserver}.\n *\n * Note that because {@link module:engine/view/observer/mutationobserver~MutationObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/mutationobserver~MutationObserver\n * @event module:engine/view/document~Document#event:mutations\n * @param {Array.<module:engine/view/observer/mutationobserver~MutatedText|module:engine/view/observer/mutationobserver~MutatedChildren>}\n * viewMutations Array of mutations.\n * For mutated texts it will be {@link module:engine/view/observer/mutationobserver~MutatedText} and for mutated elements it will be\n * {@link module:engine/view/observer/mutationobserver~MutatedChildren}. You can recognize the type based on the `type` property.\n * @param {module:engine/view/selection~Selection|null} viewSelection View selection that is a result of converting DOM selection to view.\n * Keep in\n * mind that the DOM selection is already \"updated\", meaning that it already acknowledges changes done in mutation.\n */\n\n/**\n * Mutation item for text.\n *\n * @see module:engine/view/document~Document#event:mutations\n * @see module:engine/view/observer/mutationobserver~MutatedChildren\n *\n * @typedef {Object} module:engine/view/observer/mutationobserver~MutatedText\n *\n * @property {String} type For text mutations it is always 'text'.\n * @property {module:engine/view/text~Text} node Mutated text node.\n * @property {String} oldText Old text.\n * @property {String} newText New text.\n */\n\n/**\n * Mutation item for child nodes.\n *\n * @see module:engine/view/document~Document#event:mutations\n * @see module:engine/view/observer/mutationobserver~MutatedText\n *\n * @typedef {Object} module:engine/view/observer/mutationobserver~MutatedChildren\n *\n * @property {String} type For child nodes mutations it is always 'children'.\n * @property {module:engine/view/element~Element} node Parent of the mutated children.\n * @property {Array.<module:engine/view/node~Node>} oldChildren Old child nodes.\n * @property {Array.<module:engine/view/node~Node>} newChildren New child nodes.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/observer/domeventdata\n */\n\nimport { extend } from 'lodash-es';\n\n/**\n * Information about a DOM event in context of the {@link module:engine/view/document~Document}.\n * It wraps the native event, which usually should not be used as the wrapper contains\n * additional data (like key code for keyboard events).\n */\nexport default class DomEventData {\n\t/**\n\t * @param {module:engine/view/view~View} view The instance of the view controller.\n\t * @param {Event} domEvent The DOM event.\n\t * @param {Object} [additionalData] Additional properties that the instance should contain.\n\t */\n\tconstructor( view, domEvent, additionalData ) {\n\t\t/**\n\t\t * Instance of the view controller.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/view~View} module:engine/view/observer/observer~Observer.DomEvent#view\n\t\t */\n\t\tthis.view = view;\n\n\t\t/**\n\t\t * The instance of the document.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/document~Document} module:engine/view/observer/observer~Observer.DomEvent#document\n\t\t */\n\t\tthis.document = view.document;\n\n\t\t/**\n\t\t * The DOM event.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Event} module:engine/view/observer/observer~Observer.DomEvent#domEvent\n\t\t */\n\t\tthis.domEvent = domEvent;\n\n\t\t/**\n\t\t * The DOM target.\n\t\t *\n\t\t * @readonly\n\t\t * @member {HTMLElement} module:engine/view/observer/observer~Observer.DomEvent#target\n\t\t */\n\t\tthis.domTarget = domEvent.target;\n\n\t\textend( this, additionalData );\n\t}\n\n\t/**\n\t * The tree view element representing the target.\n\t *\n\t * @readonly\n\t * @type module:engine/view/element~Element\n\t */\n\tget target() {\n\t\treturn this.view.domConverter.mapDomToView( this.domTarget );\n\t}\n\n\t/**\n\t * Prevents the native's event default action.\n\t */\n\tpreventDefault() {\n\t\tthis.domEvent.preventDefault();\n\t}\n\n\t/**\n\t * Stops native event propagation.\n\t */\n\tstopPropagation() {\n\t\tthis.domEvent.stopPropagation();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/observer/domeventobserver\n */\n\nimport Observer from './observer';\nimport DomEventData from './domeventdata';\n\n/**\n * Base class for DOM event observers. This class handles\n * {@link module:engine/view/observer/observer~Observer#observe adding} listeners to DOM elements,\n * {@link module:engine/view/observer/observer~Observer#disable disabling} and\n * {@link module:engine/view/observer/observer~Observer#enable re-enabling} events.\n * Child class needs to define\n * {@link module:engine/view/observer/domeventobserver~DomEventObserver#domEventType DOM event type} and\n * {@link module:engine/view/observer/domeventobserver~DomEventObserver#onDomEvent callback}.\n *\n * For instance:\n *\n *\t\tclass ClickObserver extends DomEventObserver {\n *\t\t\t// It can also be defined as a normal property in the constructor.\n *\t\t\tget domEventType() {\n *\t\t\t\treturn 'click';\n *\t\t\t}\n *\n *\t\t\tonDomEvent( domEvent ) {\n *\t\t\t\tthis.fire( 'click', domEvent );\n *\t\t\t}\n *\t\t}\n *\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class DomEventObserver extends Observer {\n\t/**\n\t * Type of the DOM event the observer should listen to. Array of types can be defined\n\t * if the observer should listen to multiple DOM events.\n\t *\n\t * @readonly\n\t * @member {String|Array.<String>} #domEventType\n\t */\n\n\t/**\n\t * Callback which should be called when the DOM event occurred. Note that the callback will not be called if\n\t * observer {@link #isEnabled is not enabled}.\n\t *\n\t * @see #domEventType\n\t * @abstract\n\t * @method #onDomEvent\n\t */\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\t/**\n\t\t * If set to `true` DOM events will be listened on the capturing phase.\n\t\t * Default value is `false`.\n\t\t *\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis.useCapture = false;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve( domElement ) {\n\t\tconst types = typeof this.domEventType == 'string' ? [ this.domEventType ] : this.domEventType;\n\n\t\ttypes.forEach( type => {\n\t\t\tthis.listenTo( domElement, type, ( eventInfo, domEvent ) => {\n\t\t\t\tif ( this.isEnabled && !this.checkShouldIgnoreEventFromTarget( domEvent.target ) ) {\n\t\t\t\t\tthis.onDomEvent( domEvent );\n\t\t\t\t}\n\t\t\t}, { useCapture: this.useCapture } );\n\t\t} );\n\t}\n\n\t/**\n\t * Calls `Document#fire()` if observer {@link #isEnabled is enabled}.\n\t *\n\t * @see module:utils/emittermixin~EmitterMixin#fire\n\t * @param {String} eventType The event type (name).\n\t * @param {Event} domEvent The DOM event.\n\t * @param {Object} [additionalData] The additional data which should extend the\n\t * {@link module:engine/view/observer/domeventdata~DomEventData event data} object.\n\t */\n\tfire( eventType, domEvent, additionalData ) {\n\t\tif ( this.isEnabled ) {\n\t\t\tthis.document.fire( eventType, new DomEventData( this.view, domEvent, additionalData ) );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/observer/keyobserver\n */\n\nimport DomEventObserver from './domeventobserver';\nimport { getCode } from '@ckeditor/ckeditor5-utils/src/keyboard';\n\n/**\n * Observer for events connected with pressing keyboard keys.\n *\n * Note that this observer is attached by the {@link module:engine/view/view~View} and is available by default.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class KeyObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = [ 'keydown', 'keyup' ];\n\t}\n\n\tonDomEvent( domEvt ) {\n\t\tthis.fire( domEvt.type, domEvt, {\n\t\t\tkeyCode: domEvt.keyCode,\n\n\t\t\taltKey: domEvt.altKey,\n\t\t\tctrlKey: domEvt.ctrlKey || domEvt.metaKey,\n\t\t\tshiftKey: domEvt.shiftKey,\n\n\t\t\tget keystroke() {\n\t\t\t\treturn getCode( this );\n\t\t\t}\n\t\t} );\n\t}\n}\n\n/**\n * Fired when a key has been pressed.\n *\n * Introduced by {@link module:engine/view/observer/keyobserver~KeyObserver}.\n *\n * Note that because {@link module:engine/view/observer/keyobserver~KeyObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/keyobserver~KeyObserver\n * @event module:engine/view/document~Document#event:keydown\n * @param {module:engine/view/observer/keyobserver~KeyEventData} keyEventData\n */\n\n/**\n * Fired when a key has been released.\n *\n * Introduced by {@link module:engine/view/observer/keyobserver~KeyObserver}.\n *\n * Note that because {@link module:engine/view/observer/keyobserver~KeyObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/keyobserver~KeyObserver\n * @event module:engine/view/document~Document#event:keyup\n * @param {module:engine/view/observer/keyobserver~KeyEventData} keyEventData\n */\n\n/**\n * The value of both events - {@link module:engine/view/document~Document#event:keydown} and\n * {@link module:engine/view/document~Document#event:keyup}.\n *\n * @class module:engine/view/observer/keyobserver~KeyEventData\n * @extends module:engine/view/observer/domeventdata~DomEventData\n * @implements module:utils/keyboard~KeystrokeInfo\n */\n\n/**\n * Code of the whole keystroke. See {@link module:utils/keyboard~getCode}.\n *\n * @readonly\n * @member {Number} module:engine/view/observer/keyobserver~KeyEventData#keystroke\n */\n","import root from './_root.js';\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 */\nvar now = function() {\n  return root.Date.now();\n};\n\nexport default now;\n","import isObject from './isObject.js';\nimport isSymbol from './isSymbol.js';\n\n/** Used as references for various `Number` constants. */\nvar NAN = 0 / 0;\n\n/** Used to match leading and trailing whitespace. */\nvar reTrim = /^\\s+|\\s+$/g;\n\n/** Used to detect bad signed hexadecimal string values. */\nvar reIsBadHex = /^[-+]0x[0-9a-f]+$/i;\n\n/** Used to detect binary string values. */\nvar reIsBinary = /^0b[01]+$/i;\n\n/** Used to detect octal string values. */\nvar reIsOctal = /^0o[0-7]+$/i;\n\n/** Built-in method references without a dependency on `root`. */\nvar 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 */\nfunction toNumber(value) {\n  if (typeof value == 'number') {\n    return value;\n  }\n  if (isSymbol(value)) {\n    return NAN;\n  }\n  if (isObject(value)) {\n    var other = typeof value.valueOf == 'function' ? value.valueOf() : value;\n    value = isObject(other) ? (other + '') : other;\n  }\n  if (typeof value != 'string') {\n    return value === 0 ? value : +value;\n  }\n  value = value.replace(reTrim, '');\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\nexport default toNumber;\n","import isObject from './isObject.js';\nimport now from './now.js';\nimport toNumber from './toNumber.js';\n\n/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar 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 */\nfunction 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);\n  }\n  wait = toNumber(wait) || 0;\n  if (isObject(options)) {\n    leading = !!options.leading;\n    maxing = 'maxWait' in options;\n    maxWait = maxing ? nativeMax(toNumber(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();\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());\n  }\n\n  function debounced() {\n    var time = now(),\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\nexport default debounce;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/observer/fakeselectionobserver\n */\n\nimport Observer from './observer';\nimport ViewSelection from '../selection';\nimport { keyCodes, isArrowKeyCode } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport { debounce } from 'lodash-es';\n\n/**\n * Fake selection observer class. If view selection is fake it is placed in dummy DOM container. This observer listens\n * on {@link module:engine/view/document~Document#event:keydown keydown} events and handles moving fake view selection to the correct place\n * if arrow keys are pressed.\n * Fires {@link module:engine/view/document~Document#event:selectionChange selectionChange event} simulating natural behaviour of\n * {@link module:engine/view/observer/selectionobserver~SelectionObserver SelectionObserver}.\n *\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class FakeSelectionObserver extends Observer {\n\t/**\n\t * Creates new FakeSelectionObserver instance.\n\t *\n\t * @param {module:engine/view/view~View} view\n\t */\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\t/**\n\t\t * Fires debounced event `selectionChangeDone`. It uses `lodash#debounce` method to delay function call.\n\t\t *\n\t\t * @private\n\t\t * @param {Object} data Selection change data.\n\t\t * @method #_fireSelectionChangeDoneDebounced\n\t\t */\n\t\tthis._fireSelectionChangeDoneDebounced = debounce( data => this.document.fire( 'selectionChangeDone', data ), 200 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve() {\n\t\tconst document = this.document;\n\n\t\tdocument.on( 'keydown', ( eventInfo, data ) => {\n\t\t\tconst selection = document.selection;\n\n\t\t\tif ( selection.isFake && isArrowKeyCode( data.keyCode ) && this.isEnabled ) {\n\t\t\t\t// Prevents default key down handling - no selection change will occur.\n\t\t\t\tdata.preventDefault();\n\n\t\t\t\tthis._handleSelectionMove( data.keyCode );\n\t\t\t}\n\t\t}, { priority: 'lowest' } );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tthis._fireSelectionChangeDoneDebounced.cancel();\n\t}\n\n\t/**\n\t * Handles collapsing view selection according to given key code. If left or up key is provided - new selection will be\n\t * collapsed to left. If right or down key is pressed - new selection will be collapsed to right.\n\t *\n\t * This method fires {@link module:engine/view/document~Document#event:selectionChange} and\n\t * {@link module:engine/view/document~Document#event:selectionChangeDone} events imitating behaviour of\n\t * {@link module:engine/view/observer/selectionobserver~SelectionObserver}.\n\t *\n\t * @private\n\t * @param {Number} keyCode\n\t * @fires module:engine/view/document~Document#event:selectionChange\n\t * @fires module:engine/view/document~Document#event:selectionChangeDone\n\t */\n\t_handleSelectionMove( keyCode ) {\n\t\tconst selection = this.document.selection;\n\t\tconst newSelection = new ViewSelection( selection.getRanges(), { backward: selection.isBackward, fake: false } );\n\n\t\t// Left or up arrow pressed - move selection to start.\n\t\tif ( keyCode == keyCodes.arrowleft || keyCode == keyCodes.arrowup ) {\n\t\t\tnewSelection.setTo( newSelection.getFirstPosition() );\n\t\t}\n\n\t\t// Right or down arrow pressed - move selection to end.\n\t\tif ( keyCode == keyCodes.arrowright || keyCode == keyCodes.arrowdown ) {\n\t\t\tnewSelection.setTo( newSelection.getLastPosition() );\n\t\t}\n\n\t\tconst data = {\n\t\t\toldSelection: selection,\n\t\t\tnewSelection,\n\t\t\tdomSelection: null\n\t\t};\n\n\t\t// Fire dummy selection change event.\n\t\tthis.document.fire( 'selectionChange', data );\n\n\t\t// Call` #_fireSelectionChangeDoneDebounced` every time when `selectionChange` event is fired.\n\t\t// This function is debounced what means that `selectionChangeDone` event will be fired only when\n\t\t// defined int the function time will elapse since the last time the function was called.\n\t\t// So `selectionChangeDone` will be fired when selection will stop changing.\n\t\tthis._fireSelectionChangeDoneDebounced( data );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/observer/selectionobserver\n */\n\n/* global setInterval, clearInterval */\n\nimport Observer from './observer';\nimport MutationObserver from './mutationobserver';\nimport { debounce } from 'lodash-es';\n\n/**\n * Selection observer class observes selection changes in the document. If a selection changes on the document this\n * observer checks if there are any mutations and if the DOM selection is different from the\n * {@link module:engine/view/document~Document#selection view selection}. The selection observer fires\n * {@link module:engine/view/document~Document#event:selectionChange} event only if a selection change was the only change in the document\n * and the DOM selection is different then the view selection.\n *\n * Note that this observer is attached by the {@link module:engine/view/view~View} and is available by default.\n *\n * @see module:engine/view/observer/mutationobserver~MutationObserver\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class SelectionObserver extends Observer {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\t/**\n\t\t * Instance of the mutation observer. Selection observer calls\n\t\t * {@link module:engine/view/observer/mutationobserver~MutationObserver#flush} to ensure that the mutations will be handled\n\t\t * before the {@link module:engine/view/document~Document#event:selectionChange} event is fired.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/observer/mutationobserver~MutationObserver}\n\t\t * module:engine/view/observer/selectionobserver~SelectionObserver#mutationObserver\n\t\t */\n\t\tthis.mutationObserver = view.getObserver( MutationObserver );\n\n\t\t/**\n\t\t * Reference to the view {@link module:engine/view/documentselection~DocumentSelection} object used to compare\n\t\t * new selection with it.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/documentselection~DocumentSelection}\n\t\t * module:engine/view/observer/selectionobserver~SelectionObserver#selection\n\t\t */\n\t\tthis.selection = this.document.selection;\n\n\t\t/* eslint-disable max-len */\n\t\t/**\n\t\t * Reference to the {@link module:engine/view/view~View#domConverter}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/domconverter~DomConverter} module:engine/view/observer/selectionobserver~SelectionObserver#domConverter\n\t\t */\n\t\t/* eslint-enable max-len */\n\t\tthis.domConverter = view.domConverter;\n\n\t\t/**\n\t\t * A set of documents which have added `selectionchange` listener to avoid adding a listener twice to the same\n\t\t * document.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakSet.<Document>} module:engine/view/observer/selectionobserver~SelectionObserver#_documents\n\t\t */\n\t\tthis._documents = new WeakSet();\n\n\t\t/**\n\t\t * Fires debounced event `selectionChangeDone`. It uses `lodash#debounce` method to delay function call.\n\t\t *\n\t\t * @private\n\t\t * @param {Object} data Selection change data.\n\t\t * @method #_fireSelectionChangeDoneDebounced\n\t\t */\n\t\tthis._fireSelectionChangeDoneDebounced = debounce( data => this.document.fire( 'selectionChangeDone', data ), 200 );\n\n\t\tthis._clearInfiniteLoopInterval = setInterval( () => this._clearInfiniteLoop(), 1000 );\n\n\t\t/**\n\t\t * Private property to check if the code does not enter infinite loop.\n\t\t *\n\t\t * @private\n\t\t * @member {Number} module:engine/view/observer/selectionobserver~SelectionObserver#_loopbackCounter\n\t\t */\n\t\tthis._loopbackCounter = 0;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve( domElement ) {\n\t\tconst domDocument = domElement.ownerDocument;\n\n\t\t// Add listener once per each document.\n\t\tif ( this._documents.has( domDocument ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.listenTo( domDocument, 'selectionchange', ( evt, domEvent ) => {\n\t\t\tthis._handleSelectionChange( domEvent, domDocument );\n\t\t} );\n\n\t\tthis._documents.add( domDocument );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tclearInterval( this._clearInfiniteLoopInterval );\n\t\tthis._fireSelectionChangeDoneDebounced.cancel();\n\t}\n\n\t/**\n\t * Selection change listener. {@link module:engine/view/observer/mutationobserver~MutationObserver#flush Flush} mutations, check if\n\t * a selection changes and fires {@link module:engine/view/document~Document#event:selectionChange} event on every change\n\t * and {@link module:engine/view/document~Document#event:selectionChangeDone} when a selection stop changing.\n\t *\n\t * @private\n\t * @param {Event} domEvent DOM event.\n\t * @param {Document} domDocument DOM document.\n\t */\n\t_handleSelectionChange( domEvent, domDocument ) {\n\t\tif ( !this.isEnabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst domSelection = domDocument.defaultView.getSelection();\n\n\t\tif ( this.checkShouldIgnoreEventFromTarget( domSelection.anchorNode ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Ensure the mutation event will be before selection event on all browsers.\n\t\tthis.mutationObserver.flush();\n\n\t\t// If there were mutations then the view will be re-rendered by the mutation observer and the selection\n\t\t// will be updated, so the selections will equal and the event will not be fired, as expected.\n\t\tconst newViewSelection = this.domConverter.domSelectionToView( domSelection );\n\n\t\t// Do not convert selection change if the new view selection has no ranges in it.\n\t\t//\n\t\t// It means that the DOM selection is in some way incorrect. Ranges that were in the DOM selection could not be\n\t\t// converted to the view. This happens when the DOM selection was moved outside of the editable element.\n\t\tif ( newViewSelection.rangeCount == 0 ) {\n\t\t\tthis.view.hasDomSelection = false;\n\n\t\t\treturn;\n\t\t}\n\n\t\tthis.view.hasDomSelection = true;\n\n\t\tif ( this.selection.isEqual( newViewSelection ) && this.domConverter.isDomSelectionCorrect( domSelection ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Ensure we are not in the infinite loop (#400).\n\t\t// This counter is reset each second. 60 selection changes in 1 second is enough high number\n\t\t// to be very difficult (impossible) to achieve using just keyboard keys (during normal editor use).\n\t\tif ( ++this._loopbackCounter > 60 ) {\n\t\t\t// Selection change observer detected an infinite rendering loop.\n\t\t\t// Most probably you try to put the selection in the position which is not allowed\n\t\t\t// by the browser and browser fixes it automatically what causes `selectionchange` event on\n\t\t\t// which a loopback through a model tries to re-render the wrong selection and again.\n\t\t\t//\n\t\t\t// @if CK_DEBUG // console.warn( 'Selection change observer detected an infinite rendering loop.' );\n\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this.selection.isSimilar( newViewSelection ) ) {\n\t\t\t// If selection was equal and we are at this point of algorithm, it means that it was incorrect.\n\t\t\t// Just re-render it, no need to fire any events, etc.\n\t\t\tthis.view.forceRender();\n\t\t} else {\n\t\t\tconst data = {\n\t\t\t\toldSelection: this.selection,\n\t\t\t\tnewSelection: newViewSelection,\n\t\t\t\tdomSelection\n\t\t\t};\n\n\t\t\t// Prepare data for new selection and fire appropriate events.\n\t\t\tthis.document.fire( 'selectionChange', data );\n\n\t\t\t// Call `#_fireSelectionChangeDoneDebounced` every time when `selectionChange` event is fired.\n\t\t\t// This function is debounced what means that `selectionChangeDone` event will be fired only when\n\t\t\t// defined int the function time will elapse since the last time the function was called.\n\t\t\t// So `selectionChangeDone` will be fired when selection will stop changing.\n\t\t\tthis._fireSelectionChangeDoneDebounced( data );\n\t\t}\n\t}\n\n\t/**\n\t * Clears `SelectionObserver` internal properties connected with preventing infinite loop.\n\t *\n\t * @protected\n\t */\n\t_clearInfiniteLoop() {\n\t\tthis._loopbackCounter = 0;\n\t}\n}\n\n/**\n * Fired when a selection has changed. This event is fired only when the selection change was the only change that happened\n * in the document, and the old selection is different then the new selection.\n *\n * Introduced by {@link module:engine/view/observer/selectionobserver~SelectionObserver}.\n *\n * Note that because {@link module:engine/view/observer/selectionobserver~SelectionObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/selectionobserver~SelectionObserver\n * @event module:engine/view/document~Document#event:selectionChange\n * @param {Object} data\n * @param {module:engine/view/documentselection~DocumentSelection} data.oldSelection Old View selection which is\n * {@link module:engine/view/document~Document#selection}.\n * @param {module:engine/view/selection~Selection} data.newSelection New View selection which is converted DOM selection.\n * @param {Selection} data.domSelection Native DOM selection.\n */\n\n/**\n * Fired when selection stops changing.\n *\n * Introduced by {@link module:engine/view/observer/selectionobserver~SelectionObserver}.\n *\n * Note that because {@link module:engine/view/observer/selectionobserver~SelectionObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/selectionobserver~SelectionObserver\n * @event module:engine/view/document~Document#event:selectionChangeDone\n * @param {Object} data\n * @param {module:engine/view/documentselection~DocumentSelection} data.oldSelection Old View selection which is\n * {@link module:engine/view/document~Document#selection}.\n * @param {module:engine/view/selection~Selection} data.newSelection New View selection which is converted DOM selection.\n * @param {Selection} data.domSelection Native DOM selection.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/observer/focusobserver\n */\n\n/* globals setTimeout, clearTimeout */\n\nimport DomEventObserver from './domeventobserver';\n\n/**\n * {@link module:engine/view/document~Document#event:focus Focus}\n * and {@link module:engine/view/document~Document#event:blur blur} events observer.\n * Focus observer handle also {@link module:engine/view/rooteditableelement~RootEditableElement#isFocused isFocused} property of the\n * {@link module:engine/view/rooteditableelement~RootEditableElement root elements}.\n *\n * Note that this observer is attached by the {@link module:engine/view/view~View} and is available by default.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class FocusObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = [ 'focus', 'blur' ];\n\t\tthis.useCapture = true;\n\t\tconst document = this.document;\n\n\t\tdocument.on( 'focus', () => {\n\t\t\tdocument.isFocused = true;\n\n\t\t\t// Unfortunately native `selectionchange` event is fired asynchronously.\n\t\t\t// We need to wait until `SelectionObserver` handle the event and then render. Otherwise rendering will\n\t\t\t// overwrite new DOM selection with selection from the view.\n\t\t\t// See https://github.com/ckeditor/ckeditor5-engine/issues/795 for more details.\n\t\t\t// Long timeout is needed to solve #676 and https://github.com/ckeditor/ckeditor5-engine/issues/1157 issues.\n\t\t\tthis._renderTimeoutId = setTimeout( () => view.forceRender(), 50 );\n\t\t} );\n\n\t\tdocument.on( 'blur', ( evt, data ) => {\n\t\t\tconst selectedEditable = document.selection.editableElement;\n\n\t\t\tif ( selectedEditable === null || selectedEditable === data.target ) {\n\t\t\t\tdocument.isFocused = false;\n\n\t\t\t\t// Re-render the document to update view elements.\n\t\t\t\tview.forceRender();\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * Identifier of the timeout currently used by focus listener to delay rendering execution.\n\t\t *\n\t\t * @private\n\t\t * @member {Number} #_renderTimeoutId\n\t\t */\n\t}\n\n\tonDomEvent( domEvent ) {\n\t\tthis.fire( domEvent.type, domEvent );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tif ( this._renderTimeoutId ) {\n\t\t\tclearTimeout( this._renderTimeoutId );\n\t\t}\n\n\t\tsuper.destroy();\n\t}\n}\n\n/**\n * Fired when one of the editables gets focus.\n *\n * Introduced by {@link module:engine/view/observer/focusobserver~FocusObserver}.\n *\n * Note that because {@link module:engine/view/observer/focusobserver~FocusObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/focusobserver~FocusObserver\n * @event module:engine/view/document~Document#event:focus\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n\n/**\n * Fired when one of the editables loses focus.\n *\n * Introduced by {@link module:engine/view/observer/focusobserver~FocusObserver}.\n *\n * Note that because {@link module:engine/view/observer/focusobserver~FocusObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/focusobserver~FocusObserver\n * @event module:engine/view/document~Document#event:blur\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/observer/compositionobserver\n */\n\nimport DomEventObserver from './domeventobserver';\n\n/**\n * {@link module:engine/view/document~Document#event:compositionstart Compositionstart},\n * {@link module:engine/view/document~Document#event:compositionupdate compositionupdate} and\n * {@link module:engine/view/document~Document#event:compositionend compositionend} events observer.\n *\n * Note that this observer is attached by the {@link module:engine/view/view~View} and is available by default.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class CompositionObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = [ 'compositionstart', 'compositionupdate', 'compositionend' ];\n\t\tconst document = this.document;\n\n\t\tdocument.on( 'compositionstart', () => {\n\t\t\tdocument.isComposing = true;\n\t\t} );\n\n\t\tdocument.on( 'compositionend', () => {\n\t\t\tdocument.isComposing = false;\n\t\t} );\n\t}\n\n\tonDomEvent( domEvent ) {\n\t\tthis.fire( domEvent.type, domEvent );\n\t}\n}\n\n/**\n * Fired when composition starts inside one of the editables.\n *\n * Introduced by {@link module:engine/view/observer/compositionobserver~CompositionObserver}.\n *\n * Note that because {@link module:engine/view/observer/compositionobserver~CompositionObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/compositionobserver~CompositionObserver\n * @event module:engine/view/document~Document#event:compositionstart\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n\n/**\n * Fired when composition is updated inside one of the editables.\n *\n * Introduced by {@link module:engine/view/observer/compositionobserver~CompositionObserver}.\n *\n * Note that because {@link module:engine/view/observer/compositionobserver~CompositionObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/compositionobserver~CompositionObserver\n * @event module:engine/view/document~Document#event:compositionupdate\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n\n/**\n * Fired when composition ends inside one of the editables.\n *\n * Introduced by {@link module:engine/view/observer/compositionobserver~CompositionObserver}.\n *\n * Note that because {@link module:engine/view/observer/compositionobserver~CompositionObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/compositionobserver~CompositionObserver\n * @event module:engine/view/document~Document#event:compositionend\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module engine/view/observer/inputobserver\n */\n\nimport DomEventObserver from './domeventobserver';\n\n/**\n * Observer for events connected with data input.\n *\n * Note that this observer is attached by the {@link module:engine/view/view~View} and is available by default.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class InputObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = [ 'beforeinput' ];\n\t}\n\n\tonDomEvent( domEvent ) {\n\t\tthis.fire( domEvent.type, domEvent );\n\t}\n}\n\n/**\n * Fired before browser inputs (or deletes) some data.\n *\n * This event is available only on browsers which support DOM `beforeinput` event.\n *\n * Introduced by {@link module:engine/view/observer/inputobserver~InputObserver}.\n *\n * Note that because {@link module:engine/view/observer/inputobserver~InputObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/inputobserver~InputObserver\n * @event module:engine/view/document~Document#event:beforeinput\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/isrange\n */\n\n/**\n * Checks if the object is a native DOM Range.\n *\n * @param {*} obj\n * @returns {Boolean}\n */\nexport default function isRange( obj ) {\n\treturn Object.prototype.toString.apply( obj ) == '[object Range]';\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/getborderwidths\n */\n\n/**\n * Returns an object containing CSS border widths of a specified HTML element.\n *\n * @param {HTMLElement} element An element which has CSS borders.\n * @returns {Object} An object containing `top`, `left`, `right` and `bottom` properties\n * with numerical values of the `border-[top,left,right,bottom]-width` CSS styles.\n */\nexport default function getBorderWidths( element ) {\n\t// Call getComputedStyle on the window the element document belongs to.\n\tconst style = element.ownerDocument.defaultView.getComputedStyle( element );\n\n\treturn {\n\t\ttop: parseInt( style.borderTopWidth, 10 ),\n\t\tright: parseInt( style.borderRightWidth, 10 ),\n\t\tbottom: parseInt( style.borderBottomWidth, 10 ),\n\t\tleft: parseInt( style.borderLeftWidth, 10 )\n\t};\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/rect\n */\n\nimport isRange from './isrange';\nimport isWindow from './iswindow';\nimport getBorderWidths from './getborderwidths';\nimport isText from './istext';\nimport { isElement } from 'lodash-es';\n\nconst rectProperties = [ 'top', 'right', 'bottom', 'left', 'width', 'height' ];\n\n/**\n * A helper class representing a `ClientRect` object, e.g. value returned by\n * the native `object.getBoundingClientRect()` method. Provides a set of methods\n * to manipulate the rect and compare it against other rect instances.\n */\nexport default class Rect {\n\t/**\n\t * Creates an instance of rect.\n\t *\n\t *\t\t// Rect of an HTMLElement.\n\t *\t\tconst rectA = new Rect( document.body );\n\t *\n\t *\t\t// Rect of a DOM Range.\n\t *\t\tconst rectB = new Rect( document.getSelection().getRangeAt( 0 ) );\n\t *\n\t *\t\t// Rect of a window (web browser viewport).\n\t *\t\tconst rectC = new Rect( window );\n\t *\n\t *\t\t// Rect out of an object.\n\t *\t\tconst rectD = new Rect( { top: 0, right: 10, bottom: 10, left: 0, width: 10, height: 10 } );\n\t *\n\t *\t\t// Rect out of another Rect instance.\n\t *\t\tconst rectE = new Rect( rectD );\n\t *\n\t *\t\t// Rect out of a ClientRect.\n\t *\t\tconst rectF = new Rect( document.body.getClientRects().item( 0 ) );\n\t *\n\t * **Note**: By default a rect of an HTML element includes its CSS borders and scrollbars (if any)\n\t * ant the rect of a `window` includes scrollbars too. Use {@link #excludeScrollbarsAndBorders}\n\t * to get the inner part of the rect.\n\t *\n\t * @param {HTMLElement|Range|Window|ClientRect|module:utils/dom/rect~Rect|Object} source A source object to create the rect.\n\t */\n\tconstructor( source ) {\n\t\tconst isSourceRange = isRange( source );\n\n\t\t/**\n\t\t * The object this rect is for.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @member {HTMLElement|Range|ClientRect|module:utils/dom/rect~Rect|Object} #_source\n\t\t */\n\t\tObject.defineProperty( this, '_source', {\n\t\t\t// If the source is a Rect instance, copy it's #_source.\n\t\t\tvalue: source._source || source,\n\t\t\twritable: true,\n\t\t\tenumerable: false\n\t\t} );\n\n\t\tif ( isElement( source ) || isSourceRange ) {\n\t\t\t// The `Rect` class depends on `getBoundingClientRect` and `getClientRects` DOM methods. If the source\n\t\t\t// of a rect in an HTML element or a DOM range but it does not belong to any rendered DOM tree, these methods\n\t\t\t// will fail to obtain the geometry and the rect instance makes little sense to the features using it.\n\t\t\t// To get rid of this warning make sure the source passed to the constructor is a descendant of `window.document.body`.\n\t\t\t// @if CK_DEBUG // const sourceNode = isSourceRange ? source.startContainer : source;\n\t\t\t// @if CK_DEBUG // if ( !sourceNode.ownerDocument || !sourceNode.ownerDocument.body.contains( sourceNode ) ) {\n\t\t\t// @if CK_DEBUG // \tconsole.warn(\n\t\t\t// @if CK_DEBUG // \t\t'rect-source-not-in-dom: The source of this rect does not belong to any rendered DOM tree.',\n\t\t\t// @if CK_DEBUG // \t\t{ source } );\n\t\t\t// @if CK_DEBUG // }\n\n\t\t\tif ( isSourceRange ) {\n\t\t\t\tconst rangeRects = Rect.getDomRangeRects( source );\n\t\t\t\tcopyRectProperties( this, Rect.getBoundingRect( rangeRects ) );\n\t\t\t} else {\n\t\t\t\tcopyRectProperties( this, source.getBoundingClientRect() );\n\t\t\t}\n\t\t} else if ( isWindow( source ) ) {\n\t\t\tconst { innerWidth, innerHeight } = source;\n\n\t\t\tcopyRectProperties( this, {\n\t\t\t\ttop: 0,\n\t\t\t\tright: innerWidth,\n\t\t\t\tbottom: innerHeight,\n\t\t\t\tleft: 0,\n\t\t\t\twidth: innerWidth,\n\t\t\t\theight: innerHeight\n\t\t\t} );\n\t\t} else {\n\t\t\tcopyRectProperties( this, source );\n\t\t}\n\n\t\t/**\n\t\t * The \"top\" value of the rect.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #top\n\t\t */\n\n\t\t/**\n\t\t * The \"right\" value of the rect.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #right\n\t\t */\n\n\t\t/**\n\t\t * The \"bottom\" value of the rect.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #bottom\n\t\t */\n\n\t\t/**\n\t\t * The \"left\" value of the rect.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #left\n\t\t */\n\n\t\t/**\n\t\t * The \"width\" value of the rect.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #width\n\t\t */\n\n\t\t/**\n\t\t * The \"height\" value of the rect.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #height\n\t\t */\n\t}\n\n\t/**\n\t * Returns a clone of the rect.\n\t *\n\t * @returns {module:utils/dom/rect~Rect} A cloned rect.\n\t */\n\tclone() {\n\t\treturn new Rect( this );\n\t}\n\n\t/**\n\t * Moves the rect so that its upper–left corner lands in desired `[ x, y ]` location.\n\t *\n\t * @param {Number} x Desired horizontal location.\n\t * @param {Number} y Desired vertical location.\n\t * @returns {module:utils/dom/rect~Rect} A rect which has been moved.\n\t */\n\tmoveTo( x, y ) {\n\t\tthis.top = y;\n\t\tthis.right = x + this.width;\n\t\tthis.bottom = y + this.height;\n\t\tthis.left = x;\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Moves the rect in–place by a dedicated offset.\n\t *\n\t * @param {Number} x A horizontal offset.\n\t * @param {Number} y A vertical offset\n\t * @returns {module:utils/dom/rect~Rect} A rect which has been moved.\n\t */\n\tmoveBy( x, y ) {\n\t\tthis.top += y;\n\t\tthis.right += x;\n\t\tthis.left += x;\n\t\tthis.bottom += y;\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Returns a new rect a a result of intersection with another rect.\n\t *\n\t * @param {module:utils/dom/rect~Rect} anotherRect\n\t * @returns {module:utils/dom/rect~Rect}\n\t */\n\tgetIntersection( anotherRect ) {\n\t\tconst rect = {\n\t\t\ttop: Math.max( this.top, anotherRect.top ),\n\t\t\tright: Math.min( this.right, anotherRect.right ),\n\t\t\tbottom: Math.min( this.bottom, anotherRect.bottom ),\n\t\t\tleft: Math.max( this.left, anotherRect.left )\n\t\t};\n\n\t\trect.width = rect.right - rect.left;\n\t\trect.height = rect.bottom - rect.top;\n\n\t\tif ( rect.width < 0 || rect.height < 0 ) {\n\t\t\treturn null;\n\t\t} else {\n\t\t\treturn new Rect( rect );\n\t\t}\n\t}\n\n\t/**\n\t * Returns the area of intersection with another rect.\n\t *\n\t * @param {module:utils/dom/rect~Rect} anotherRect [description]\n\t * @returns {Number} Area of intersection.\n\t */\n\tgetIntersectionArea( anotherRect ) {\n\t\tconst rect = this.getIntersection( anotherRect );\n\n\t\tif ( rect ) {\n\t\t\treturn rect.getArea();\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t/**\n\t * Returns the area of the rect.\n\t *\n\t * @returns {Number}\n\t */\n\tgetArea() {\n\t\treturn this.width * this.height;\n\t}\n\n\t/**\n\t * Returns a new rect, a part of the original rect, which is actually visible to the user,\n\t * e.g. an original rect cropped by parent element rects which have `overflow` set in CSS\n\t * other than `\"visible\"`.\n\t *\n\t * If there's no such visible rect, which is when the rect is limited by one or many of\n\t * the ancestors, `null` is returned.\n\t *\n\t * @returns {module:utils/dom/rect~Rect|null} A visible rect instance or `null`, if there's none.\n\t */\n\tgetVisible() {\n\t\tconst source = this._source;\n\t\tlet visibleRect = this.clone();\n\n\t\t// There's no ancestor to crop <body> with the overflow.\n\t\tif ( !isBody( source ) ) {\n\t\t\tlet parent = source.parentNode || source.commonAncestorContainer;\n\n\t\t\t// Check the ancestors all the way up to the <body>.\n\t\t\twhile ( parent && !isBody( parent ) ) {\n\t\t\t\tconst parentRect = new Rect( parent );\n\t\t\t\tconst intersectionRect = visibleRect.getIntersection( parentRect );\n\n\t\t\t\tif ( intersectionRect ) {\n\t\t\t\t\tif ( intersectionRect.getArea() < visibleRect.getArea() ) {\n\t\t\t\t\t\t// Reduce the visible rect to the intersection.\n\t\t\t\t\t\tvisibleRect = intersectionRect;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// There's no intersection, the rect is completely invisible.\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tparent = parent.parentNode;\n\t\t\t}\n\t\t}\n\n\t\treturn visibleRect;\n\t}\n\n\t/**\n\t * Checks if all property values ({@link #top}, {@link #left}, {@link #right},\n\t * {@link #bottom}, {@link #width} and {@link #height}) are the equal in both rect\n\t * instances.\n\t *\n\t * @param {module:utils/dom/rect~Rect} rect A rect instance to compare with.\n\t * @returns {Boolean} `true` when Rects are equal. `false` otherwise.\n\t */\n\tisEqual( anotherRect ) {\n\t\tfor ( const prop of rectProperties ) {\n\t\t\tif ( this[ prop ] !== anotherRect[ prop ] ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Checks whether a rect fully contains another rect instance.\n\t *\n\t * @param {module:utils/dom/rect~Rect} anotherRect\n\t * @returns {Boolean} `true` if contains, `false` otherwise.\n\t */\n\tcontains( anotherRect ) {\n\t\tconst intersectRect = this.getIntersection( anotherRect );\n\n\t\treturn !!( intersectRect && intersectRect.isEqual( anotherRect ) );\n\t}\n\n\t/**\n\t * Excludes scrollbars and CSS borders from the rect.\n\t *\n\t * * Borders are removed when {@link #_source} is an HTML element.\n\t * * Scrollbars are excluded from HTML elements and the `window`.\n\t *\n\t * @returns {module:utils/dom/rect~Rect} A rect which has been updated.\n\t */\n\texcludeScrollbarsAndBorders() {\n\t\tconst source = this._source;\n\t\tlet scrollBarWidth, scrollBarHeight, direction;\n\n\t\tif ( isWindow( source ) ) {\n\t\t\tscrollBarWidth = source.innerWidth - source.document.documentElement.clientWidth;\n\t\t\tscrollBarHeight = source.innerHeight - source.document.documentElement.clientHeight;\n\t\t\tdirection = source.getComputedStyle( source.document.documentElement ).direction;\n\t\t} else {\n\t\t\tconst borderWidths = getBorderWidths( this._source );\n\n\t\t\tscrollBarWidth = source.offsetWidth - source.clientWidth - borderWidths.left - borderWidths.right;\n\t\t\tscrollBarHeight = source.offsetHeight - source.clientHeight - borderWidths.top - borderWidths.bottom;\n\t\t\tdirection = source.ownerDocument.defaultView.getComputedStyle( source ).direction;\n\n\t\t\tthis.left += borderWidths.left;\n\t\t\tthis.top += borderWidths.top;\n\t\t\tthis.right -= borderWidths.right;\n\t\t\tthis.bottom -= borderWidths.bottom;\n\t\t\tthis.width = this.right - this.left;\n\t\t\tthis.height = this.bottom - this.top;\n\t\t}\n\n\t\tthis.width -= scrollBarWidth;\n\n\t\tif ( direction === 'ltr' ) {\n\t\t\tthis.right -= scrollBarWidth;\n\t\t} else {\n\t\t\tthis.left += scrollBarWidth;\n\t\t}\n\n\t\tthis.height -= scrollBarHeight;\n\t\tthis.bottom -= scrollBarHeight;\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Returns an array of rects of the given native DOM Range.\n\t *\n\t * @param {Range} range A native DOM range.\n\t * @returns {Array.<module:utils/dom/rect~Rect>} DOM Range rects.\n\t */\n\tstatic getDomRangeRects( range ) {\n\t\tconst rects = [];\n\t\t// Safari does not iterate over ClientRectList using for...of loop.\n\t\tconst clientRects = Array.from( range.getClientRects() );\n\n\t\tif ( clientRects.length ) {\n\t\t\tfor ( const rect of clientRects ) {\n\t\t\t\trects.push( new Rect( rect ) );\n\t\t\t}\n\t\t}\n\t\t// If there's no client rects for the Range, use parent container's bounding rect\n\t\t// instead and adjust rect's width to simulate the actual geometry of such range.\n\t\t// https://github.com/ckeditor/ckeditor5-utils/issues/153\n\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/317\n\t\telse {\n\t\t\tlet startContainer = range.startContainer;\n\n\t\t\tif ( isText( startContainer ) ) {\n\t\t\t\tstartContainer = startContainer.parentNode;\n\t\t\t}\n\n\t\t\tconst rect = new Rect( startContainer.getBoundingClientRect() );\n\t\t\trect.right = rect.left;\n\t\t\trect.width = 0;\n\n\t\t\trects.push( rect );\n\t\t}\n\n\t\treturn rects;\n\t}\n\n\t/**\n\t * Returns a bounding rectangle that contains all the given `rects`.\n\t *\n\t * @param {Iterable.<module:utils/dom/rect~Rect>} rects A list of rectangles that should be contained in the result rectangle.\n\t * @returns {module:utils/dom/rect~Rect|null} Bounding rectangle or `null` if no `rects` were given.\n\t */\n\tstatic getBoundingRect( rects ) {\n\t\tconst boundingRectData = {\n\t\t\tleft: Number.POSITIVE_INFINITY,\n\t\t\ttop: Number.POSITIVE_INFINITY,\n\t\t\tright: Number.NEGATIVE_INFINITY,\n\t\t\tbottom: Number.NEGATIVE_INFINITY\n\t\t};\n\t\tlet rectangleCount = 0;\n\n\t\tfor ( const rect of rects ) {\n\t\t\trectangleCount++;\n\n\t\t\tboundingRectData.left = Math.min( boundingRectData.left, rect.left );\n\t\t\tboundingRectData.top = Math.min( boundingRectData.top, rect.top );\n\t\t\tboundingRectData.right = Math.max( boundingRectData.right, rect.right );\n\t\t\tboundingRectData.bottom = Math.max( boundingRectData.bottom, rect.bottom );\n\t\t}\n\n\t\tif ( rectangleCount == 0 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tboundingRectData.width = boundingRectData.right - boundingRectData.left;\n\t\tboundingRectData.height = boundingRectData.bottom - boundingRectData.top;\n\n\t\treturn new Rect( boundingRectData );\n\t}\n}\n\n// Acquires all the rect properties from the passed source.\n//\n// @private\n// @param {module:utils/dom/rect~Rect} rect\n// @param {ClientRect|module:utils/dom/rect~Rect|Object} source\nfunction copyRectProperties( rect, source ) {\n\tfor ( const p of rectProperties ) {\n\t\trect[ p ] = source[ p ];\n\t}\n}\n\n// Checks if provided object is a <body> HTML element.\n//\n// @private\n// @param {HTMLElement|Range} elementOrRange\n// @returns {Boolean}\nfunction isBody( elementOrRange ) {\n\tif ( !isElement( elementOrRange ) ) {\n\t\treturn false;\n\t}\n\n\treturn elementOrRange === elementOrRange.ownerDocument.body;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/scroll\n */\n\nimport isRange from './isrange';\nimport Rect from './rect';\nimport isText from './istext';\n\nconst utils = {};\n\n/**\n * Makes any page `HTMLElement` or `Range` (`target`) visible inside the browser viewport.\n * This helper will scroll all `target` ancestors and the web browser viewport to reveal the target to\n * the user. If the `target` is already visible, nothing will happen.\n *\n * @param {HTMLElement|Range} options.target A target, which supposed to become visible to the user.\n * @param {Number} [options.viewportOffset] An offset from the edge of the viewport (in pixels)\n * the `target` will be moved by when the viewport is scrolled. It enhances the user experience\n * by keeping the `target` some distance from the edge of the viewport and thus making it easier to\n * read or edit by the user.\n */\nexport function scrollViewportToShowTarget( { target, viewportOffset = 0 } ) {\n\tconst targetWindow = getWindow( target );\n\tlet currentWindow = targetWindow;\n\tlet currentFrame = null;\n\n\t// Iterate over all windows, starting from target's parent window up to window#top.\n\twhile ( currentWindow ) {\n\t\tlet firstAncestorToScroll;\n\n\t\t// Let's scroll target's ancestors first to reveal it. Then, once the ancestor scrolls\n\t\t// settled down, the algorithm can eventually scroll the viewport of the current window.\n\t\t//\n\t\t// Note: If the current window is target's **original** window (e.g. the first one),\n\t\t// start scrolling the closest parent of the target. If not, scroll the closest parent\n\t\t// of an iframe that resides in the current window.\n\t\tif ( currentWindow == targetWindow ) {\n\t\t\tfirstAncestorToScroll = getParentElement( target );\n\t\t} else {\n\t\t\tfirstAncestorToScroll = getParentElement( currentFrame );\n\t\t}\n\n\t\t// Scroll the target's ancestors first. Once done, scrolling the viewport is easy.\n\t\tscrollAncestorsToShowRect( firstAncestorToScroll, () => {\n\t\t\t// Note: If the target does not belong to the current window **directly**,\n\t\t\t// i.e. it resides in an iframe belonging to the window, obtain the target's rect\n\t\t\t// in the coordinates of the current window. By default, a Rect returns geometry\n\t\t\t// relative to the current window's viewport. To make it work in a parent window,\n\t\t\t// it must be shifted.\n\t\t\treturn getRectRelativeToWindow( target, currentWindow );\n\t\t} );\n\n\t\t// Obtain the rect of the target after it has been scrolled within its ancestors.\n\t\t// It's time to scroll the viewport.\n\t\tconst targetRect = getRectRelativeToWindow( target, currentWindow );\n\n\t\tscrollWindowToShowRect( currentWindow, targetRect, viewportOffset );\n\n\t\tif ( currentWindow.parent != currentWindow ) {\n\t\t\t// Keep the reference to the <iframe> element the \"previous current window\" was\n\t\t\t// rendered within. It will be useful to re–calculate the rect of the target\n\t\t\t// in the parent window's relative geometry. The target's rect must be shifted\n\t\t\t// by it's iframe's position.\n\t\t\tcurrentFrame = currentWindow.frameElement;\n\t\t\tcurrentWindow = currentWindow.parent;\n\n\t\t\t// If the current window has some parent but frameElement is inaccessible, then they have\n\t\t\t// different domains/ports and, due to security reasons, accessing and scrolling\n\t\t\t// the parent window won't be possible.\n\t\t\t// See https://github.com/ckeditor/ckeditor5/issues/930.\n\t\t\tif ( !currentFrame ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t} else {\n\t\t\tcurrentWindow = null;\n\t\t}\n\t}\n}\n\n/**\n * Makes any page `HTMLElement` or `Range` (target) visible within its scrollable ancestors,\n * e.g. if they have `overflow: scroll` CSS style.\n *\n * @param {HTMLElement|Range} target A target, which supposed to become visible to the user.\n */\nexport function scrollAncestorsToShowTarget( target ) {\n\tconst targetParent = getParentElement( target );\n\n\tscrollAncestorsToShowRect( targetParent, () => {\n\t\treturn new Rect( target );\n\t} );\n}\n\n// TODO: Using a property value shorthand in the top of the file\n// causes JSDoc to throw errors. See https://github.com/cksource/docs-builder/issues/75.\nObject.assign( utils, {\n\tscrollViewportToShowTarget,\n\tscrollAncestorsToShowTarget\n} );\n\n// Makes a given rect visible within its parent window.\n//\n// Note: Avoid the situation where the caret is still in the viewport, but totally\n// at the edge of it. In such situation, if it moved beyond the viewport in the next\n// action e.g. after paste, the scrolling would move it to the viewportOffset level\n// and it all would look like the caret visually moved up/down:\n//\n// 1.\n//\t\t| foo[]\n//\t\t|                                    <--- N px of space below the caret\n//\t\t+---------------------------------...\n//\n// 2. *paste*\n// 3.\n//\t\t|\n//\t\t|\n//\t\t+-foo-----------------------------...\n//\t\t  bar[]                              <--- caret below viewport, scrolling...\n//\n// 4. *scrolling*\n// 5.\n//\t\t|\n//\t\t| foo\n//\t\t| bar[]                              <--- caret precisely at the edge\n//\t\t+---------------------------------...\n//\n// To prevent this, this method checks the rects moved by the viewportOffset to cover\n// the upper/lower edge of the viewport. It makes sure if the action repeats, there's\n// no twitching – it's a purely visual improvement:\n//\n// 5. (after fix)\n//\t\t|\n//\t\t| foo\n//\t\t| bar[]\n//\t\t|                                    <--- N px of space below the caret\n//\t\t+---------------------------------...\n//\n// @private\n// @param {Window} window A window which is scrolled to reveal the rect.\n// @param {module:utils/dom/rect~Rect} rect A rect which is to be revealed.\n// @param {Number} viewportOffset See scrollViewportToShowTarget.\nfunction scrollWindowToShowRect( window, rect, viewportOffset ) {\n\tconst targetShiftedDownRect = rect.clone().moveBy( 0, viewportOffset );\n\tconst targetShiftedUpRect = rect.clone().moveBy( 0, -viewportOffset );\n\tconst viewportRect = new Rect( window ).excludeScrollbarsAndBorders();\n\n\tconst rects = [ targetShiftedUpRect, targetShiftedDownRect ];\n\n\tif ( !rects.every( rect => viewportRect.contains( rect ) ) ) {\n\t\tlet { scrollX, scrollY } = window;\n\n\t\tif ( isAbove( targetShiftedUpRect, viewportRect ) ) {\n\t\t\tscrollY -= viewportRect.top - rect.top + viewportOffset;\n\t\t} else if ( isBelow( targetShiftedDownRect, viewportRect ) ) {\n\t\t\tscrollY += rect.bottom - viewportRect.bottom + viewportOffset;\n\t\t}\n\n\t\t// TODO: Web browsers scroll natively to place the target in the middle\n\t\t// of the viewport. It's not a very popular case, though.\n\t\tif ( isLeftOf( rect, viewportRect ) ) {\n\t\t\tscrollX -= viewportRect.left - rect.left + viewportOffset;\n\t\t} else if ( isRightOf( rect, viewportRect ) ) {\n\t\t\tscrollX += rect.right - viewportRect.right + viewportOffset;\n\t\t}\n\n\t\twindow.scrollTo( scrollX, scrollY );\n\t}\n}\n\n// Recursively scrolls element ancestors to visually reveal a rect.\n//\n// @private\n// @param {HTMLElement} A parent The first ancestors to start scrolling.\n// @param {Function} getRect A function which returns the Rect, which is to be revealed.\nfunction scrollAncestorsToShowRect( parent, getRect ) {\n\tconst parentWindow = getWindow( parent );\n\tlet parentRect, targetRect;\n\n\twhile ( parent != parentWindow.document.body ) {\n\t\ttargetRect = getRect();\n\t\tparentRect = new Rect( parent ).excludeScrollbarsAndBorders();\n\n\t\tif ( !parentRect.contains( targetRect ) ) {\n\t\t\tif ( isAbove( targetRect, parentRect ) ) {\n\t\t\t\tparent.scrollTop -= parentRect.top - targetRect.top;\n\t\t\t} else if ( isBelow( targetRect, parentRect ) ) {\n\t\t\t\tparent.scrollTop += targetRect.bottom - parentRect.bottom;\n\t\t\t}\n\n\t\t\tif ( isLeftOf( targetRect, parentRect ) ) {\n\t\t\t\tparent.scrollLeft -= parentRect.left - targetRect.left;\n\t\t\t} else if ( isRightOf( targetRect, parentRect ) ) {\n\t\t\t\tparent.scrollLeft += targetRect.right - parentRect.right;\n\t\t\t}\n\t\t}\n\n\t\tparent = parent.parentNode;\n\t}\n}\n\n// Determines if a given `Rect` extends beyond the bottom edge of the second `Rect`.\n//\n// @private\n// @param {module:utils/dom/rect~Rect} firstRect\n// @param {module:utils/dom/rect~Rect} secondRect\nfunction isBelow( firstRect, secondRect ) {\n\treturn firstRect.bottom > secondRect.bottom;\n}\n\n// Determines if a given `Rect` extends beyond the top edge of the second `Rect`.\n//\n// @private\n// @param {module:utils/dom/rect~Rect} firstRect\n// @param {module:utils/dom/rect~Rect} secondRect\nfunction isAbove( firstRect, secondRect ) {\n\treturn firstRect.top < secondRect.top;\n}\n\n// Determines if a given `Rect` extends beyond the left edge of the second `Rect`.\n//\n// @private\n// @param {module:utils/dom/rect~Rect} firstRect\n// @param {module:utils/dom/rect~Rect} secondRect\nfunction isLeftOf( firstRect, secondRect ) {\n\treturn firstRect.left < secondRect.left;\n}\n\n// Determines if a given `Rect` extends beyond the right edge of the second `Rect`.\n//\n// @private\n// @param {module:utils/dom/rect~Rect} firstRect\n// @param {module:utils/dom/rect~Rect} secondRect\nfunction isRightOf( firstRect, secondRect ) {\n\treturn firstRect.right > secondRect.right;\n}\n\n// Returns the closest window of an element or range.\n//\n// @private\n// @param {HTMLElement|Range} firstRect\n// @returns {Window}\nfunction getWindow( elementOrRange ) {\n\tif ( isRange( elementOrRange ) ) {\n\t\treturn elementOrRange.startContainer.ownerDocument.defaultView;\n\t} else {\n\t\treturn elementOrRange.ownerDocument.defaultView;\n\t}\n}\n\n// Returns the closest parent of an element or DOM range.\n//\n// @private\n// @param {HTMLElement|Range} firstRect\n// @returns {HTMLelement}\nfunction getParentElement( elementOrRange ) {\n\tif ( isRange( elementOrRange ) ) {\n\t\tlet parent = elementOrRange.commonAncestorContainer;\n\n\t\t// If a Range is attached to the Text, use the closest element ancestor.\n\t\tif ( isText( parent ) ) {\n\t\t\tparent = parent.parentNode;\n\t\t}\n\n\t\treturn parent;\n\t} else {\n\t\treturn elementOrRange.parentNode;\n\t}\n}\n\n// Returns the rect of an element or range residing in an iframe.\n// The result rect is relative to the geometry of the passed window instance.\n//\n// @private\n// @param {HTMLElement|Range} target Element or range which rect should be returned.\n// @param {Window} relativeWindow A window the rect should be relative to.\n// @returns {module:utils/dom/rect~Rect}\nfunction getRectRelativeToWindow( target, relativeWindow ) {\n\tconst targetWindow = getWindow( target );\n\tconst rect = new Rect( target );\n\n\tif ( targetWindow === relativeWindow ) {\n\t\treturn rect;\n\t} else {\n\t\tlet currentWindow = targetWindow;\n\n\t\twhile ( currentWindow != relativeWindow ) {\n\t\t\tconst frame = currentWindow.frameElement;\n\t\t\tconst frameRect = new Rect( frame ).excludeScrollbarsAndBorders();\n\n\t\t\trect.moveBy( frameRect.left, frameRect.top );\n\n\t\t\tcurrentWindow = currentWindow.parent;\n\t\t}\n\t}\n\n\treturn rect;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/view\n */\n\nimport Document from './document';\nimport DowncastWriter from './downcastwriter';\nimport Renderer from './renderer';\nimport DomConverter from './domconverter';\nimport Position from './position';\nimport Range from './range';\nimport Selection from './selection';\n\nimport MutationObserver from './observer/mutationobserver';\nimport KeyObserver from './observer/keyobserver';\nimport FakeSelectionObserver from './observer/fakeselectionobserver';\nimport SelectionObserver from './observer/selectionobserver';\nimport FocusObserver from './observer/focusobserver';\nimport CompositionObserver from './observer/compositionobserver';\nimport InputObserver from './observer/inputobserver';\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport { scrollViewportToShowTarget } from '@ckeditor/ckeditor5-utils/src/dom/scroll';\nimport { injectUiElementHandling } from './uielement';\nimport { injectQuirksHandling } from './filler';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\n/**\n * Editor's view controller class. Its main responsibility is DOM - View management for editing purposes, to provide\n * abstraction over the DOM structure and events and hide all browsers quirks.\n *\n * View controller renders view document to DOM whenever view structure changes. To determine when view can be rendered,\n * all changes need to be done using the {@link module:engine/view/view~View#change} method, using\n * {@link module:engine/view/downcastwriter~DowncastWriter}:\n *\n *\t\tview.change( writer => {\n *\t\t\twriter.insert( position, writer.createText( 'foo' ) );\n *\t\t} );\n *\n * View controller also register {@link module:engine/view/observer/observer~Observer observers} which observes changes\n * on DOM and fire events on the {@link module:engine/view/document~Document Document}.\n * Note that the following observers are added by the class constructor and are always available:\n *\n * * {@link module:engine/view/observer/mutationobserver~MutationObserver},\n * * {@link module:engine/view/observer/selectionobserver~SelectionObserver},\n * * {@link module:engine/view/observer/focusobserver~FocusObserver},\n * * {@link module:engine/view/observer/keyobserver~KeyObserver},\n * * {@link module:engine/view/observer/fakeselectionobserver~FakeSelectionObserver}.\n * * {@link module:engine/view/observer/compositionobserver~CompositionObserver}.\n *\n * This class also {@link module:engine/view/view~View#attachDomRoot binds the DOM and the view elements}.\n *\n * If you do not need full a DOM - view management, and only want to transform a tree of view elements to a tree of DOM\n * elements you do not need this controller. You can use the {@link module:engine/view/domconverter~DomConverter DomConverter} instead.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class View {\n\t/**\n\t * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor The styles processor instance.\n\t */\n\tconstructor( stylesProcessor ) {\n\t\t/**\n\t\t * Instance of the {@link module:engine/view/document~Document} associated with this view controller.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = new Document( stylesProcessor );\n\n\t\t/**\n\t\t * Instance of the {@link module:engine/view/domconverter~DomConverter domConverter} used by\n\t\t * {@link module:engine/view/view~View#_renderer renderer}\n\t\t * and {@link module:engine/view/observer/observer~Observer observers}.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/view/domconverter~DomConverter}\n\t\t */\n\t\tthis.domConverter = new DomConverter( this.document );\n\n\t\t/**\n\t\t * Roots of the DOM tree. Map on the `HTMLElement`s with roots names as keys.\n\t\t *\n\t\t * @readonly\n\t\t * @type {Map.<String, HTMLElement>}\n\t\t */\n\t\tthis.domRoots = new Map();\n\n\t\t/**\n\t\t * Used to prevent calling {@link #forceRender} and {@link #change} during rendering view to the DOM.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} #isRenderingInProgress\n\t\t */\n\t\tthis.set( 'isRenderingInProgress', false );\n\n\t\t/**\n\t\t * Informs whether the DOM selection is inside any of the DOM roots managed by the view.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} #hasDomSelection\n\t\t */\n\t\tthis.set( 'hasDomSelection', false );\n\n\t\t/**\n\t\t * Instance of the {@link module:engine/view/renderer~Renderer renderer}.\n\t\t *\n\t\t * @protected\n\t\t * @type {module:engine/view/renderer~Renderer}\n\t\t */\n\t\tthis._renderer = new Renderer( this.domConverter, this.document.selection );\n\t\tthis._renderer.bind( 'isFocused' ).to( this.document );\n\n\t\t/**\n\t\t * A DOM root attributes cache. It saves the initial values of DOM root attributes before the DOM element\n\t\t * is {@link module:engine/view/view~View#attachDomRoot attached} to the view so later on, when\n\t\t * the view is destroyed ({@link module:engine/view/view~View#detachDomRoot}), they can be easily restored.\n\t\t * This way, the DOM element can go back to the (clean) state as if the editing view never used it.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap.<HTMLElement,Object>}\n\t\t */\n\t\tthis._initialDomRootAttributes = new WeakMap();\n\n\t\t/**\n\t\t * Map of registered {@link module:engine/view/observer/observer~Observer observers}.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.<Function, module:engine/view/observer/observer~Observer>}\n\t\t */\n\t\tthis._observers = new Map();\n\n\t\t/**\n\t\t * Is set to `true` when {@link #change view changes} are currently in progress.\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._ongoingChange = false;\n\n\t\t/**\n\t\t * Used to prevent calling {@link #forceRender} and {@link #change} during rendering view to the DOM.\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._postFixersInProgress = false;\n\n\t\t/**\n\t\t * Internal flag to temporary disable rendering. See the usage in the {@link #_disableRendering}.\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._renderingDisabled = false;\n\n\t\t/**\n\t\t * Internal flag that disables rendering when there are no changes since the last rendering.\n\t\t * It stores information about changed selection and changed elements from attached document roots.\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._hasChangedSinceTheLastRendering = false;\n\n\t\t/**\n\t\t * DowncastWriter instance used in {@link #change change method} callbacks.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/view/downcastwriter~DowncastWriter}\n\t\t */\n\t\tthis._writer = new DowncastWriter( this.document );\n\n\t\t// Add default observers.\n\t\tthis.addObserver( MutationObserver );\n\t\tthis.addObserver( SelectionObserver );\n\t\tthis.addObserver( FocusObserver );\n\t\tthis.addObserver( KeyObserver );\n\t\tthis.addObserver( FakeSelectionObserver );\n\t\tthis.addObserver( CompositionObserver );\n\n\t\tif ( env.isAndroid ) {\n\t\t\tthis.addObserver( InputObserver );\n\t\t}\n\n\t\t// Inject quirks handlers.\n\t\tinjectQuirksHandling( this );\n\t\tinjectUiElementHandling( this );\n\n\t\t// Use 'normal' priority so that rendering is performed as first when using that priority.\n\t\tthis.on( 'render', () => {\n\t\t\tthis._render();\n\n\t\t\t// Informs that layout has changed after render.\n\t\t\tthis.document.fire( 'layoutChanged' );\n\n\t\t\t// Reset the `_hasChangedSinceTheLastRendering` flag after rendering.\n\t\t\tthis._hasChangedSinceTheLastRendering = false;\n\t\t} );\n\n\t\t// Listen to the document selection changes directly.\n\t\tthis.listenTo( this.document.selection, 'change', () => {\n\t\t\tthis._hasChangedSinceTheLastRendering = true;\n\t\t} );\n\t}\n\n\t/**\n\t * Attaches a DOM root element to the view element and enable all observers on that element.\n\t * Also {@link module:engine/view/renderer~Renderer#markToSync mark element} to be synchronized\n\t * with the view what means that all child nodes will be removed and replaced with content of the view root.\n\t *\n\t * This method also will change view element name as the same as tag name of given dom root.\n\t * Name is always transformed to lower case.\n\t *\n\t * **Note:** Use {@link #detachDomRoot `detachDomRoot()`} to revert this action.\n\t *\n\t * @param {Element} domRoot DOM root element.\n\t * @param {String} [name='main'] Name of the root.\n\t */\n\tattachDomRoot( domRoot, name = 'main' ) {\n\t\tconst viewRoot = this.document.getRoot( name );\n\n\t\t// Set view root name the same as DOM root tag name.\n\t\tviewRoot._name = domRoot.tagName.toLowerCase();\n\n\t\tconst initialDomRootAttributes = {};\n\n\t\t// 1. Copy and cache the attributes to remember the state of the element before attaching.\n\t\t//    The cached attributes will be restored in detachDomRoot() so the element goes to the\n\t\t//    clean state as if the editing view never used it.\n\t\t// 2. Apply the attributes using the view writer, so they all go under the control of the engine.\n\t\t//    The editing view takes over the attribute management completely because various\n\t\t//    features (e.g. addPlaceholder()) require dynamic changes of those attributes and they\n\t\t//    cannot be managed by the engine and the UI library at the same time.\n\t\tfor ( const { name, value } of Array.from( domRoot.attributes ) ) {\n\t\t\tinitialDomRootAttributes[ name ] = value;\n\n\t\t\t// Do not use writer.setAttribute() for the class attribute. The EditableUIView class\n\t\t\t// and its descendants could have already set some using the writer.addClass() on the view\n\t\t\t// document root. They haven't been rendered yet so they are not present in the DOM root.\n\t\t\t// Using writer.setAttribute( 'class', ... ) would override them completely.\n\t\t\tif ( name === 'class' ) {\n\t\t\t\tthis._writer.addClass( value.split( ' ' ), viewRoot );\n\t\t\t} else {\n\t\t\t\tthis._writer.setAttribute( name, value, viewRoot );\n\t\t\t}\n\t\t}\n\n\t\tthis._initialDomRootAttributes.set( domRoot, initialDomRootAttributes );\n\n\t\tconst updateContenteditableAttribute = () => {\n\t\t\tthis._writer.setAttribute( 'contenteditable', !viewRoot.isReadOnly, viewRoot );\n\n\t\t\tif ( viewRoot.isReadOnly ) {\n\t\t\t\tthis._writer.addClass( 'ck-read-only', viewRoot );\n\t\t\t} else {\n\t\t\t\tthis._writer.removeClass( 'ck-read-only', viewRoot );\n\t\t\t}\n\t\t};\n\n\t\t// Set initial value.\n\t\tupdateContenteditableAttribute();\n\n\t\tthis.domRoots.set( name, domRoot );\n\t\tthis.domConverter.bindElements( domRoot, viewRoot );\n\t\tthis._renderer.markToSync( 'children', viewRoot );\n\t\tthis._renderer.markToSync( 'attributes', viewRoot );\n\t\tthis._renderer.domDocuments.add( domRoot.ownerDocument );\n\n\t\tviewRoot.on( 'change:children', ( evt, node ) => this._renderer.markToSync( 'children', node ) );\n\t\tviewRoot.on( 'change:attributes', ( evt, node ) => this._renderer.markToSync( 'attributes', node ) );\n\t\tviewRoot.on( 'change:text', ( evt, node ) => this._renderer.markToSync( 'text', node ) );\n\t\tviewRoot.on( 'change:isReadOnly', () => this.change( updateContenteditableAttribute ) );\n\n\t\tviewRoot.on( 'change', () => {\n\t\t\tthis._hasChangedSinceTheLastRendering = true;\n\t\t} );\n\n\t\tfor ( const observer of this._observers.values() ) {\n\t\t\tobserver.observe( domRoot, name );\n\t\t}\n\t}\n\n\t/**\n\t * Detaches a DOM root element from the view element and restores its attributes to the state before\n\t * {@link #attachDomRoot `attachDomRoot()`}.\n\t *\n\t * @param {String} name Name of the root to detach.\n\t */\n\tdetachDomRoot( name ) {\n\t\tconst domRoot = this.domRoots.get( name );\n\n\t\t// Remove all root attributes so the DOM element is \"bare\".\n\t\tArray.from( domRoot.attributes ).forEach( ( { name } ) => domRoot.removeAttribute( name ) );\n\n\t\tconst initialDomRootAttributes = this._initialDomRootAttributes.get( domRoot );\n\n\t\t// Revert all view root attributes back to the state before attachDomRoot was called.\n\t\tfor ( const attribute in initialDomRootAttributes ) {\n\t\t\tdomRoot.setAttribute( attribute, initialDomRootAttributes[ attribute ] );\n\t\t}\n\n\t\tthis.domRoots.delete( name );\n\t\tthis.domConverter.unbindDomElement( domRoot );\n\t}\n\n\t/**\n\t * Gets DOM root element.\n\t *\n\t * @param {String} [name='main']  Name of the root.\n\t * @returns {Element} DOM root element instance.\n\t */\n\tgetDomRoot( name = 'main' ) {\n\t\treturn this.domRoots.get( name );\n\t}\n\n\t/**\n\t * Creates observer of the given type if not yet created, {@link module:engine/view/observer/observer~Observer#enable enables} it\n\t * and {@link module:engine/view/observer/observer~Observer#observe attaches} to all existing and future\n\t * {@link #domRoots DOM roots}.\n\t *\n\t * Note: Observers are recognized by their constructor (classes). A single observer will be instantiated and used only\n\t * when registered for the first time. This means that features and other components can register a single observer\n\t * multiple times without caring whether it has been already added or not.\n\t *\n\t * @param {Function} Observer The constructor of an observer to add.\n\t * Should create an instance inheriting from {@link module:engine/view/observer/observer~Observer}.\n\t * @returns {module:engine/view/observer/observer~Observer} Added observer instance.\n\t */\n\taddObserver( Observer ) {\n\t\tlet observer = this._observers.get( Observer );\n\n\t\tif ( observer ) {\n\t\t\treturn observer;\n\t\t}\n\n\t\tobserver = new Observer( this );\n\n\t\tthis._observers.set( Observer, observer );\n\n\t\tfor ( const [ name, domElement ] of this.domRoots ) {\n\t\t\tobserver.observe( domElement, name );\n\t\t}\n\n\t\tobserver.enable();\n\n\t\treturn observer;\n\t}\n\n\t/**\n\t * Returns observer of the given type or `undefined` if such observer has not been added yet.\n\t *\n\t * @param {Function} Observer The constructor of an observer to get.\n\t * @returns {module:engine/view/observer/observer~Observer|undefined} Observer instance or undefined.\n\t */\n\tgetObserver( Observer ) {\n\t\treturn this._observers.get( Observer );\n\t}\n\n\t/**\n\t * Disables all added observers.\n\t */\n\tdisableObservers() {\n\t\tfor ( const observer of this._observers.values() ) {\n\t\t\tobserver.disable();\n\t\t}\n\t}\n\n\t/**\n\t * Enables all added observers.\n\t */\n\tenableObservers() {\n\t\tfor ( const observer of this._observers.values() ) {\n\t\t\tobserver.enable();\n\t\t}\n\t}\n\n\t/**\n\t * Scrolls the page viewport and {@link #domRoots} with their ancestors to reveal the\n\t * caret, if not already visible to the user.\n\t */\n\tscrollToTheSelection() {\n\t\tconst range = this.document.selection.getFirstRange();\n\n\t\tif ( range ) {\n\t\t\tscrollViewportToShowTarget( {\n\t\t\t\ttarget: this.domConverter.viewRangeToDom( range ),\n\t\t\t\tviewportOffset: 20\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * It will focus DOM element representing {@link module:engine/view/editableelement~EditableElement EditableElement}\n\t * that is currently having selection inside.\n\t */\n\tfocus() {\n\t\tif ( !this.document.isFocused ) {\n\t\t\tconst editable = this.document.selection.editableElement;\n\n\t\t\tif ( editable ) {\n\t\t\t\tthis.domConverter.focus( editable );\n\t\t\t\tthis.forceRender();\n\t\t\t} else {\n\t\t\t\t// Before focusing view document, selection should be placed inside one of the view's editables.\n\t\t\t\t// Normally its selection will be converted from model document (which have default selection), but\n\t\t\t\t// when using view document on its own, we need to manually place selection before focusing it.\n\t\t\t\t//\n\t\t\t\t// @if CK_DEBUG // console.warn( 'There is no selection in any editable to focus.' );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * The `change()` method is the primary way of changing the view. You should use it to modify any node in the view tree.\n\t * It makes sure that after all changes are made the view is rendered to the DOM (assuming that the view will be changed\n\t * inside the callback). It prevents situations when the DOM is updated when the view state is not yet correct. It allows\n\t * to nest calls one inside another and still performs a single rendering after all those changes are made.\n\t * It also returns the return value of its callback.\n\t *\n\t *\t\tconst text = view.change( writer => {\n\t *\t\t\tconst newText = writer.createText( 'foo' );\n\t *\t\t\twriter.insert( position1, newText );\n\t *\n\t *\t\t\tview.change( writer => {\n\t *\t\t\t\twriter.insert( position2, writer.createText( 'bar' ) );\n\t *\t\t\t} );\n\t *\n\t * \t\t\twriter.remove( range );\n\t *\n\t * \t\t\treturn newText;\n\t *\t\t} );\n\t *\n\t * When the outermost change block is done and rendering to the DOM is over the\n\t * {@link module:engine/view/view~View#event:render `View#render`} event is fired.\n\t *\n\t * This method throws a `applying-view-changes-on-rendering` error when\n\t * the change block is used after rendering to the DOM has started.\n\t *\n\t * @param {Function} callback Callback function which may modify the view.\n\t * @returns {*} Value returned by the callback.\n\t */\n\tchange( callback ) {\n\t\tif ( this.isRenderingInProgress || this._postFixersInProgress ) {\n\t\t\t/**\n\t\t\t * Thrown when there is an attempt to make changes to the view tree when it is in incorrect state. This may\n\t\t\t * cause some unexpected behaviour and inconsistency between the DOM and the view.\n\t\t\t * This may be caused by:\n\t\t\t *\n\t\t\t * * calling {@link #change} or {@link #forceRender} during rendering process,\n\t\t\t * * calling {@link #change} or {@link #forceRender} inside of\n\t\t\t *   {@link module:engine/view/document~Document#registerPostFixer post-fixer function}.\n\t\t\t *\n\t\t\t * @error cannot-change-view-tree\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'cannot-change-view-tree',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\ttry {\n\t\t\t// Recursive call to view.change() method - execute listener immediately.\n\t\t\tif ( this._ongoingChange ) {\n\t\t\t\treturn callback( this._writer );\n\t\t\t}\n\n\t\t\t// This lock will assure that all recursive calls to view.change() will end up in same block - one \"render\"\n\t\t\t// event for all nested calls.\n\t\t\tthis._ongoingChange = true;\n\t\t\tconst callbackResult = callback( this._writer );\n\t\t\tthis._ongoingChange = false;\n\n\t\t\t// This lock is used by editing controller to render changes from outer most model.change() once. As plugins might call\n\t\t\t// view.change() inside model.change() block - this will ensures that postfixers and rendering are called once after all\n\t\t\t// changes. Also, we don't need to render anything if there're no changes since last rendering.\n\t\t\tif ( !this._renderingDisabled && this._hasChangedSinceTheLastRendering ) {\n\t\t\t\tthis._postFixersInProgress = true;\n\t\t\t\tthis.document._callPostFixers( this._writer );\n\t\t\t\tthis._postFixersInProgress = false;\n\n\t\t\t\tthis.fire( 'render' );\n\t\t\t}\n\n\t\t\treturn callbackResult;\n\t\t} catch ( err ) {\n\t\t\t// @if CK_DEBUG // throw err;\n\t\t\t/* istanbul ignore next */\n\t\t\tCKEditorError.rethrowUnexpectedError( err, this );\n\t\t}\n\t}\n\n\t/**\n\t * Forces rendering {@link module:engine/view/document~Document view document} to DOM. If any view changes are\n\t * currently in progress, rendering will start after all {@link #change change blocks} are processed.\n\t *\n\t * Note that this method is dedicated for special cases. All view changes should be wrapped in the {@link #change}\n\t * block and the view will automatically check whether it needs to render DOM or not.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `applying-view-changes-on-rendering` when\n\t * trying to re-render when rendering to DOM has already started.\n\t */\n\tforceRender() {\n\t\tthis._hasChangedSinceTheLastRendering = true;\n\t\tthis.change( () => {} );\n\t}\n\n\t/**\n\t * Destroys this instance. Makes sure that all observers are destroyed and listeners removed.\n\t */\n\tdestroy() {\n\t\tfor ( const observer of this._observers.values() ) {\n\t\t\tobserver.destroy();\n\t\t}\n\n\t\tthis.document.destroy();\n\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Creates position at the given location. The location can be specified as:\n\t *\n\t * * a {@link module:engine/view/position~Position position},\n\t * * parent element and offset (offset defaults to `0`),\n\t * * parent element and `'end'` (sets position at the end of that element),\n\t * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).\n\t *\n\t * This method is a shortcut to other constructors such as:\n\t *\n\t * * {@link #createPositionBefore},\n\t * * {@link #createPositionAfter},\n\t *\n\t * @param {module:engine/view/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/view/item~Item view item}.\n\t */\n\tcreatePositionAt( itemOrPosition, offset ) {\n\t\treturn Position._createAt( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Creates a new position after given view item.\n\t *\n\t * @param {module:engine/view/item~Item} item View item after which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tcreatePositionAfter( item ) {\n\t\treturn Position._createAfter( item );\n\t}\n\n\t/**\n\t * Creates a new position before given view item.\n\t *\n\t * @param {module:engine/view/item~Item} item View item before which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tcreatePositionBefore( item ) {\n\t\treturn Position._createBefore( item );\n\t}\n\n\t/**\n\t * Creates a range spanning from `start` position to `end` position.\n\t *\n\t * **Note:** This factory method creates it's own {@link module:engine/view/position~Position} instances basing on passed values.\n\t *\n\t * @param {module:engine/view/position~Position} start Start position.\n\t * @param {module:engine/view/position~Position} [end] End position. If not set, range will be collapsed at `start` position.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRange( start, end ) {\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.\n\t *\n\t * @param {module:engine/view/item~Item} item\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRangeOn( item ) {\n\t\treturn Range._createOn( item );\n\t}\n\n\t/**\n\t * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t * @param {module:engine/view/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRangeIn( element ) {\n\t\treturn Range._createIn( element );\n\t}\n\n\t/**\n\t Creates new {@link module:engine/view/selection~Selection} instance.\n\t *\n\t * \t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = view.createSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = view.createRange( start, end );\n\t *\t\tconst selection = view.createSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t * \t\tconst ranges = [ view.createRange( start1, end2 ), view.createRange( star2, end2 ) ];\n\t *\t\tconst selection = view.createSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\tconst otherSelection = view.createSelection();\n\t *\t\tconst selection = view.createSelection( otherSelection );\n\t *\n\t *\t\t// Creates selection from the document selection.\n\t *\t\tconst selection = view.createSelection( editor.editing.view.document.selection );\n\t *\n\t * \t\t// Creates selection at the given position.\n\t *\t\tconst position = view.createPositionFromPath( root, path );\n\t *\t\tconst selection = view.createSelection( position );\n\t *\n\t *\t\t// Creates collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = view.createContainerElement( 'paragraph' );\n\t *\t\tconst selection = view.createSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = view.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = view.createSelection( paragraph, 'on' );\n\t *\n\t * `Selection`'s factory method allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = view.createSelection( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * (and be  properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tconst selection = view.createSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/selection~Selectable} [selectable=null]\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Offset or place when selectable is an `Item`.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t * @returns {module:engine/view/selection~Selection}\n\t */\n\tcreateSelection( selectable, placeOrOffset, options ) {\n\t\treturn new Selection( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Disables or enables rendering. If the flag is set to `true` then the rendering will be disabled.\n\t * If the flag is set to `false` and if there was some change in the meantime, then the rendering action will be performed.\n\t *\n\t * @protected\n\t * @param {Boolean} flag A flag indicates whether the rendering should be disabled.\n\t */\n\t_disableRendering( flag ) {\n\t\tthis._renderingDisabled = flag;\n\n\t\tif ( flag == false ) {\n\t\t\t// Render when you stop blocking rendering.\n\t\t\tthis.change( () => {} );\n\t\t}\n\t}\n\n\t/**\n\t * Renders all changes. In order to avoid triggering the observers (e.g. mutations) all observers are disabled\n\t * before rendering and re-enabled after that.\n\t *\n\t * @private\n\t */\n\t_render() {\n\t\tthis.isRenderingInProgress = true;\n\t\tthis.disableObservers();\n\t\tthis._renderer.render();\n\t\tthis.enableObservers();\n\t\tthis.isRenderingInProgress = false;\n\t}\n\n\t/**\n\t * Fired after a topmost {@link module:engine/view/view~View#change change block} and all\n\t * {@link module:engine/view/document~Document#registerPostFixer post-fixers} are executed.\n\t *\n\t * Actual rendering is performed as a first listener on 'normal' priority.\n\t *\n\t *\t\tview.on( 'render', () => {\n\t *\t\t\t// Rendering to the DOM is complete.\n\t *\t\t} );\n\t *\n\t * This event is useful when you want to update interface elements after the rendering, e.g. position of the\n\t * balloon panel. If you wants to change view structure use\n\t * {@link module:engine/view/document~Document#registerPostFixer post-fixers}.\n\t *\n\t * @event module:engine/view/view~View#event:render\n\t */\n}\n\nmix( View, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/node\n */\n\nimport toMap from '@ckeditor/ckeditor5-utils/src/tomap';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\n// To check if component is loaded more than once.\nimport '@ckeditor/ckeditor5-utils/src/version';\n\n/**\n * Model node. Most basic structure of model tree.\n *\n * This is an abstract class that is a base for other classes representing different nodes in model.\n *\n * **Note:** If a node is detached from the model tree, you can manipulate it using it's API.\n * However, it is **very important** that nodes already attached to model tree should be only changed through\n * {@link module:engine/model/writer~Writer Writer API}.\n *\n * Changes done by `Node` methods, like {@link module:engine/model/element~Element#_insertChild _insertChild} or\n * {@link module:engine/model/node~Node#_setAttribute _setAttribute}\n * do not generate {@link module:engine/model/operation/operation~Operation operations}\n * which are essential for correct editor work if you modify nodes in {@link module:engine/model/document~Document document} root.\n *\n * The flow of working on `Node` (and classes that inherits from it) is as such:\n * 1. You can create a `Node` instance, modify it using it's API.\n * 2. Add `Node` to the model using `Batch` API.\n * 3. Change `Node` that was already added to the model using `Batch` API.\n *\n * Similarly, you cannot use `Batch` API on a node that has not been added to the model tree, with the exception\n * of {@link module:engine/model/writer~Writer#insert inserting} that node to the model tree.\n *\n * Be aware that using {@link module:engine/model/writer~Writer#remove remove from Batch API} does not allow to use `Node` API because\n * the information about `Node` is still kept in model document.\n *\n * In case of {@link module:engine/model/element~Element element node}, adding and removing children also counts as changing a node and\n * follows same rules.\n */\nexport default class Node {\n\t/**\n\t * Creates a model node.\n\t *\n\t * This is an abstract class, so this constructor should not be used directly.\n\t *\n\t * @abstract\n\t * @param {Object} [attrs] Node's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.\n\t */\n\tconstructor( attrs ) {\n\t\t/**\n\t\t * Parent of this node. It could be {@link module:engine/model/element~Element}\n\t\t * or {@link module:engine/model/documentfragment~DocumentFragment}.\n\t\t * Equals to `null` if the node has no parent.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment|null}\n\t\t */\n\t\tthis.parent = null;\n\n\t\t/**\n\t\t * Attributes set on this node.\n\t\t *\n\t\t * @private\n\t\t * @member {Map} module:engine/model/node~Node#_attrs\n\t\t */\n\t\tthis._attrs = toMap( attrs );\n\t}\n\n\t/**\n\t * Index of this node in it's parent or `null` if the node has no parent.\n\t *\n\t * Accessing this property throws an error if this node's parent element does not contain it.\n\t * This means that model tree got broken.\n\t *\n\t * @readonly\n\t * @type {Number|null}\n\t */\n\tget index() {\n\t\tlet pos;\n\n\t\tif ( !this.parent ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( ( pos = this.parent.getChildIndex( this ) ) === null ) {\n\t\t\tthrow new CKEditorError( 'model-node-not-found-in-parent', this );\n\t\t}\n\n\t\treturn pos;\n\t}\n\n\t/**\n\t * Offset at which this node starts in it's parent. It is equal to the sum of {@link #offsetSize offsetSize}\n\t * of all it's previous siblings. Equals to `null` if node has no parent.\n\t *\n\t * Accessing this property throws an error if this node's parent element does not contain it.\n\t * This means that model tree got broken.\n\t *\n\t * @readonly\n\t * @type {Number|null}\n\t */\n\tget startOffset() {\n\t\tlet pos;\n\n\t\tif ( !this.parent ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( ( pos = this.parent.getChildStartOffset( this ) ) === null ) {\n\t\t\tthrow new CKEditorError( 'model-node-not-found-in-parent', this );\n\t\t}\n\n\t\treturn pos;\n\t}\n\n\t/**\n\t * Offset size of this node. Represents how much \"offset space\" is occupied by the node in it's parent.\n\t * It is important for {@link module:engine/model/position~Position position}. When node has `offsetSize` greater than `1`, position\n\t * can be placed between that node start and end. `offsetSize` greater than `1` is for nodes that represents more\n\t * than one entity, i.e. {@link module:engine/model/text~Text text node}.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget offsetSize() {\n\t\treturn 1;\n\t}\n\n\t/**\n\t * Offset at which this node ends in it's parent. It is equal to the sum of this node's\n\t * {@link module:engine/model/node~Node#startOffset start offset} and {@link #offsetSize offset size}.\n\t * Equals to `null` if the node has no parent.\n\t *\n\t * @readonly\n\t * @type {Number|null}\n\t */\n\tget endOffset() {\n\t\tif ( !this.parent ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.startOffset + this.offsetSize;\n\t}\n\n\t/**\n\t * Node's next sibling or `null` if the node is a last child of it's parent or if the node has no parent.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/node~Node|null}\n\t */\n\tget nextSibling() {\n\t\tconst index = this.index;\n\n\t\treturn ( index !== null && this.parent.getChild( index + 1 ) ) || null;\n\t}\n\n\t/**\n\t * Node's previous sibling or `null` if the node is a first child of it's parent or if the node has no parent.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/node~Node|null}\n\t */\n\tget previousSibling() {\n\t\tconst index = this.index;\n\n\t\treturn ( index !== null && this.parent.getChild( index - 1 ) ) || null;\n\t}\n\n\t/**\n\t * The top-most ancestor of the node. If node has no parent it is the root itself. If the node is a part\n\t * of {@link module:engine/model/documentfragment~DocumentFragment}, it's `root` is equal to that `DocumentFragment`.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/node~Node|module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\tlet root = this; // eslint-disable-line consistent-this\n\n\t\twhile ( root.parent ) {\n\t\t\troot = root.parent;\n\t\t}\n\n\t\treturn root;\n\t}\n\n\t/**\n\t * Returns true if the node is in a tree rooted in the document (is a descendant of one of its roots).\n\t *\n\t * @returns {Boolean}\n\t */\n\tisAttached() {\n\t\treturn this.root.is( 'rootElement' );\n\t}\n\n\t/**\n\t * Gets path to the node. The path is an array containing starting offsets of consecutive ancestors of this node,\n\t * beginning from {@link module:engine/model/node~Node#root root}, down to this node's starting offset. The path can be used to\n\t * create {@link module:engine/model/position~Position Position} instance.\n\t *\n\t *\t\tconst abc = new Text( 'abc' );\n\t *\t\tconst foo = new Text( 'foo' );\n\t *\t\tconst h1 = new Element( 'h1', null, new Text( 'header' ) );\n\t *\t\tconst p = new Element( 'p', null, [ abc, foo ] );\n\t *\t\tconst div = new Element( 'div', null, [ h1, p ] );\n\t *\t\tfoo.getPath(); // Returns [ 1, 3 ]. `foo` is in `p` which is in `div`. `p` starts at offset 1, while `foo` at 3.\n\t *\t\th1.getPath(); // Returns [ 0 ].\n\t *\t\tdiv.getPath(); // Returns [].\n\t *\n\t * @returns {Array.<Number>} The path.\n\t */\n\tgetPath() {\n\t\tconst path = [];\n\t\tlet node = this; // eslint-disable-line consistent-this\n\n\t\twhile ( node.parent ) {\n\t\t\tpath.unshift( node.startOffset );\n\t\t\tnode = node.parent;\n\t\t}\n\n\t\treturn path;\n\t}\n\n\t/**\n\t * Returns ancestors array of this node.\n\t *\n\t * @param {Object} options Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` this node will be also included in parent's array.\n\t * @param {Boolean} [options.parentFirst=false] When set to `true`, array will be sorted from node's parent to root element,\n\t * otherwise root element will be the first item in the array.\n\t * @returns {Array} Array with ancestors.\n\t */\n\tgetAncestors( options = { includeSelf: false, parentFirst: false } ) {\n\t\tconst ancestors = [];\n\t\tlet parent = options.includeSelf ? this : this.parent;\n\n\t\twhile ( parent ) {\n\t\t\tancestors[ options.parentFirst ? 'push' : 'unshift' ]( parent );\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn ancestors;\n\t}\n\n\t/**\n\t * Returns a {@link module:engine/model/element~Element} or {@link module:engine/model/documentfragment~DocumentFragment}\n\t * which is a common ancestor of both nodes.\n\t *\n\t * @param {module:engine/model/node~Node} node The second node.\n\t * @param {Object} options Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` both nodes will be considered \"ancestors\" too.\n\t * Which means that if e.g. node A is inside B, then their common ancestor will be B.\n\t * @returns {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor( node, options = {} ) {\n\t\tconst ancestorsA = this.getAncestors( options );\n\t\tconst ancestorsB = node.getAncestors( options );\n\n\t\tlet i = 0;\n\n\t\twhile ( ancestorsA[ i ] == ancestorsB[ i ] && ancestorsA[ i ] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i === 0 ? null : ancestorsA[ i - 1 ];\n\t}\n\n\t/**\n\t * Returns whether this node is before given node. `false` is returned if nodes are in different trees (for example,\n\t * in different {@link module:engine/model/documentfragment~DocumentFragment}s).\n\t *\n\t * @param {module:engine/model/node~Node} node Node to compare with.\n\t * @returns {Boolean}\n\t */\n\tisBefore( node ) {\n\t\t// Given node is not before this node if they are same.\n\t\tif ( this == node ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Return `false` if it is impossible to compare nodes.\n\t\tif ( this.root !== node.root ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst thisPath = this.getPath();\n\t\tconst nodePath = node.getPath();\n\n\t\tconst result = compareArrays( thisPath, nodePath );\n\n\t\tswitch ( result ) {\n\t\t\tcase 'prefix':\n\t\t\t\treturn true;\n\n\t\t\tcase 'extension':\n\t\t\t\treturn false;\n\n\t\t\tdefault:\n\t\t\t\treturn thisPath[ result ] < nodePath[ result ];\n\t\t}\n\t}\n\n\t/**\n\t * Returns whether this node is after given node. `false` is returned if nodes are in different trees (for example,\n\t * in different {@link module:engine/model/documentfragment~DocumentFragment}s).\n\t *\n\t * @param {module:engine/model/node~Node} node Node to compare with.\n\t * @returns {Boolean}\n\t */\n\tisAfter( node ) {\n\t\t// Given node is not before this node if they are same.\n\t\tif ( this == node ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Return `false` if it is impossible to compare nodes.\n\t\tif ( this.root !== node.root ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// In other cases, just check if the `node` is before, and return the opposite.\n\t\treturn !this.isBefore( node );\n\t}\n\n\t/**\n\t * Checks if the node has an attribute with given key.\n\t *\n\t * @param {String} key Key of attribute to check.\n\t * @returns {Boolean} `true` if attribute with given key is set on node, `false` otherwise.\n\t */\n\thasAttribute( key ) {\n\t\treturn this._attrs.has( key );\n\t}\n\n\t/**\n\t * Gets an attribute value for given key or `undefined` if that attribute is not set on node.\n\t *\n\t * @param {String} key Key of attribute to look for.\n\t * @returns {*} Attribute value or `undefined`.\n\t */\n\tgetAttribute( key ) {\n\t\treturn this._attrs.get( key );\n\t}\n\n\t/**\n\t * Returns iterator that iterates over this node's attributes.\n\t *\n\t * Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.\n\t * This format is accepted by native `Map` object and also can be passed in `Node` constructor.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\tgetAttributes() {\n\t\treturn this._attrs.entries();\n\t}\n\n\t/**\n\t * Returns iterator that iterates over this node's attribute keys.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetAttributeKeys() {\n\t\treturn this._attrs.keys();\n\t}\n\n\t/**\n\t * Converts `Node` to plain object and returns it.\n\t *\n\t * @returns {Object} `Node` converted to plain object.\n\t */\n\ttoJSON() {\n\t\tconst json = {};\n\n\t\t// Serializes attributes to the object.\n\t\t// attributes = { a: 'foo', b: 1, c: true }.\n\t\tif ( this._attrs.size ) {\n\t\t\tjson.attributes = Array.from( this._attrs ).reduce( ( result, attr ) => {\n\t\t\t\tresult[ attr[ 0 ] ] = attr[ 1 ];\n\n\t\t\t\treturn result;\n\t\t\t}, {} );\n\t\t}\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t * This method is useful when processing model objects that are of unknown type. For example, a function\n\t * may return a {@link module:engine/model/documentfragment~DocumentFragment} or a {@link module:engine/model/node~Node}\n\t * that can be either a text node or an element. This method can be used to check what kind of object is returned.\n\t *\n\t *\t\tsomeObject.is( 'element' ); // -> true if this is an element\n\t *\t\tsomeObject.is( 'node' ); // -> true if this is a node (a text node or an element)\n\t *\t\tsomeObject.is( 'documentFragment' ); // -> true if this is a document fragment\n\t *\n\t * Since this method is also available on a range of view objects, you can prefix the type of the object with\n\t * `model:` or `view:` to check, for example, if this is the model's or view's element:\n\t *\n\t *\t\tmodelElement.is( 'model:element' ); // -> true\n\t *\t\tmodelElement.is( 'view:element' ); // -> false\n\t *\n\t * By using this method it is also possible to check a name of an element:\n\t *\n\t *\t\timageElement.is( 'element', 'image' ); // -> true\n\t *\t\timageElement.is( 'element', 'image' ); // -> same as above\n\t *\t\timageElement.is( 'model:element', 'image' ); // -> same as above, but more precise\n\t *\n\t * The list of model objects which implement the `is()` method:\n\t *\n\t * * {@link module:engine/model/node~Node#is `Node#is()`}\n\t * * {@link module:engine/model/text~Text#is `Text#is()`}\n\t * * {@link module:engine/model/element~Element#is `Element#is()`}\n\t * * {@link module:engine/model/rootelement~RootElement#is `RootElement#is()`}\n\t * * {@link module:engine/model/position~Position#is `Position#is()`}\n\t * * {@link module:engine/model/liveposition~LivePosition#is `LivePosition#is()`}\n\t * * {@link module:engine/model/range~Range#is `Range#is()`}\n\t * * {@link module:engine/model/liverange~LiveRange#is `LiveRange#is()`}\n\t * * {@link module:engine/model/documentfragment~DocumentFragment#is `DocumentFragment#is()`}\n\t * * {@link module:engine/model/selection~Selection#is `Selection#is()`}\n\t * * {@link module:engine/model/documentselection~DocumentSelection#is `DocumentSelection#is()`}\n\t * * {@link module:engine/model/markercollection~Marker#is `Marker#is()`}\n\t * * {@link module:engine/model/textproxy~TextProxy#is `TextProxy#is()`}\n\t *\n\t * @method #is\n\t * @param {String} type Type to check.\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'node' || type === 'model:node';\n\t}\n\n\t/**\n\t * Creates a copy of this node, that is a node with exactly same attributes, and returns it.\n\t *\n\t * @protected\n\t * @returns {module:engine/model/node~Node} Node with same attributes as this node.\n\t */\n\t_clone() {\n\t\treturn new Node( this._attrs );\n\t}\n\n\t/**\n\t * Removes this node from it's parent.\n\t *\n\t * @see module:engine/model/writer~Writer#remove\n\t * @protected\n\t */\n\t_remove() {\n\t\tthis.parent._removeChildren( this.index );\n\t}\n\n\t/**\n\t * Sets attribute on the node. If attribute with the same key already is set, it's value is overwritten.\n\t *\n\t * @see module:engine/model/writer~Writer#setAttribute\n\t * @protected\n\t * @param {String} key Key of attribute to set.\n\t * @param {*} value Attribute value.\n\t */\n\t_setAttribute( key, value ) {\n\t\tthis._attrs.set( key, value );\n\t}\n\n\t/**\n\t * Removes all attributes from the node and sets given attributes.\n\t *\n\t * @see module:engine/model/writer~Writer#setAttributes\n\t * @protected\n\t * @param {Object} [attrs] Attributes to set. See {@link module:utils/tomap~toMap} for a list of accepted values.\n\t */\n\t_setAttributesTo( attrs ) {\n\t\tthis._attrs = toMap( attrs );\n\t}\n\n\t/**\n\t * Removes an attribute with given key from the node.\n\t *\n\t * @see module:engine/model/writer~Writer#removeAttribute\n\t * @protected\n\t * @param {String} key Key of attribute to remove.\n\t * @returns {Boolean} `true` if the attribute was set on the element, `false` otherwise.\n\t */\n\t_removeAttribute( key ) {\n\t\treturn this._attrs.delete( key );\n\t}\n\n\t/**\n\t * Removes all attributes from the node.\n\t *\n\t * @see module:engine/model/writer~Writer#clearAttributes\n\t * @protected\n\t */\n\t_clearAttributes() {\n\t\tthis._attrs.clear();\n\t}\n}\n\n/**\n * The node's parent does not contain this node.\n *\n * @error model-node-not-found-in-parent\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/text\n */\n\nimport Node from './node';\n\n// @if CK_DEBUG_ENGINE // const { convertMapToStringifiedObject } = require( '../dev-utils/utils' );\n\n/**\n * Model text node. Type of {@link module:engine/model/node~Node node} that contains {@link module:engine/model/text~Text#data text data}.\n *\n * **Important:** see {@link module:engine/model/node~Node} to read about restrictions using `Text` and `Node` API.\n *\n * **Note:** keep in mind that `Text` instances might indirectly got removed from model tree when model is changed.\n * This happens when {@link module:engine/model/writer~Writer model writer} is used to change model and the text node is merged with\n * another text node. Then, both text nodes are removed and a new text node is inserted into the model. Because of\n * this behavior, keeping references to `Text` is not recommended. Instead, consider creating\n * {@link module:engine/model/liveposition~LivePosition live position} placed before the text node.\n *\n * @extends module:engine/model/node~Node\n */\nexport default class Text extends Node {\n\t/**\n\t * Creates a text node.\n\t *\n\t * **Note:** Constructor of this class shouldn't be used directly in the code.\n\t * Use the {@link module:engine/model/writer~Writer#createText} method instead.\n\t *\n\t * @protected\n\t * @param {String} data Node's text.\n\t * @param {Object} [attrs] Node's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.\n\t */\n\tconstructor( data, attrs ) {\n\t\tsuper( attrs );\n\n\t\t/**\n\t\t * Text data contained in this text node.\n\t\t *\n\t\t * @protected\n\t\t * @type {String}\n\t\t */\n\t\tthis._data = data || '';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget offsetSize() {\n\t\treturn this.data.length;\n\t}\n\n\t/**\n\t * Returns a text data contained in the node.\n\t *\n\t * @readonly\n\t * @type {String}\n\t */\n\tget data() {\n\t\treturn this._data;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\ttext.is( '$text' ); // -> true\n\t *\t\ttext.is( 'node' ); // -> true\n\t *\t\ttext.is( 'model:$text' ); // -> true\n\t *\t\ttext.is( 'model:node' ); // -> true\n\t *\n\t *\t\ttext.is( 'view:$text' ); // -> false\n\t *\t\ttext.is( 'documentSelection' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * **Note:** Until version 20.0.0 this method wasn't accepting `'$text'` type. The legacy `'text'` type is still\n\t * accepted for backward compatibility.\n\t *\n\t * @param {String} type Type to check.\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === '$text' || type === 'model:$text' ||\n\t\t\t// This are legacy values kept for backward compatibility.\n\t\t\ttype === 'text' || type === 'model:text' ||\n\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\ttype === 'node' || type === 'model:node';\n\t}\n\n\t/**\n\t * Converts `Text` instance to plain object and returns it.\n\t *\n\t * @returns {Object} `Text` instance converted to plain object.\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.data = this.data;\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Creates a copy of this text node and returns it. Created text node has same text data and attributes as original text node.\n\t *\n\t * @protected\n\t * @returns {module:engine/model/text~Text} `Text` instance created using given plain object.\n\t */\n\t_clone() {\n\t\treturn new Text( this.data, this.getAttributes() );\n\t}\n\n\t/**\n\t * Creates a `Text` instance from given plain object (i.e. parsed JSON string).\n\t *\n\t * @param {Object} json Plain object to be converted to `Text`.\n\t * @returns {module:engine/model/text~Text} `Text` instance created using given plain object.\n\t */\n\tstatic fromJSON( json ) {\n\t\treturn new Text( json.data, json.attributes );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `#${ this.data }`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logExtended() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( `ModelText: ${ this }, attrs: ${ convertMapToStringifiedObject( this.getAttributes() ) }` );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelText: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/textproxy\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n// @if CK_DEBUG_ENGINE // const { convertMapToStringifiedObject } = require( '../dev-utils/utils' );\n\n/**\n * `TextProxy` represents a part of {@link module:engine/model/text~Text text node}.\n *\n * Since {@link module:engine/model/position~Position positions} can be placed between characters of a text node,\n * {@link module:engine/model/range~Range ranges} may contain only parts of text nodes. When {@link module:engine/model/range~Range#getItems\n * getting items}\n * contained in such range, we need to represent a part of that text node, since returning the whole text node would be incorrect.\n * `TextProxy` solves this issue.\n *\n * `TextProxy` has an API similar to {@link module:engine/model/text~Text Text} and allows to do most of the common tasks performed\n * on model nodes.\n *\n * **Note:** Some `TextProxy` instances may represent whole text node, not just a part of it.\n * See {@link module:engine/model/textproxy~TextProxy#isPartial}.\n *\n * **Note:** `TextProxy` is not an instance of {@link module:engine/model/node~Node node}. Keep this in mind when using it as a\n * parameter of methods.\n *\n * **Note:** `TextProxy` is a readonly interface. If you want to perform changes on model data represented by a `TextProxy`\n * use {@link module:engine/model/writer~Writer model writer API}.\n *\n * **Note:** `TextProxy` instances are created on the fly, basing on the current state of model. Because of this, it is\n * highly unrecommended to store references to `TextProxy` instances. `TextProxy` instances are not refreshed when\n * model changes, so they might get invalidated. Instead, consider creating {@link module:engine/model/liveposition~LivePosition live\n * position}.\n *\n * `TextProxy` instances are created by {@link module:engine/model/treewalker~TreeWalker model tree walker}. You should not need to create\n * an instance of this class by your own.\n */\nexport default class TextProxy {\n\t/**\n\t * Creates a text proxy.\n\t *\n\t * @protected\n\t * @param {module:engine/model/text~Text} textNode Text node which part is represented by this text proxy.\n\t * @param {Number} offsetInText Offset in {@link module:engine/model/textproxy~TextProxy#textNode text node} from which the text proxy\n\t * starts.\n\t * @param {Number} length Text proxy length, that is how many text node's characters, starting from `offsetInText` it represents.\n\t * @constructor\n\t */\n\tconstructor( textNode, offsetInText, length ) {\n\t\t/**\n\t\t * Text node which part is represented by this text proxy.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/text~Text}\n\t\t */\n\t\tthis.textNode = textNode;\n\n\t\tif ( offsetInText < 0 || offsetInText > textNode.offsetSize ) {\n\t\t\t/**\n\t\t\t * Given `offsetInText` value is incorrect.\n\t\t\t *\n\t\t\t * @error model-textproxy-wrong-offsetintext\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-textproxy-wrong-offsetintext', this );\n\t\t}\n\n\t\tif ( length < 0 || offsetInText + length > textNode.offsetSize ) {\n\t\t\t/**\n\t\t\t * Given `length` value is incorrect.\n\t\t\t *\n\t\t\t * @error model-textproxy-wrong-length\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-textproxy-wrong-length', this );\n\t\t}\n\n\t\t/**\n\t\t * Text data represented by this text proxy.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.data = textNode.data.substring( offsetInText, offsetInText + length );\n\n\t\t/**\n\t\t * Offset in {@link module:engine/model/textproxy~TextProxy#textNode text node} from which the text proxy starts.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.offsetInText = offsetInText;\n\t}\n\n\t/**\n\t * Offset at which this text proxy starts in it's parent.\n\t *\n\t * @see module:engine/model/node~Node#startOffset\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget startOffset() {\n\t\treturn this.textNode.startOffset !== null ? this.textNode.startOffset + this.offsetInText : null;\n\t}\n\n\t/**\n\t * Offset size of this text proxy. Equal to the number of characters represented by the text proxy.\n\t *\n\t * @see module:engine/model/node~Node#offsetSize\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget offsetSize() {\n\t\treturn this.data.length;\n\t}\n\n\t/**\n\t * Offset at which this text proxy ends in it's parent.\n\t *\n\t * @see module:engine/model/node~Node#endOffset\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget endOffset() {\n\t\treturn this.startOffset !== null ? this.startOffset + this.offsetSize : null;\n\t}\n\n\t/**\n\t * Flag indicating whether `TextProxy` instance covers only part of the original {@link module:engine/model/text~Text text node}\n\t * (`true`) or the whole text node (`false`).\n\t *\n\t * This is `false` when text proxy starts at the very beginning of {@link module:engine/model/textproxy~TextProxy#textNode textNode}\n\t * ({@link module:engine/model/textproxy~TextProxy#offsetInText offsetInText} equals `0`) and text proxy sizes is equal to\n\t * text node size.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isPartial() {\n\t\treturn this.offsetSize !== this.textNode.offsetSize;\n\t}\n\n\t/**\n\t * Parent of this text proxy, which is same as parent of text node represented by this text proxy.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment|null}\n\t */\n\tget parent() {\n\t\treturn this.textNode.parent;\n\t}\n\n\t/**\n\t * Root of this text proxy, which is same as root of text node represented by this text proxy.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/node~Node|module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this.textNode.root;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\ttextProxy.is( '$textProxy' ); // -> true\n\t *\t\ttextProxy.is( 'model:$textProxy' ); // -> true\n\t *\n\t *\t\ttextProxy.is( 'view:$textProxy' ); // -> false\n\t *\t\ttextProxy.is( 'range' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * **Note:** Until version 20.0.0 this method wasn't accepting `'$textProxy'` type. The legacy `'textProxt'` type is still\n\t * accepted for backward compatibility.\n\t *\n\t * @param {String} type Type to check.\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === '$textProxy' || type === 'model:$textProxy' ||\n\t\t\t// This are legacy values kept for backward compatibility.\n\t\t\ttype === 'textProxy' || type === 'model:textProxy';\n\t}\n\n\t/**\n\t * Gets path to this text proxy.\n\t *\n\t * @see module:engine/model/node~Node#getPath\n\t * @returns {Array.<Number>}\n\t */\n\tgetPath() {\n\t\tconst path = this.textNode.getPath();\n\n\t\tif ( path.length > 0 ) {\n\t\t\tpath[ path.length - 1 ] += this.offsetInText;\n\t\t}\n\n\t\treturn path;\n\t}\n\n\t/**\n\t * Returns ancestors array of this text proxy.\n\t *\n\t * @param {Object} options Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` this text proxy will be also included in parent's array.\n\t * @param {Boolean} [options.parentFirst=false] When set to `true`, array will be sorted from text proxy parent to root element,\n\t * otherwise root element will be the first item in the array.\n\t * @returns {Array} Array with ancestors.\n\t */\n\tgetAncestors( options = { includeSelf: false, parentFirst: false } ) {\n\t\tconst ancestors = [];\n\t\tlet parent = options.includeSelf ? this : this.parent;\n\n\t\twhile ( parent ) {\n\t\t\tancestors[ options.parentFirst ? 'push' : 'unshift' ]( parent );\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn ancestors;\n\t}\n\n\t/**\n\t * Checks if this text proxy has an attribute for given key.\n\t *\n\t * @param {String} key Key of attribute to check.\n\t * @returns {Boolean} `true` if attribute with given key is set on text proxy, `false` otherwise.\n\t */\n\thasAttribute( key ) {\n\t\treturn this.textNode.hasAttribute( key );\n\t}\n\n\t/**\n\t * Gets an attribute value for given key or `undefined` if that attribute is not set on text proxy.\n\t *\n\t * @param {String} key Key of attribute to look for.\n\t * @returns {*} Attribute value or `undefined`.\n\t */\n\tgetAttribute( key ) {\n\t\treturn this.textNode.getAttribute( key );\n\t}\n\n\t/**\n\t * Returns iterator that iterates over this node's attributes. Attributes are returned as arrays containing two\n\t * items. First one is attribute key and second is attribute value.\n\t *\n\t * This format is accepted by native `Map` object and also can be passed in `Node` constructor.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\tgetAttributes() {\n\t\treturn this.textNode.getAttributes();\n\t}\n\n\t/**\n\t * Returns iterator that iterates over this node's attribute keys.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetAttributeKeys() {\n\t\treturn this.textNode.getAttributeKeys();\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `#${ this.data }`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelTextProxy: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logExtended() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( `ModelTextProxy: ${ this }, ` +\n\t// @if CK_DEBUG_ENGINE // \t\t`attrs: ${ convertMapToStringifiedObject( this.getAttributes() ) }` );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/nodelist\n */\n\nimport Node from './node';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Provides an interface to operate on a list of {@link module:engine/model/node~Node nodes}. `NodeList` is used internally\n * in classes like {@link module:engine/model/element~Element Element}\n * or {@link module:engine/model/documentfragment~DocumentFragment DocumentFragment}.\n */\nexport default class NodeList {\n\t/**\n\t * Creates an empty node list.\n\t *\n\t * @protected\n\t * @param {Iterable.<module:engine/model/node~Node>} nodes Nodes contained in this node list.\n\t */\n\tconstructor( nodes ) {\n\t\t/**\n\t\t * Nodes contained in this node list.\n\t\t *\n\t\t * @private\n\t\t * @member {Array.<module:engine/model/node~Node>}\n\t\t */\n\t\tthis._nodes = [];\n\n\t\tif ( nodes ) {\n\t\t\tthis._insertNodes( 0, nodes );\n\t\t}\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over all nodes contained inside this node list.\n\t *\n\t * @returns {Iterable.<module:engine/model/node~Node>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._nodes[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Number of nodes contained inside this node list.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget length() {\n\t\treturn this._nodes.length;\n\t}\n\n\t/**\n\t * Sum of {@link module:engine/model/node~Node#offsetSize offset sizes} of all nodes contained inside this node list.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget maxOffset() {\n\t\treturn this._nodes.reduce( ( sum, node ) => sum + node.offsetSize, 0 );\n\t}\n\n\t/**\n\t * Gets the node at the given index. Returns `null` if incorrect index was passed.\n\t *\n\t * @param {Number} index Index of node.\n\t * @returns {module:engine/model/node~Node|null} Node at given index.\n\t */\n\tgetNode( index ) {\n\t\treturn this._nodes[ index ] || null;\n\t}\n\n\t/**\n\t * Returns an index of the given node. Returns `null` if given node is not inside this node list.\n\t *\n\t * @param {module:engine/model/node~Node} node Child node to look for.\n\t * @returns {Number|null} Child node's index.\n\t */\n\tgetNodeIndex( node ) {\n\t\tconst index = this._nodes.indexOf( node );\n\n\t\treturn index == -1 ? null : index;\n\t}\n\n\t/**\n\t * Returns the starting offset of given node. Starting offset is equal to the sum of\n\t * {@link module:engine/model/node~Node#offsetSize offset sizes} of all nodes that are before this node in this node list.\n\t *\n\t * @param {module:engine/model/node~Node} node Node to look for.\n\t * @returns {Number|null} Node's starting offset.\n\t */\n\tgetNodeStartOffset( node ) {\n\t\tconst index = this.getNodeIndex( node );\n\n\t\treturn index === null ? null : this._nodes.slice( 0, index ).reduce( ( sum, node ) => sum + node.offsetSize, 0 );\n\t}\n\n\t/**\n\t * Converts index to offset in node list.\n\t *\n\t * Returns starting offset of a node that is at given index. Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError}\n\t * `model-nodelist-index-out-of-bounds` if given index is less than `0` or more than {@link #length}.\n\t *\n\t * @param {Number} index Node's index.\n\t * @returns {Number} Node's starting offset.\n\t */\n\tindexToOffset( index ) {\n\t\tif ( index == this._nodes.length ) {\n\t\t\treturn this.maxOffset;\n\t\t}\n\n\t\tconst node = this._nodes[ index ];\n\n\t\tif ( !node ) {\n\t\t\t/**\n\t\t\t * Given index cannot be found in the node list.\n\t\t\t *\n\t\t\t * @error model-nodelist-index-out-of-bounds\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-nodelist-index-out-of-bounds', this );\n\t\t}\n\n\t\treturn this.getNodeStartOffset( node );\n\t}\n\n\t/**\n\t * Converts offset in node list to index.\n\t *\n\t * Returns index of a node that occupies given offset. Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError}\n\t * `model-nodelist-offset-out-of-bounds` if given offset is less than `0` or more than {@link #maxOffset}.\n\t *\n\t * @param {Number} offset Offset to look for.\n\t * @returns {Number} Index of a node that occupies given offset.\n\t */\n\toffsetToIndex( offset ) {\n\t\tlet totalOffset = 0;\n\n\t\tfor ( const node of this._nodes ) {\n\t\t\tif ( offset >= totalOffset && offset < totalOffset + node.offsetSize ) {\n\t\t\t\treturn this.getNodeIndex( node );\n\t\t\t}\n\n\t\t\ttotalOffset += node.offsetSize;\n\t\t}\n\n\t\tif ( totalOffset != offset ) {\n\t\t\t/**\n\t\t\t * Given offset cannot be found in the node list.\n\t\t\t *\n\t\t\t * @error model-nodelist-offset-out-of-bounds\n\t\t\t * @param {Number} offset\n\t\t\t * @param {module:engine/model/nodelist~NodeList} nodeList Stringified node list.\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-nodelist-offset-out-of-bounds',\n\t\t\t\tthis,\n\t\t\t\t{\n\t\t\t\t\toffset,\n\t\t\t\t\tnodeList: this\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\treturn this.length;\n\t}\n\n\t/**\n\t * Inserts given nodes at given index.\n\t *\n\t * @protected\n\t * @param {Number} index Index at which nodes should be inserted.\n\t * @param {Iterable.<module:engine/model/node~Node>} nodes Nodes to be inserted.\n\t */\n\t_insertNodes( index, nodes ) {\n\t\t// Validation.\n\t\tfor ( const node of nodes ) {\n\t\t\tif ( !( node instanceof Node ) ) {\n\t\t\t\t/**\n\t\t\t\t * Trying to insert an object which is not a Node instance.\n\t\t\t\t *\n\t\t\t\t * @error model-nodelist-insertnodes-not-node\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'model-nodelist-insertnodes-not-node', this );\n\t\t\t}\n\t\t}\n\n\t\tthis._nodes.splice( index, 0, ...nodes );\n\t}\n\n\t/**\n\t * Removes one or more nodes starting at the given index.\n\t *\n\t * @protected\n\t * @param {Number} indexStart Index of the first node to remove.\n\t * @param {Number} [howMany=1] Number of nodes to remove.\n\t * @returns {Array.<module:engine/model/node~Node>} Array containing removed nodes.\n\t */\n\t_removeNodes( indexStart, howMany = 1 ) {\n\t\treturn this._nodes.splice( indexStart, howMany );\n\t}\n\n\t/**\n\t * Converts `NodeList` instance to an array containing nodes that were inserted in the node list. Nodes\n\t * are also converted to their plain object representation.\n\t *\n\t * @returns {Array.<module:engine/model/node~Node>} `NodeList` instance converted to `Array`.\n\t */\n\ttoJSON() {\n\t\treturn this._nodes.map( node => node.toJSON() );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/element\n */\n\nimport Node from './node';\nimport NodeList from './nodelist';\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\n\n// @if CK_DEBUG_ENGINE // const { stringifyMap, convertMapToStringifiedObject, convertMapToTags } = require( '../dev-utils/utils' );\n\n/**\n * Model element. Type of {@link module:engine/model/node~Node node} that has a {@link module:engine/model/element~Element#name name} and\n * {@link module:engine/model/element~Element#getChildren child nodes}.\n *\n * **Important**: see {@link module:engine/model/node~Node} to read about restrictions using `Element` and `Node` API.\n *\n * @extends module:engine/model/node~Node\n */\nexport default class Element extends Node {\n\t/**\n\t * Creates a model element.\n\t *\n\t * **Note:** Constructor of this class shouldn't be used directly in the code.\n\t * Use the {@link module:engine/model/writer~Writer#createElement} method instead.\n\t *\n\t * @protected\n\t * @param {String} name Element's name.\n\t * @param {Object} [attrs] Element's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.\n\t * @param {module:engine/model/node~Node|Iterable.<module:engine/model/node~Node>} [children]\n\t * One or more nodes to be inserted as children of created element.\n\t */\n\tconstructor( name, attrs, children ) {\n\t\tsuper( attrs );\n\n\t\t/**\n\t\t * Element name.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} module:engine/model/element~Element#name\n\t\t */\n\t\tthis.name = name;\n\n\t\t/**\n\t\t * List of children nodes.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/nodelist~NodeList} module:engine/model/element~Element#_children\n\t\t */\n\t\tthis._children = new NodeList();\n\n\t\tif ( children ) {\n\t\t\tthis._insertChild( 0, children );\n\t\t}\n\t}\n\n\t/**\n\t * Number of this element's children.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget childCount() {\n\t\treturn this._children.length;\n\t}\n\n\t/**\n\t * Sum of {@link module:engine/model/node~Node#offsetSize offset sizes} of all of this element's children.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget maxOffset() {\n\t\treturn this._children.maxOffset;\n\t}\n\n\t/**\n\t * Is `true` if there are no nodes inside this element, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isEmpty() {\n\t\treturn this.childCount === 0;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\telement.is( 'element' ); // -> true\n\t *\t\telement.is( 'node' ); // -> true\n\t *\t\telement.is( 'model:element' ); // -> true\n\t *\t\telement.is( 'model:node' ); // -> true\n\t *\n\t *\t\telement.is( 'view:element' ); // -> false\n\t *\t\telement.is( 'documentSelection' ); // -> false\n\t *\n\t * Assuming that the object being checked is an element, you can also check its\n\t * {@link module:engine/model/element~Element#name name}:\n\t *\n\t *\t\telement.is( 'element', 'image' ); // -> true if this is an <image> element\n\t *\t\telement.is( 'element', 'image' ); // -> same as above\n\t *\t\ttext.is( 'element', 'image' ); -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'element' || type === 'model:element' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'node' || type === 'model:node';\n\t\t}\n\n\t\treturn name === this.name && ( type === 'element' || type === 'model:element' );\n\t}\n\n\t/**\n\t * Gets the child at the given index.\n\t *\n\t * @param {Number} index Index of child.\n\t * @returns {module:engine/model/node~Node} Child node.\n\t */\n\tgetChild( index ) {\n\t\treturn this._children.getNode( index );\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all of this element's children.\n\t *\n\t * @returns {Iterable.<module:engine/model/node~Node>}\n\t */\n\tgetChildren() {\n\t\treturn this._children[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Returns an index of the given child node. Returns `null` if given node is not a child of this element.\n\t *\n\t * @param {module:engine/model/node~Node} node Child node to look for.\n\t * @returns {Number} Child node's index in this element.\n\t */\n\tgetChildIndex( node ) {\n\t\treturn this._children.getNodeIndex( node );\n\t}\n\n\t/**\n\t * Returns the starting offset of given child. Starting offset is equal to the sum of\n\t * {@link module:engine/model/node~Node#offsetSize offset sizes} of all node's siblings that are before it. Returns `null` if\n\t * given node is not a child of this element.\n\t *\n\t * @param {module:engine/model/node~Node} node Child node to look for.\n\t * @returns {Number} Child node's starting offset.\n\t */\n\tgetChildStartOffset( node ) {\n\t\treturn this._children.getNodeStartOffset( node );\n\t}\n\n\t/**\n\t * Returns index of a node that occupies given offset. If given offset is too low, returns `0`. If given offset is\n\t * too high, returns {@link module:engine/model/element~Element#getChildIndex index after last child}.\n\t *\n\t *\t\tconst textNode = new Text( 'foo' );\n\t *\t\tconst pElement = new Element( 'p' );\n\t *\t\tconst divElement = new Element( [ textNode, pElement ] );\n\t *\t\tdivElement.offsetToIndex( -1 ); // Returns 0, because offset is too low.\n\t *\t\tdivElement.offsetToIndex( 0 ); // Returns 0, because offset 0 is taken by `textNode` which is at index 0.\n\t *\t\tdivElement.offsetToIndex( 1 ); // Returns 0, because `textNode` has `offsetSize` equal to 3, so it occupies offset 1 too.\n\t *\t\tdivElement.offsetToIndex( 2 ); // Returns 0.\n\t *\t\tdivElement.offsetToIndex( 3 ); // Returns 1.\n\t *\t\tdivElement.offsetToIndex( 4 ); // Returns 2. There are no nodes at offset 4, so last available index is returned.\n\t *\n\t * @param {Number} offset Offset to look for.\n\t * @returns {Number}\n\t */\n\toffsetToIndex( offset ) {\n\t\treturn this._children.offsetToIndex( offset );\n\t}\n\n\t/**\n\t * Returns a descendant node by its path relative to this element.\n\t *\n\t *\t\t// <this>a<b>c</b></this>\n\t *\t\tthis.getNodeByPath( [ 0 ] );     // -> \"a\"\n\t *\t\tthis.getNodeByPath( [ 1 ] );     // -> <b>\n\t *\t\tthis.getNodeByPath( [ 1, 0 ] );  // -> \"c\"\n\t *\n\t * @param {Array.<Number>} relativePath Path of the node to find, relative to this element.\n\t * @returns {module:engine/model/node~Node}\n\t */\n\tgetNodeByPath( relativePath ) {\n\t\tlet node = this; // eslint-disable-line consistent-this\n\n\t\tfor ( const index of relativePath ) {\n\t\t\tnode = node.getChild( node.offsetToIndex( index ) );\n\t\t}\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Returns the parent element of the given name. Returns null if the element is not inside the desired parent.\n\t *\n\t * @param {String} parentName The name of the parent element to find.\n\t * @param {Object} [options] Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` this node will be also included while searching.\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\tfindAncestor( parentName, options = { includeSelf: false } ) {\n\t\tlet parent = options.includeSelf ? this : this.parent;\n\n\t\twhile ( parent ) {\n\t\t\tif ( parent.name === parentName ) {\n\t\t\t\treturn parent;\n\t\t\t}\n\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Converts `Element` instance to plain object and returns it. Takes care of converting all of this element's children.\n\t *\n\t * @returns {Object} `Element` instance converted to plain object.\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.name = this.name;\n\n\t\tif ( this._children.length > 0 ) {\n\t\t\tjson.children = [];\n\n\t\t\tfor ( const node of this._children ) {\n\t\t\t\tjson.children.push( node.toJSON() );\n\t\t\t}\n\t\t}\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Creates a copy of this element and returns it. Created element has the same name and attributes as the original element.\n\t * If clone is deep, the original element's children are also cloned. If not, then empty element is returned.\n\t *\n\t * @protected\n\t * @param {Boolean} [deep=false] If set to `true` clones element and all its children recursively. When set to `false`,\n\t * element will be cloned without any child.\n\t */\n\t_clone( deep = false ) {\n\t\tconst children = deep ? Array.from( this._children ).map( node => node._clone( true ) ) : null;\n\n\t\treturn new Element( this.name, this.getAttributes(), children );\n\t}\n\n\t/**\n\t * {@link module:engine/model/element~Element#_insertChild Inserts} one or more nodes at the end of this element.\n\t *\n\t * @see module:engine/model/writer~Writer#append\n\t * @protected\n\t * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} nodes Nodes to be inserted.\n\t */\n\t_appendChild( nodes ) {\n\t\tthis._insertChild( this.childCount, nodes );\n\t}\n\n\t/**\n\t * Inserts one or more nodes at the given index and sets {@link module:engine/model/node~Node#parent parent} of these nodes\n\t * to this element.\n\t *\n\t * @see module:engine/model/writer~Writer#insert\n\t * @protected\n\t * @param {Number} index Index at which nodes should be inserted.\n\t * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} items Items to be inserted.\n\t */\n\t_insertChild( index, items ) {\n\t\tconst nodes = normalize( items );\n\n\t\tfor ( const node of nodes ) {\n\t\t\t// If node that is being added to this element is already inside another element, first remove it from the old parent.\n\t\t\tif ( node.parent !== null ) {\n\t\t\t\tnode._remove();\n\t\t\t}\n\n\t\t\tnode.parent = this;\n\t\t}\n\n\t\tthis._children._insertNodes( index, nodes );\n\t}\n\n\t/**\n\t * Removes one or more nodes starting at the given index and sets\n\t * {@link module:engine/model/node~Node#parent parent} of these nodes to `null`.\n\t *\n\t * @see module:engine/model/writer~Writer#remove\n\t * @protected\n\t * @param {Number} index Index of the first node to remove.\n\t * @param {Number} [howMany=1] Number of nodes to remove.\n\t * @returns {Array.<module:engine/model/node~Node>} Array containing removed nodes.\n\t */\n\t_removeChildren( index, howMany = 1 ) {\n\t\tconst nodes = this._children._removeNodes( index, howMany );\n\n\t\tfor ( const node of nodes ) {\n\t\t\tnode.parent = null;\n\t\t}\n\n\t\treturn nodes;\n\t}\n\n\t/**\n\t * Creates an `Element` instance from given plain object (i.e. parsed JSON string).\n\t * Converts `Element` children to proper nodes.\n\t *\n\t * @param {Object} json Plain object to be converted to `Element`.\n\t * @returns {module:engine/model/element~Element} `Element` instance created using given plain object.\n\t */\n\tstatic fromJSON( json ) {\n\t\tlet children = null;\n\n\t\tif ( json.children ) {\n\t\t\tchildren = [];\n\n\t\t\tfor ( const child of json.children ) {\n\t\t\t\tif ( child.name ) {\n\t\t\t\t\t// If child has name property, it is an Element.\n\t\t\t\t\tchildren.push( Element.fromJSON( child ) );\n\t\t\t\t} else {\n\t\t\t\t\t// Otherwise, it is a Text node.\n\t\t\t\t\tchildren.push( Text.fromJSON( child ) );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn new Element( json.name, json.attributes, children );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `<${ this.rootName || this.name }>`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelElement: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logExtended() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( `ModelElement: ${ this }, ${ this.childCount } children,\n\t// @if CK_DEBUG_ENGINE //\t\tattrs: ${ convertMapToStringifiedObject( this.getAttributes() ) }` );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logAll() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( '--------------------' );\n\t// @if CK_DEBUG_ENGINE //\n\t// @if CK_DEBUG_ENGINE // \tthis.logExtended();\n\t// @if CK_DEBUG_ENGINE //\tconsole.log( 'List of children:' );\n\t// @if CK_DEBUG_ENGINE //\n\t// @if CK_DEBUG_ENGINE // \tfor ( const child of this.getChildren() ) {\n\t// @if CK_DEBUG_ENGINE // \t\tchild.log();\n\t// @if CK_DEBUG_ENGINE // \t}\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // printTree( level = 0) {\n\t// @if CK_DEBUG_ENGINE // \tlet string = '';\n\n\t// @if CK_DEBUG_ENGINE // \tstring += '\\t'.repeat( level );\n\t// @if CK_DEBUG_ENGINE // \tstring += `<${ this.rootName || this.name }${ convertMapToTags( this.getAttributes() ) }>`;\n\n\t// @if CK_DEBUG_ENGINE // \tfor ( const child of this.getChildren() ) {\n\t// @if CK_DEBUG_ENGINE // \t\tstring += '\\n';\n\n\t// @if CK_DEBUG_ENGINE // \t\tif ( child.is( '$text' ) ) {\n\t// @if CK_DEBUG_ENGINE // \t\t\tconst textAttrs = convertMapToTags( child._attrs );\n\n\t// @if CK_DEBUG_ENGINE // \t\t\tstring += '\\t'.repeat( level + 1 );\n\n\t// @if CK_DEBUG_ENGINE // \t\t\tif ( textAttrs !== '' ) {\n\t// @if CK_DEBUG_ENGINE // \t\t\t\tstring += `<$text${ textAttrs }>` + child.data + '</$text>';\n\t// @if CK_DEBUG_ENGINE // \t\t\t} else {\n\t// @if CK_DEBUG_ENGINE // \t\t\t\tstring += child.data;\n\t// @if CK_DEBUG_ENGINE // \t\t\t}\n\t// @if CK_DEBUG_ENGINE // \t\t} else {\n\t// @if CK_DEBUG_ENGINE // \t\t\tstring += child.printTree( level + 1 );\n\t// @if CK_DEBUG_ENGINE // \t\t}\n\t// @if CK_DEBUG_ENGINE // \t}\n\n\t// @if CK_DEBUG_ENGINE // \tif ( this.childCount ) {\n\t// @if CK_DEBUG_ENGINE // \t\tstring += '\\n' + '\\t'.repeat( level );\n\t// @if CK_DEBUG_ENGINE // \t}\n\n\t// @if CK_DEBUG_ENGINE // \tstring += `</${ this.rootName || this.name }>`;\n\n\t// @if CK_DEBUG_ENGINE // \treturn string;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logTree() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( this.printTree() );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\n// Converts strings to Text and non-iterables to arrays.\n//\n// @param {String|module:engine/model/item~Item|Iterable.<String|module:engine/model/item~Item>}\n// @returns {Iterable.<module:engine/model/node~Node>}\nfunction normalize( nodes ) {\n\t// Separate condition because string is iterable.\n\tif ( typeof nodes == 'string' ) {\n\t\treturn [ new Text( nodes ) ];\n\t}\n\n\tif ( !isIterable( nodes ) ) {\n\t\tnodes = [ nodes ];\n\t}\n\n\t// Array.from to enable .map() on non-arrays.\n\treturn Array.from( nodes )\n\t\t.map( node => {\n\t\t\tif ( typeof node == 'string' ) {\n\t\t\t\treturn new Text( node );\n\t\t\t}\n\n\t\t\tif ( node instanceof TextProxy ) {\n\t\t\t\treturn new Text( node.data, node.getAttributes() );\n\t\t\t}\n\n\t\t\treturn node;\n\t\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/treewalker\n */\n\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport Element from './element';\nimport {\n\tdefault as Position,\n\tgetTextNodeAtPosition,\n\tgetNodeAfterPosition,\n\tgetNodeBeforePosition\n} from './position';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Position iterator class. It allows to iterate forward and backward over the document.\n */\nexport default class TreeWalker {\n\t/**\n\t * Creates a range iterator. All parameters are optional, but you have to specify either `boundaries` or `startPosition`.\n\t *\n\t * @constructor\n\t * @param {Object} [options={}] Object with configuration.\n\t * @param {'forward'|'backward'} [options.direction='forward'] Walking direction.\n\t * @param {module:engine/model/range~Range} [options.boundaries=null] Range to define boundaries of the iterator.\n\t * @param {module:engine/model/position~Position} [options.startPosition] Starting position.\n\t * @param {Boolean} [options.singleCharacters=false] Flag indicating whether all consecutive characters with the same attributes\n\t * should be returned one by one as multiple {@link module:engine/model/textproxy~TextProxy} (`true`) objects or as one\n\t * {@link module:engine/model/textproxy~TextProxy} (`false`).\n\t * @param {Boolean} [options.shallow=false] Flag indicating whether iterator should enter elements or not. If the\n\t * iterator is shallow child nodes of any iterated node will not be returned along with `elementEnd` tag.\n\t * @param {Boolean} [options.ignoreElementEnd=false] Flag indicating whether iterator should ignore `elementEnd`\n\t * tags. If the option is true walker will not return a parent node of start position. If this option is `true`\n\t * each {@link module:engine/model/element~Element} will be returned once, while if the option is `false` they might be returned\n\t * twice: for `'elementStart'` and `'elementEnd'`.\n\t */\n\tconstructor( options = {} ) {\n\t\tif ( !options.boundaries && !options.startPosition ) {\n\t\t\t/**\n\t\t\t * Neither boundaries nor starting position of a `TreeWalker` have been defined.\n\t\t\t *\n\t\t\t * @error model-tree-walker-no-start-position\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-tree-walker-no-start-position',\n\t\t\t\tnull\n\t\t\t);\n\t\t}\n\n\t\tconst direction = options.direction || 'forward';\n\n\t\tif ( direction != 'forward' && direction != 'backward' ) {\n\t\t\t/**\n\t\t\t * Only `backward` and `forward` direction allowed.\n\t\t\t *\n\t\t\t * @error model-tree-walker-unknown-direction\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-tree-walker-unknown-direction', options, { direction } );\n\t\t}\n\n\t\t/**\n\t\t * Walking direction. Defaults `'forward'`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {'backward'|'forward'} module:engine/model/treewalker~TreeWalker#direction\n\t\t */\n\t\tthis.direction = direction;\n\n\t\t/**\n\t\t * Iterator boundaries.\n\t\t *\n\t\t * When the iterator is walking `'forward'` on the end of boundary or is walking `'backward'`\n\t\t * on the start of boundary, then `{ done: true }` is returned.\n\t\t *\n\t\t * If boundaries are not defined they are set before first and after last child of the root node.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/range~Range} module:engine/model/treewalker~TreeWalker#boundaries\n\t\t */\n\t\tthis.boundaries = options.boundaries || null;\n\n\t\t/**\n\t\t * Iterator position. This is always static position, even if the initial position was a\n\t\t * {@link module:engine/model/liveposition~LivePosition live position}. If start position is not defined then position depends\n\t\t * on {@link #direction}. If direction is `'forward'` position starts form the beginning, when direction\n\t\t * is `'backward'` position starts from the end.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/position~Position} module:engine/model/treewalker~TreeWalker#position\n\t\t */\n\t\tif ( options.startPosition ) {\n\t\t\tthis.position = options.startPosition.clone();\n\t\t} else {\n\t\t\tthis.position = Position._createAt( this.boundaries[ this.direction == 'backward' ? 'end' : 'start' ] );\n\t\t}\n\n\t\t// Reset position stickiness in case it was set to other value, as the stickiness is kept after cloning.\n\t\tthis.position.stickiness = 'toNone';\n\n\t\t/**\n\t\t * Flag indicating whether all consecutive characters with the same attributes should be\n\t\t * returned as one {@link module:engine/model/textproxy~TextProxy} (`true`) or one by one (`false`).\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/model/treewalker~TreeWalker#singleCharacters\n\t\t */\n\t\tthis.singleCharacters = !!options.singleCharacters;\n\n\t\t/**\n\t\t * Flag indicating whether iterator should enter elements or not. If the iterator is shallow child nodes of any\n\t\t * iterated node will not be returned along with `elementEnd` tag.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/model/treewalker~TreeWalker#shallow\n\t\t */\n\t\tthis.shallow = !!options.shallow;\n\n\t\t/**\n\t\t * Flag indicating whether iterator should ignore `elementEnd` tags. If the option is true walker will not\n\t\t * return a parent node of the start position. If this option is `true` each {@link module:engine/model/element~Element} will\n\t\t * be returned once, while if the option is `false` they might be returned twice:\n\t\t * for `'elementStart'` and `'elementEnd'`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/model/treewalker~TreeWalker#ignoreElementEnd\n\t\t */\n\t\tthis.ignoreElementEnd = !!options.ignoreElementEnd;\n\n\t\t/**\n\t\t * Start boundary cached for optimization purposes.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/element~Element} module:engine/model/treewalker~TreeWalker#_boundaryStartParent\n\t\t */\n\t\tthis._boundaryStartParent = this.boundaries ? this.boundaries.start.parent : null;\n\n\t\t/**\n\t\t * End boundary cached for optimization purposes.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/element~Element} module:engine/model/treewalker~TreeWalker#_boundaryEndParent\n\t\t */\n\t\tthis._boundaryEndParent = this.boundaries ? this.boundaries.end.parent : null;\n\n\t\t/**\n\t\t * Parent of the most recently visited node. Cached for optimization purposes.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment}\n\t\t * module:engine/model/treewalker~TreeWalker#_visitedParent\n\t\t */\n\t\tthis._visitedParent = this.position.parent;\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * @returns {Iterable.<module:engine/model/treewalker~TreeWalkerValue>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Moves {@link #position} in the {@link #direction} skipping values as long as the callback function returns `true`.\n\t *\n\t * For example:\n\t *\n\t * \t\twalker.skip( value => value.type == 'text' ); // <paragraph>[]foo</paragraph> -> <paragraph>foo[]</paragraph>\n\t * \t\twalker.skip( () => true ); // Move the position to the end: <paragraph>[]foo</paragraph> -> <paragraph>foo</paragraph>[]\n\t * \t\twalker.skip( () => false ); // Do not move the position.\n\t *\n\t * @param {Function} skip Callback function. Gets {@link module:engine/model/treewalker~TreeWalkerValue} and should\n\t * return `true` if the value should be skipped or `false` if not.\n\t */\n\tskip( skip ) {\n\t\tlet done, value, prevPosition, prevVisitedParent;\n\n\t\tdo {\n\t\t\tprevPosition = this.position;\n\t\t\tprevVisitedParent = this._visitedParent;\n\n\t\t\t( { done, value } = this.next() );\n\t\t} while ( !done && skip( value ) );\n\n\t\tif ( !done ) {\n\t\t\tthis.position = prevPosition;\n\t\t\tthis._visitedParent = prevVisitedParent;\n\t\t}\n\t}\n\n\t/**\n\t * Gets the next tree walker's value.\n\t *\n\t * @returns {module:engine/model/treewalker~TreeWalkerValue} Next tree walker's value.\n\t */\n\tnext() {\n\t\tif ( this.direction == 'forward' ) {\n\t\t\treturn this._next();\n\t\t} else {\n\t\t\treturn this._previous();\n\t\t}\n\t}\n\n\t/**\n\t * Makes a step forward in model. Moves the {@link #position} to the next position and returns the encountered value.\n\t *\n\t * @private\n\t * @returns {Object}\n\t * @returns {Boolean} return.done True if iterator is done.\n\t * @returns {module:engine/model/treewalker~TreeWalkerValue} return.value Information about taken step.\n\t */\n\t_next() {\n\t\tconst previousPosition = this.position;\n\t\tconst position = this.position.clone();\n\t\tconst parent = this._visitedParent;\n\n\t\t// We are at the end of the root.\n\t\tif ( parent.parent === null && position.offset === parent.maxOffset ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// We reached the walker boundary.\n\t\tif ( parent === this._boundaryEndParent && position.offset == this.boundaries.end.offset ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// Get node just after the current position.\n\t\t// Use a highly optimized version instead of checking the text node first and then getting the node after. See #6582.\n\t\tconst positionParent = position.parent;\n\t\tconst textNodeAtPosition = getTextNodeAtPosition( position, positionParent );\n\t\tconst node = textNodeAtPosition ? textNodeAtPosition : getNodeAfterPosition( position, positionParent, textNodeAtPosition );\n\n\t\tif ( node instanceof Element ) {\n\t\t\tif ( !this.shallow ) {\n\t\t\t\t// Manual operations on path internals for optimization purposes. Here and in the rest of the method.\n\t\t\t\tposition.path.push( 0 );\n\t\t\t\tthis._visitedParent = node;\n\t\t\t} else {\n\t\t\t\tposition.offset++;\n\t\t\t}\n\n\t\t\tthis.position = position;\n\n\t\t\treturn formatReturnValue( 'elementStart', node, previousPosition, position, 1 );\n\t\t} else if ( node instanceof Text ) {\n\t\t\tlet charactersCount;\n\n\t\t\tif ( this.singleCharacters ) {\n\t\t\t\tcharactersCount = 1;\n\t\t\t} else {\n\t\t\t\tlet offset = node.endOffset;\n\n\t\t\t\tif ( this._boundaryEndParent == parent && this.boundaries.end.offset < offset ) {\n\t\t\t\t\toffset = this.boundaries.end.offset;\n\t\t\t\t}\n\n\t\t\t\tcharactersCount = offset - position.offset;\n\t\t\t}\n\n\t\t\tconst offsetInTextNode = position.offset - node.startOffset;\n\t\t\tconst item = new TextProxy( node, offsetInTextNode, charactersCount );\n\n\t\t\tposition.offset += charactersCount;\n\t\t\tthis.position = position;\n\n\t\t\treturn formatReturnValue( 'text', item, previousPosition, position, charactersCount );\n\t\t} else {\n\t\t\t// `node` is not set, we reached the end of current `parent`.\n\t\t\tposition.path.pop();\n\t\t\tposition.offset++;\n\t\t\tthis.position = position;\n\t\t\tthis._visitedParent = parent.parent;\n\n\t\t\tif ( this.ignoreElementEnd ) {\n\t\t\t\treturn this._next();\n\t\t\t} else {\n\t\t\t\treturn formatReturnValue( 'elementEnd', parent, previousPosition, position );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Makes a step backward in model. Moves the {@link #position} to the previous position and returns the encountered value.\n\t *\n\t * @private\n\t * @returns {Object}\n\t * @returns {Boolean} return.done True if iterator is done.\n\t * @returns {module:engine/model/treewalker~TreeWalkerValue} return.value Information about taken step.\n\t */\n\t_previous() {\n\t\tconst previousPosition = this.position;\n\t\tconst position = this.position.clone();\n\t\tconst parent = this._visitedParent;\n\n\t\t// We are at the beginning of the root.\n\t\tif ( parent.parent === null && position.offset === 0 ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// We reached the walker boundary.\n\t\tif ( parent == this._boundaryStartParent && position.offset == this.boundaries.start.offset ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// Get node just before the current position.\n\t\t// Use a highly optimized version instead of checking the text node first and then getting the node before. See #6582.\n\t\tconst positionParent = position.parent;\n\t\tconst textNodeAtPosition = getTextNodeAtPosition( position, positionParent );\n\t\tconst node = textNodeAtPosition ? textNodeAtPosition : getNodeBeforePosition( position, positionParent, textNodeAtPosition );\n\n\t\tif ( node instanceof Element ) {\n\t\t\tposition.offset--;\n\n\t\t\tif ( !this.shallow ) {\n\t\t\t\tposition.path.push( node.maxOffset );\n\t\t\t\tthis.position = position;\n\t\t\t\tthis._visitedParent = node;\n\n\t\t\t\tif ( this.ignoreElementEnd ) {\n\t\t\t\t\treturn this._previous();\n\t\t\t\t} else {\n\t\t\t\t\treturn formatReturnValue( 'elementEnd', node, previousPosition, position );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.position = position;\n\n\t\t\t\treturn formatReturnValue( 'elementStart', node, previousPosition, position, 1 );\n\t\t\t}\n\t\t} else if ( node instanceof Text ) {\n\t\t\tlet charactersCount;\n\n\t\t\tif ( this.singleCharacters ) {\n\t\t\t\tcharactersCount = 1;\n\t\t\t} else {\n\t\t\t\tlet offset = node.startOffset;\n\n\t\t\t\tif ( this._boundaryStartParent == parent && this.boundaries.start.offset > offset ) {\n\t\t\t\t\toffset = this.boundaries.start.offset;\n\t\t\t\t}\n\n\t\t\t\tcharactersCount = position.offset - offset;\n\t\t\t}\n\n\t\t\tconst offsetInTextNode = position.offset - node.startOffset;\n\t\t\tconst item = new TextProxy( node, offsetInTextNode - charactersCount, charactersCount );\n\n\t\t\tposition.offset -= charactersCount;\n\t\t\tthis.position = position;\n\n\t\t\treturn formatReturnValue( 'text', item, previousPosition, position, charactersCount );\n\t\t} else {\n\t\t\t// `node` is not set, we reached the beginning of current `parent`.\n\t\t\tposition.path.pop();\n\t\t\tthis.position = position;\n\t\t\tthis._visitedParent = parent.parent;\n\n\t\t\treturn formatReturnValue( 'elementStart', parent, previousPosition, position, 1 );\n\t\t}\n\t}\n}\n\nfunction formatReturnValue( type, item, previousPosition, nextPosition, length ) {\n\treturn {\n\t\tdone: false,\n\t\tvalue: {\n\t\t\ttype,\n\t\t\titem,\n\t\t\tpreviousPosition,\n\t\t\tnextPosition,\n\t\t\tlength\n\t\t}\n\t};\n}\n\n/**\n * Type of the step made by {@link module:engine/model/treewalker~TreeWalker}.\n * Possible values: `'elementStart'` if walker is at the beginning of a node, `'elementEnd'` if walker is at the end of node,\n * `'character'` if walker traversed over a character, or `'text'` if walker traversed over multiple characters (available in\n * character merging mode, see {@link module:engine/model/treewalker~TreeWalker#constructor}).\n *\n * @typedef {'elementStart'|'elementEnd'|'character'|'text'} module:engine/model/treewalker~TreeWalkerValueType\n */\n\n/**\n * Object returned by {@link module:engine/model/treewalker~TreeWalker} when traversing tree model.\n *\n * @typedef {Object} module:engine/model/treewalker~TreeWalkerValue\n * @property {module:engine/model/treewalker~TreeWalkerValueType} type\n * @property {module:engine/model/item~Item} item Item between old and new positions of {@link module:engine/model/treewalker~TreeWalker}.\n * @property {module:engine/model/position~Position} previousPosition Previous position of the iterator.\n * * Forward iteration: For `'elementEnd'` it is the last position inside the element. For all other types it is the\n * position before the item.\n * * Backward iteration: For `'elementStart'` it is the first position inside the element. For all other types it is\n * the position after item.\n * @property {module:engine/model/position~Position} nextPosition Next position of the iterator.\n * * Forward iteration: For `'elementStart'` it is the first position inside the element. For all other types it is\n * the position after the item.\n * * Backward iteration: For `'elementEnd'` it is last position inside element. For all other types it is the position\n * before the item.\n * @property {Number} [length] Length of the item. For `'elementStart'` and `'character'` it is 1. For `'text'` it is\n * the length of the text. For `'elementEnd'` it is `undefined`.\n */\n\n/**\n * Tree walking directions.\n *\n * @typedef {'forward'|'backward'} module:engine/model/treewalker~TreeWalkerDirection\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/position\n */\n\nimport TreeWalker from './treewalker';\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n// To check if component is loaded more than once.\nimport '@ckeditor/ckeditor5-utils/src/version';\n\n/**\n * Represents a position in the model tree.\n *\n * A position is represented by its {@link module:engine/model/position~Position#root} and\n * a {@link module:engine/model/position~Position#path} in that root.\n *\n * You can create position instances via its constructor or the `createPosition*()` factory methods of\n * {@link module:engine/model/model~Model} and {@link module:engine/model/writer~Writer}.\n *\n * **Note:** Position is based on offsets, not indexes. This means that a position between two text nodes\n * `foo` and `bar` has offset `3`, not `1`. See {@link module:engine/model/position~Position#path} for more information.\n *\n * Since a position in the model is represented by a {@link module:engine/model/position~Position#root position root} and\n * {@link module:engine/model/position~Position#path position path} it is possible to create positions placed in non-existing places.\n * This requirement is important for operational transformation algorithms.\n *\n * Also, {@link module:engine/model/operation/operation~Operation operations}\n * kept in the {@link module:engine/model/document~Document#history document history}\n * are storing positions (and ranges) which were correct when those operations were applied, but may not be correct\n * after the document has changed.\n *\n * When changes are applied to the model, it may also happen that {@link module:engine/model/position~Position#parent position parent}\n * will change even if position path has not changed. Keep in mind, that if a position leads to non-existing element,\n * {@link module:engine/model/position~Position#parent} and some other properties and methods will throw errors.\n *\n * In most cases, position with wrong path is caused by an error in code, but it is sometimes needed, as described above.\n */\nexport default class Position {\n\t/**\n\t * Creates a position.\n\t *\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} root Root of the position.\n\t * @param {Array.<Number>} path Position path. See {@link module:engine/model/position~Position#path}.\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone'] Position stickiness.\n\t * See {@link module:engine/model/position~PositionStickiness}.\n\t */\n\tconstructor( root, path, stickiness = 'toNone' ) {\n\t\tif ( !root.is( 'element' ) && !root.is( 'documentFragment' ) ) {\n\t\t\t/**\n\t\t\t * Position root is invalid.\n\t\t\t *\n\t\t\t * Positions can only be anchored in elements or document fragments.\n\t\t\t *\n\t\t\t * @error model-position-root-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-position-root-invalid',\n\t\t\t\troot\n\t\t\t);\n\t\t}\n\n\t\tif ( !( path instanceof Array ) || path.length === 0 ) {\n\t\t\t/**\n\t\t\t * Position path must be an array with at least one item.\n\t\t\t *\n\t\t\t * @error model-position-path-incorrect-format\n\t\t\t * @param path\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-position-path-incorrect-format',\n\t\t\t\troot,\n\t\t\t\t{ path }\n\t\t\t);\n\t\t}\n\n\t\t// Normalize the root and path when element (not root) is passed.\n\t\tif ( root.is( 'rootElement' ) ) {\n\t\t\tpath = path.slice();\n\t\t} else {\n\t\t\tpath = [ ...root.getPath(), ...path ];\n\t\t\troot = root.root;\n\t\t}\n\n\t\t/**\n\t\t * Root of the position path.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment}\n\t\t * module:engine/model/position~Position#root\n\t\t */\n\t\tthis.root = root;\n\n\t\t/**\n\t\t * Position of the node in the tree. **Path contains offsets, not indexes.**\n\t\t *\n\t\t * Position can be placed before, after or in a {@link module:engine/model/node~Node node} if that node has\n\t\t * {@link module:engine/model/node~Node#offsetSize} greater than `1`. Items in position path are\n\t\t * {@link module:engine/model/node~Node#startOffset starting offsets} of position ancestors, starting from direct root children,\n\t\t * down to the position offset in it's parent.\n\t\t *\n\t\t *\t\t ROOT\n\t\t *\t\t  |- P            before: [ 0 ]         after: [ 1 ]\n\t\t *\t\t  |- UL           before: [ 1 ]         after: [ 2 ]\n\t\t *\t\t     |- LI        before: [ 1, 0 ]      after: [ 1, 1 ]\n\t\t *\t\t     |  |- foo    before: [ 1, 0, 0 ]   after: [ 1, 0, 3 ]\n\t\t *\t\t     |- LI        before: [ 1, 1 ]      after: [ 1, 2 ]\n\t\t *\t\t        |- bar    before: [ 1, 1, 0 ]   after: [ 1, 1, 3 ]\n\t\t *\n\t\t * `foo` and `bar` are representing {@link module:engine/model/text~Text text nodes}. Since text nodes has offset size\n\t\t * greater than `1` you can place position offset between their start and end:\n\t\t *\n\t\t *\t\t ROOT\n\t\t *\t\t  |- P\n\t\t *\t\t  |- UL\n\t\t *\t\t     |- LI\n\t\t *\t\t     |  |- f^o|o  ^ has path: [ 1, 0, 1 ]   | has path: [ 1, 0, 2 ]\n\t\t *\t\t     |- LI\n\t\t *\t\t        |- b^a|r  ^ has path: [ 1, 1, 1 ]   | has path: [ 1, 1, 2 ]\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<Number>} module:engine/model/position~Position#path\n\t\t */\n\t\tthis.path = path;\n\n\t\t/**\n\t\t * Position stickiness. See {@link module:engine/model/position~PositionStickiness}.\n\t\t *\n\t\t * @member {module:engine/model/position~PositionStickiness} module:engine/model/position~Position#stickiness\n\t\t */\n\t\tthis.stickiness = stickiness;\n\t}\n\n\t/**\n\t * Offset at which this position is located in its {@link module:engine/model/position~Position#parent parent}. It is equal\n\t * to the last item in position {@link module:engine/model/position~Position#path path}.\n\t *\n\t * @type {Number}\n\t */\n\tget offset() {\n\t\treturn this.path[ this.path.length - 1 ];\n\t}\n\n\tset offset( newOffset ) {\n\t\tthis.path[ this.path.length - 1 ] = newOffset;\n\t}\n\n\t/**\n\t * Parent element of this position.\n\t *\n\t * Keep in mind that `parent` value is calculated when the property is accessed.\n\t * If {@link module:engine/model/position~Position#path position path}\n\t * leads to a non-existing element, `parent` property will throw error.\n\t *\n\t * Also it is a good idea to cache `parent` property if it is used frequently in an algorithm (i.e. in a long loop).\n\t *\n\t * @readonly\n\t * @type {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget parent() {\n\t\tlet parent = this.root;\n\n\t\tfor ( let i = 0; i < this.path.length - 1; i++ ) {\n\t\t\tparent = parent.getChild( parent.offsetToIndex( this.path[ i ] ) );\n\n\t\t\tif ( !parent ) {\n\t\t\t\t/**\n\t\t\t\t * The position's path is incorrect. This means that a position does not point to\n\t\t\t\t * a correct place in the tree and hence, some of its methods and getters cannot work correctly.\n\t\t\t\t *\n\t\t\t\t * **Note**: Unlike DOM and view positions, in the model, the\n\t\t\t\t * {@link module:engine/model/position~Position#parent position's parent} is always an element or a document fragment.\n\t\t\t\t * The last offset in the {@link module:engine/model/position~Position#path position's path} is the point in this element\n\t\t\t\t * where this position points.\n\t\t\t\t *\n\t\t\t\t * Read more about model positions and offsets in\n\t\t\t\t * the {@glink framework/guides/architecture/editing-engine#indexes-and-offsets Editing engine architecture guide}.\n\t\t\t\t *\n\t\t\t\t * @error model-position-path-incorrect\n\t\t\t\t * @param {module:engine/model/position~Position} position The incorrect position.\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'model-position-path-incorrect', this, { position: this } );\n\t\t\t}\n\t\t}\n\n\t\tif ( parent.is( '$text' ) ) {\n\t\t\tthrow new CKEditorError( 'model-position-path-incorrect', this, { position: this } );\n\t\t}\n\n\t\treturn parent;\n\t}\n\n\t/**\n\t * Position {@link module:engine/model/position~Position#offset offset} converted to an index in position's parent node. It is\n\t * equal to the {@link module:engine/model/node~Node#index index} of a node after this position. If position is placed\n\t * in text node, position index is equal to the index of that text node.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget index() {\n\t\treturn this.parent.offsetToIndex( this.offset );\n\t}\n\n\t/**\n\t * Returns {@link module:engine/model/text~Text text node} instance in which this position is placed or `null` if this\n\t * position is not in a text node.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/text~Text|null}\n\t */\n\tget textNode() {\n\t\treturn getTextNodeAtPosition( this, this.parent );\n\t}\n\n\t/**\n\t * Node directly after this position or `null` if this position is in text node.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/node~Node|null}\n\t */\n\tget nodeAfter() {\n\t\t// Cache the parent and reuse for performance reasons. See #6579 and #6582.\n\t\tconst parent = this.parent;\n\n\t\treturn getNodeAfterPosition( this, parent, getTextNodeAtPosition( this, parent ) );\n\t}\n\n\t/**\n\t * Node directly before this position or `null` if this position is in text node.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/node~Node|null}\n\t */\n\tget nodeBefore() {\n\t\t// Cache the parent and reuse for performance reasons. See #6579 and #6582.\n\t\tconst parent = this.parent;\n\n\t\treturn getNodeBeforePosition( this, parent, getTextNodeAtPosition( this, parent ) );\n\t}\n\n\t/**\n\t * Is `true` if position is at the beginning of its {@link module:engine/model/position~Position#parent parent}, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isAtStart() {\n\t\treturn this.offset === 0;\n\t}\n\n\t/**\n\t * Is `true` if position is at the end of its {@link module:engine/model/position~Position#parent parent}, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isAtEnd() {\n\t\treturn this.offset == this.parent.maxOffset;\n\t}\n\n\t/**\n\t * Checks whether this position is before or after given position.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {module:engine/model/position~Position} otherPosition Position to compare with.\n\t * @returns {module:engine/model/position~PositionRelation}\n\t */\n\tcompareWith( otherPosition ) {\n\t\tif ( this.root != otherPosition.root ) {\n\t\t\treturn 'different';\n\t\t}\n\n\t\tconst result = compareArrays( this.path, otherPosition.path );\n\n\t\tswitch ( result ) {\n\t\t\tcase 'same':\n\t\t\t\treturn 'same';\n\n\t\t\tcase 'prefix':\n\t\t\t\treturn 'before';\n\n\t\t\tcase 'extension':\n\t\t\t\treturn 'after';\n\n\t\t\tdefault:\n\t\t\t\treturn this.path[ result ] < otherPosition.path[ result ] ? 'before' : 'after';\n\t\t}\n\t}\n\n\t/**\n\t * Gets the farthest position which matches the callback using\n\t * {@link module:engine/model/treewalker~TreeWalker TreeWalker}.\n\t *\n\t * For example:\n\t *\n\t * \t\tgetLastMatchingPosition( value => value.type == 'text' );\n\t * \t\t// <paragraph>[]foo</paragraph> -> <paragraph>foo[]</paragraph>\n\t *\n\t * \t\tgetLastMatchingPosition( value => value.type == 'text', { direction: 'backward' } );\n\t * \t\t// <paragraph>foo[]</paragraph> -> <paragraph>[]foo</paragraph>\n\t *\n\t * \t\tgetLastMatchingPosition( value => false );\n\t * \t\t// Do not move the position.\n\t *\n\t * @param {Function} skip Callback function. Gets {@link module:engine/model/treewalker~TreeWalkerValue} and should\n\t * return `true` if the value should be skipped or `false` if not.\n\t * @param {Object} options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.\n\t *\n\t * @returns {module:engine/model/position~Position} The position after the last item which matches the `skip` callback test.\n\t */\n\tgetLastMatchingPosition( skip, options = {} ) {\n\t\toptions.startPosition = this;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\t\ttreeWalker.skip( skip );\n\n\t\treturn treeWalker.position;\n\t}\n\n\t/**\n\t * Returns a path to this position's parent. Parent path is equal to position {@link module:engine/model/position~Position#path path}\n\t * but without the last item.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @returns {Array.<Number>} Path to the parent.\n\t */\n\tgetParentPath() {\n\t\treturn this.path.slice( 0, -1 );\n\t}\n\n\t/**\n\t * Returns ancestors array of this position, that is this position's parent and its ancestors.\n\t *\n\t * @returns {Array.<module:engine/model/item~Item>} Array with ancestors.\n\t */\n\tgetAncestors() {\n\t\tconst parent = this.parent;\n\n\t\tif ( parent.is( 'documentFragment' ) ) {\n\t\t\treturn [ parent ];\n\t\t} else {\n\t\t\treturn parent.getAncestors( { includeSelf: true } );\n\t\t}\n\t}\n\n\t/**\n\t * Returns the parent element of the given name. Returns null if the position is not inside the desired parent.\n\t *\n\t * @param {String} parentName The name of the parent element to find.\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\tfindAncestor( parentName ) {\n\t\tconst parent = this.parent;\n\n\t\tif ( parent.is( 'element' ) ) {\n\t\t\treturn parent.findAncestor( parentName, { includeSelf: true } );\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns the slice of two position {@link #path paths} which is identical. The {@link #root roots}\n\t * of these two paths must be identical.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {module:engine/model/position~Position} position The second position.\n\t * @returns {Array.<Number>} The common path.\n\t */\n\tgetCommonPath( position ) {\n\t\tif ( this.root != position.root ) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// We find on which tree-level start and end have the lowest common ancestor\n\t\tconst cmp = compareArrays( this.path, position.path );\n\t\t// If comparison returned string it means that arrays are same.\n\t\tconst diffAt = ( typeof cmp == 'string' ) ? Math.min( this.path.length, position.path.length ) : cmp;\n\n\t\treturn this.path.slice( 0, diffAt );\n\t}\n\n\t/**\n\t * Returns an {@link module:engine/model/element~Element} or {@link module:engine/model/documentfragment~DocumentFragment}\n\t * which is a common ancestor of both positions. The {@link #root roots} of these two positions must be identical.\n\t *\n\t * @param {module:engine/model/position~Position} position The second position.\n\t * @returns {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor( position ) {\n\t\tconst ancestorsA = this.getAncestors();\n\t\tconst ancestorsB = position.getAncestors();\n\n\t\tlet i = 0;\n\n\t\twhile ( ancestorsA[ i ] == ancestorsB[ i ] && ancestorsA[ i ] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i === 0 ? null : ancestorsA[ i - 1 ];\n\t}\n\n\t/**\n\t * Returns a new instance of `Position`, that has same {@link #parent parent} but it's offset\n\t * is shifted by `shift` value (can be a negative value).\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {Number} shift Offset shift. Can be a negative value.\n\t * @returns {module:engine/model/position~Position} Shifted position.\n\t */\n\tgetShiftedBy( shift ) {\n\t\tconst shifted = this.clone();\n\n\t\tconst offset = shifted.offset + shift;\n\t\tshifted.offset = offset < 0 ? 0 : offset;\n\n\t\treturn shifted;\n\t}\n\n\t/**\n\t * Checks whether this position is after given position.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @see module:engine/model/position~Position#isBefore\n\t * @param {module:engine/model/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} True if this position is after given position.\n\t */\n\tisAfter( otherPosition ) {\n\t\treturn this.compareWith( otherPosition ) == 'after';\n\t}\n\n\t/**\n\t * Checks whether this position is before given position.\n\t *\n\t * **Note:** watch out when using negation of the value returned by this method, because the negation will also\n\t * be `true` if positions are in different roots and you might not expect this. You should probably use\n\t * `a.isAfter( b ) || a.isEqual( b )` or `!a.isBefore( p ) && a.root == b.root` in most scenarios. If your\n\t * condition uses multiple `isAfter` and `isBefore` checks, build them so they do not use negated values, i.e.:\n\t *\n\t *\t\tif ( a.isBefore( b ) && c.isAfter( d ) ) {\n\t *\t\t\t// do A.\n\t *\t\t} else {\n\t *\t\t\t// do B.\n\t *\t\t}\n\t *\n\t * or, if you have only one if-branch:\n\t *\n\t *\t\tif ( !( a.isBefore( b ) && c.isAfter( d ) ) {\n\t *\t\t\t// do B.\n\t *\t\t}\n\t *\n\t * rather than:\n\t *\n\t *\t\tif ( !a.isBefore( b ) || && !c.isAfter( d ) ) {\n\t *\t\t\t// do B.\n\t *\t\t} else {\n\t *\t\t\t// do A.\n\t *\t\t}\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {module:engine/model/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} True if this position is before given position.\n\t */\n\tisBefore( otherPosition ) {\n\t\treturn this.compareWith( otherPosition ) == 'before';\n\t}\n\n\t/**\n\t * Checks whether this position is equal to given position.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {module:engine/model/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} True if positions are same.\n\t */\n\tisEqual( otherPosition ) {\n\t\treturn this.compareWith( otherPosition ) == 'same';\n\t}\n\n\t/**\n\t * Checks whether this position is touching given position. Positions touch when there are no text nodes\n\t * or empty nodes in a range between them. Technically, those positions are not equal but in many cases\n\t * they are very similar or even indistinguishable.\n\t *\n\t * @param {module:engine/model/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} True if positions touch.\n\t */\n\tisTouching( otherPosition ) {\n\t\tlet left = null;\n\t\tlet right = null;\n\t\tconst compare = this.compareWith( otherPosition );\n\n\t\tswitch ( compare ) {\n\t\t\tcase 'same':\n\t\t\t\treturn true;\n\n\t\t\tcase 'before':\n\t\t\t\tleft = Position._createAt( this );\n\t\t\t\tright = Position._createAt( otherPosition );\n\t\t\t\tbreak;\n\n\t\t\tcase 'after':\n\t\t\t\tleft = Position._createAt( otherPosition );\n\t\t\t\tright = Position._createAt( this );\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\n\t\t// Cached for optimization purposes.\n\t\tlet leftParent = left.parent;\n\n\t\twhile ( left.path.length + right.path.length ) {\n\t\t\tif ( left.isEqual( right ) ) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif ( left.path.length > right.path.length ) {\n\t\t\t\tif ( left.offset !== leftParent.maxOffset ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tleft.path = left.path.slice( 0, -1 );\n\t\t\t\tleftParent = leftParent.parent;\n\t\t\t\tleft.offset++;\n\t\t\t} else {\n\t\t\t\tif ( right.offset !== 0 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tright.path = right.path.slice( 0, -1 );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tposition.is( 'position' ); // -> true\n\t *\t\tposition.is( 'model:position' ); // -> true\n\t *\n\t *\t\tposition.is( 'view:position' ); // -> false\n\t *\t\tposition.is( 'documentSelection' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'position' || type === 'model:position';\n\t}\n\n\t/**\n\t * Checks if two positions are in the same parent.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {module:engine/model/position~Position} position Position to compare with.\n\t * @returns {Boolean} `true` if positions have the same parent, `false` otherwise.\n\t */\n\thasSameParentAs( position ) {\n\t\tif ( this.root !== position.root ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst thisParentPath = this.getParentPath();\n\t\tconst posParentPath = position.getParentPath();\n\n\t\treturn compareArrays( thisParentPath, posParentPath ) == 'same';\n\t}\n\n\t/**\n\t * Returns a copy of this position that is transformed by given `operation`.\n\t *\n\t * The new position's parameters are updated accordingly to the effect of the `operation`.\n\t *\n\t * For example, if `n` nodes are inserted before the position, the returned position {@link ~Position#offset} will be\n\t * increased by `n`. If the position was in a merged element, it will be accordingly moved to the new element, etc.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation Operation to transform by.\n\t * @returns {module:engine/model/position~Position} Transformed position.\n\t */\n\tgetTransformedByOperation( operation ) {\n\t\tlet result;\n\n\t\tswitch ( operation.type ) {\n\t\t\tcase 'insert':\n\t\t\t\tresult = this._getTransformedByInsertOperation( operation );\n\t\t\t\tbreak;\n\t\t\tcase 'move':\n\t\t\tcase 'remove':\n\t\t\tcase 'reinsert':\n\t\t\t\tresult = this._getTransformedByMoveOperation( operation );\n\t\t\t\tbreak;\n\t\t\tcase 'split':\n\t\t\t\tresult = this._getTransformedBySplitOperation( operation );\n\t\t\t\tbreak;\n\t\t\tcase 'merge':\n\t\t\t\tresult = this._getTransformedByMergeOperation( operation );\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tresult = Position._createAt( this );\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns a copy of this position transformed by an insert operation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/insertoperation~InsertOperation} operation\n\t * @returns {module:engine/model/position~Position}\n\t */\n\t_getTransformedByInsertOperation( operation ) {\n\t\treturn this._getTransformedByInsertion( operation.position, operation.howMany );\n\t}\n\n\t/**\n\t * Returns a copy of this position transformed by a move operation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/moveoperation~MoveOperation} operation\n\t * @returns {module:engine/model/position~Position}\n\t */\n\t_getTransformedByMoveOperation( operation ) {\n\t\treturn this._getTransformedByMove( operation.sourcePosition, operation.targetPosition, operation.howMany );\n\t}\n\n\t/**\n\t * Returns a copy of this position transformed by a split operation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/splitoperation~SplitOperation} operation\n\t * @returns {module:engine/model/position~Position}\n\t */\n\t_getTransformedBySplitOperation( operation ) {\n\t\tconst movedRange = operation.movedRange;\n\n\t\tconst isContained = movedRange.containsPosition( this ) ||\n\t\t\t( movedRange.start.isEqual( this ) && this.stickiness == 'toNext' );\n\n\t\tif ( isContained ) {\n\t\t\treturn this._getCombined( operation.splitPosition, operation.moveTargetPosition );\n\t\t} else {\n\t\t\tif ( operation.graveyardPosition ) {\n\t\t\t\treturn this._getTransformedByMove( operation.graveyardPosition, operation.insertionPosition, 1 );\n\t\t\t} else {\n\t\t\t\treturn this._getTransformedByInsertion( operation.insertionPosition, 1 );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns a copy of this position transformed by merge operation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/mergeoperation~MergeOperation} operation\n\t * @returns {module:engine/model/position~Position}\n\t */\n\t_getTransformedByMergeOperation( operation ) {\n\t\tconst movedRange = operation.movedRange;\n\t\tconst isContained = movedRange.containsPosition( this ) || movedRange.start.isEqual( this );\n\n\t\tlet pos;\n\n\t\tif ( isContained ) {\n\t\t\tpos = this._getCombined( operation.sourcePosition, operation.targetPosition );\n\n\t\t\tif ( operation.sourcePosition.isBefore( operation.targetPosition ) ) {\n\t\t\t\t// Above happens during OT when the merged element is moved before the merged-to element.\n\t\t\t\tpos = pos._getTransformedByDeletion( operation.deletionPosition, 1 );\n\t\t\t}\n\t\t} else if ( this.isEqual( operation.deletionPosition ) ) {\n\t\t\tpos = Position._createAt( operation.deletionPosition );\n\t\t} else {\n\t\t\tpos = this._getTransformedByMove( operation.deletionPosition, operation.graveyardPosition, 1 );\n\t\t}\n\n\t\treturn pos;\n\t}\n\n\t/**\n\t * Returns a copy of this position that is updated by removing `howMany` nodes starting from `deletePosition`.\n\t * It may happen that this position is in a removed node. If that is the case, `null` is returned instead.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} deletePosition Position before the first removed node.\n\t * @param {Number} howMany How many nodes are removed.\n\t * @returns {module:engine/model/position~Position|null} Transformed position or `null`.\n\t */\n\t_getTransformedByDeletion( deletePosition, howMany ) {\n\t\tconst transformed = Position._createAt( this );\n\n\t\t// This position can't be affected if deletion was in a different root.\n\t\tif ( this.root != deletePosition.root ) {\n\t\t\treturn transformed;\n\t\t}\n\n\t\tif ( compareArrays( deletePosition.getParentPath(), this.getParentPath() ) == 'same' ) {\n\t\t\t// If nodes are removed from the node that is pointed by this position...\n\t\t\tif ( deletePosition.offset < this.offset ) {\n\t\t\t\t// And are removed from before an offset of that position...\n\t\t\t\tif ( deletePosition.offset + howMany > this.offset ) {\n\t\t\t\t\t// Position is in removed range, it's no longer in the tree.\n\t\t\t\t\treturn null;\n\t\t\t\t} else {\n\t\t\t\t\t// Decrement the offset accordingly.\n\t\t\t\t\ttransformed.offset -= howMany;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if ( compareArrays( deletePosition.getParentPath(), this.getParentPath() ) == 'prefix' ) {\n\t\t\t// If nodes are removed from a node that is on a path to this position...\n\t\t\tconst i = deletePosition.path.length - 1;\n\n\t\t\tif ( deletePosition.offset <= this.path[ i ] ) {\n\t\t\t\t// And are removed from before next node of that path...\n\t\t\t\tif ( deletePosition.offset + howMany > this.path[ i ] ) {\n\t\t\t\t\t// If the next node of that path is removed return null\n\t\t\t\t\t// because the node containing this position got removed.\n\t\t\t\t\treturn null;\n\t\t\t\t} else {\n\t\t\t\t\t// Otherwise, decrement index on that path.\n\t\t\t\t\ttransformed.path[ i ] -= howMany;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn transformed;\n\t}\n\n\t/**\n\t * Returns a copy of this position that is updated by inserting `howMany` nodes at `insertPosition`.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} insertPosition Position where nodes are inserted.\n\t * @param {Number} howMany How many nodes are inserted.\n\t * @returns {module:engine/model/position~Position} Transformed position.\n\t */\n\t_getTransformedByInsertion( insertPosition, howMany ) {\n\t\tconst transformed = Position._createAt( this );\n\n\t\t// This position can't be affected if insertion was in a different root.\n\t\tif ( this.root != insertPosition.root ) {\n\t\t\treturn transformed;\n\t\t}\n\n\t\tif ( compareArrays( insertPosition.getParentPath(), this.getParentPath() ) == 'same' ) {\n\t\t\t// If nodes are inserted in the node that is pointed by this position...\n\t\t\tif ( insertPosition.offset < this.offset || ( insertPosition.offset == this.offset && this.stickiness != 'toPrevious' ) ) {\n\t\t\t\t// And are inserted before an offset of that position...\n\t\t\t\t// \"Push\" this positions offset.\n\t\t\t\ttransformed.offset += howMany;\n\t\t\t}\n\t\t} else if ( compareArrays( insertPosition.getParentPath(), this.getParentPath() ) == 'prefix' ) {\n\t\t\t// If nodes are inserted in a node that is on a path to this position...\n\t\t\tconst i = insertPosition.path.length - 1;\n\n\t\t\tif ( insertPosition.offset <= this.path[ i ] ) {\n\t\t\t\t// And are inserted before next node of that path...\n\t\t\t\t// \"Push\" the index on that path.\n\t\t\t\ttransformed.path[ i ] += howMany;\n\t\t\t}\n\t\t}\n\n\t\treturn transformed;\n\t}\n\n\t/**\n\t * Returns a copy of this position that is updated by moving `howMany` nodes from `sourcePosition` to `targetPosition`.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} sourcePosition Position before the first element to move.\n\t * @param {module:engine/model/position~Position} targetPosition Position where moved elements will be inserted.\n\t * @param {Number} howMany How many consecutive nodes to move, starting from `sourcePosition`.\n\t * @returns {module:engine/model/position~Position} Transformed position.\n\t */\n\t_getTransformedByMove( sourcePosition, targetPosition, howMany ) {\n\t\t// Update target position, as it could be affected by nodes removal.\n\t\ttargetPosition = targetPosition._getTransformedByDeletion( sourcePosition, howMany );\n\n\t\tif ( sourcePosition.isEqual( targetPosition ) ) {\n\t\t\t// If `targetPosition` is equal to `sourcePosition` this isn't really any move. Just return position as it is.\n\t\t\treturn Position._createAt( this );\n\t\t}\n\n\t\t// Moving a range removes nodes from their original position. We acknowledge this by proper transformation.\n\t\tconst transformed = this._getTransformedByDeletion( sourcePosition, howMany );\n\n\t\tconst isMoved = transformed === null ||\n\t\t\t( sourcePosition.isEqual( this ) && this.stickiness == 'toNext' ) ||\n\t\t\t( sourcePosition.getShiftedBy( howMany ).isEqual( this ) && this.stickiness == 'toPrevious' );\n\n\t\tif ( isMoved ) {\n\t\t\t// This position is inside moved range (or sticks to it).\n\t\t\t// In this case, we calculate a combination of this position, move source position and target position.\n\t\t\treturn this._getCombined( sourcePosition, targetPosition );\n\t\t} else {\n\t\t\t// This position is not inside a removed range.\n\t\t\t//\n\t\t\t// In next step, we simply reflect inserting `howMany` nodes, which might further affect the position.\n\t\t\treturn transformed._getTransformedByInsertion( targetPosition, howMany );\n\t\t}\n\t}\n\n\t/**\n\t * Returns a new position that is a combination of this position and given positions.\n\t *\n\t * The combined position is a copy of this position transformed by moving a range starting at `source` position\n\t * to the `target` position. It is expected that this position is inside the moved range.\n\t *\n\t * Example:\n\t *\n\t *\t\tlet original = model.createPositionFromPath( root, [ 2, 3, 1 ] );\n\t *\t\tlet source = model.createPositionFromPath( root, [ 2, 2 ] );\n\t *\t\tlet target = model.createPositionFromPath( otherRoot, [ 1, 1, 3 ] );\n\t *\t\toriginal._getCombined( source, target ); // path is [ 1, 1, 4, 1 ], root is `otherRoot`\n\t *\n\t * Explanation:\n\t *\n\t * We have a position `[ 2, 3, 1 ]` and move some nodes from `[ 2, 2 ]` to `[ 1, 1, 3 ]`. The original position\n\t * was inside moved nodes and now should point to the new place. The moved nodes will be after\n\t * positions `[ 1, 1, 3 ]`, `[ 1, 1, 4 ]`, `[ 1, 1, 5 ]`. Since our position was in the second moved node,\n\t * the transformed position will be in a sub-tree of a node at `[ 1, 1, 4 ]`. Looking at original path, we\n\t * took care of `[ 2, 3 ]` part of it. Now we have to add the rest of the original path to the transformed path.\n\t * Finally, the transformed position will point to `[ 1, 1, 4, 1 ]`.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} source Beginning of the moved range.\n\t * @param {module:engine/model/position~Position} target Position where the range is moved.\n\t * @returns {module:engine/model/position~Position} Combined position.\n\t */\n\t_getCombined( source, target ) {\n\t\tconst i = source.path.length - 1;\n\n\t\t// The first part of a path to combined position is a path to the place where nodes were moved.\n\t\tconst combined = Position._createAt( target );\n\t\tcombined.stickiness = this.stickiness;\n\n\t\t// Then we have to update the rest of the path.\n\n\t\t// Fix the offset because this position might be after `from` position and we have to reflect that.\n\t\tcombined.offset = combined.offset + this.path[ i ] - source.offset;\n\n\t\t// Then, add the rest of the path.\n\t\t// If this position is at the same level as `from` position nothing will get added.\n\t\tcombined.path = [ ...combined.path, ...this.path.slice( i + 1 ) ];\n\n\t\treturn combined;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\treturn {\n\t\t\troot: this.root.toJSON(),\n\t\t\tpath: Array.from( this.path ),\n\t\t\tstickiness: this.stickiness\n\t\t};\n\t}\n\n\t/**\n\t * Returns a new position that is equal to current position.\n\t *\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tclone() {\n\t\treturn new this.constructor( this.root, this.path, this.stickiness );\n\t}\n\n\t/**\n\t * Creates position at the given location. The location can be specified as:\n\t *\n\t * * a {@link module:engine/model/position~Position position},\n\t * * parent element and offset (offset defaults to `0`),\n\t * * parent element and `'end'` (sets position at the end of that element),\n\t * * {@link module:engine/model/item~Item model item} and `'before'` or `'after'` (sets position before or after given model item).\n\t *\n\t * This method is a shortcut to other factory methods such as:\n\t *\n\t * * {@link module:engine/model/position~Position._createBefore},\n\t * * {@link module:engine/model/position~Position._createAfter}.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when the\n\t * first parameter is a {@link module:engine/model/item~Item model item}.\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone'] Position stickiness. Used only when the\n\t * first parameter is a {@link module:engine/model/item~Item model item}.\n\t * @protected\n\t */\n\tstatic _createAt( itemOrPosition, offset, stickiness = 'toNone' ) {\n\t\tif ( itemOrPosition instanceof Position ) {\n\t\t\treturn new Position( itemOrPosition.root, itemOrPosition.path, itemOrPosition.stickiness );\n\t\t} else {\n\t\t\tconst node = itemOrPosition;\n\n\t\t\tif ( offset == 'end' ) {\n\t\t\t\toffset = node.maxOffset;\n\t\t\t} else if ( offset == 'before' ) {\n\t\t\t\treturn this._createBefore( node, stickiness );\n\t\t\t} else if ( offset == 'after' ) {\n\t\t\t\treturn this._createAfter( node, stickiness );\n\t\t\t} else if ( offset !== 0 && !offset ) {\n\t\t\t\t/**\n\t\t\t\t * {@link module:engine/model/model~Model#createPositionAt `Model#createPositionAt()`}\n\t\t\t\t * requires the offset to be specified when the first parameter is a model item.\n\t\t\t\t *\n\t\t\t\t * @error model-createpositionat-offset-required\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'model-createpositionat-offset-required', [ this, itemOrPosition ] );\n\t\t\t}\n\n\t\t\tif ( !node.is( 'element' ) && !node.is( 'documentFragment' ) ) {\n\t\t\t\t/**\n\t\t\t\t * Position parent have to be a model element or model document fragment.\n\t\t\t\t *\n\t\t\t\t * @error model-position-parent-incorrect\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'model-position-parent-incorrect',\n\t\t\t\t\t[ this, itemOrPosition ]\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst path = node.getPath();\n\n\t\t\tpath.push( offset );\n\n\t\t\treturn new this( node.root, path, stickiness );\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new position, after given {@link module:engine/model/item~Item model item}.\n\t *\n\t * @param {module:engine/model/item~Item} item Item after which the position should be placed.\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone'] Position stickiness.\n\t * @returns {module:engine/model/position~Position}\n\t * @protected\n\t */\n\tstatic _createAfter( item, stickiness ) {\n\t\tif ( !item.parent ) {\n\t\t\t/**\n\t\t\t * You can not make a position after a root element.\n\t\t\t *\n\t\t\t * @error model-position-after-root\n\t\t\t * @param {module:engine/model/item~Item} root\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-position-after-root',\n\t\t\t\t[ this, item ],\n\t\t\t\t{ root: item }\n\t\t\t);\n\t\t}\n\n\t\treturn this._createAt( item.parent, item.endOffset, stickiness );\n\t}\n\n\t/**\n\t * Creates a new position, before the given {@link module:engine/model/item~Item model item}.\n\t *\n\t * @param {module:engine/model/item~Item} item Item before which the position should be placed.\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone'] Position stickiness.\n\t * @returns {module:engine/model/position~Position}\n\t * @protected\n\t */\n\tstatic _createBefore( item, stickiness ) {\n\t\tif ( !item.parent ) {\n\t\t\t/**\n\t\t\t * You can not make a position before a root element.\n\t\t\t *\n\t\t\t * @error model-position-before-root\n\t\t\t * @param {module:engine/model/item~Item} root\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-position-before-root',\n\t\t\t\titem,\n\t\t\t\t{ root: item }\n\t\t\t);\n\t\t}\n\n\t\treturn this._createAt( item.parent, item.startOffset, stickiness );\n\t}\n\n\t/**\n\t * Creates a `Position` instance from given plain object (i.e. parsed JSON string).\n\t *\n\t * @param {Object} json Plain object to be converted to `Position`.\n\t * @param {module:engine/model/document~Document} doc Document object that will be position owner.\n\t * @returns {module:engine/model/position~Position} `Position` instance created using given plain object.\n\t */\n\tstatic fromJSON( json, doc ) {\n\t\tif ( json.root === '$graveyard' ) {\n\t\t\tconst pos = new Position( doc.graveyard, json.path );\n\t\t\tpos.stickiness = json.stickiness;\n\n\t\t\treturn pos;\n\t\t}\n\n\t\tif ( !doc.getRoot( json.root ) ) {\n\t\t\t/**\n\t\t\t * Cannot create position for document. Root with specified name does not exist.\n\t\t\t *\n\t\t\t * @error model-position-fromjson-no-root\n\t\t\t * @param {String} rootName\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-position-fromjson-no-root',\n\t\t\t\tdoc,\n\t\t\t\t{ rootName: json.root }\n\t\t\t);\n\t\t}\n\n\t\treturn new Position( doc.getRoot( json.root ), json.path, json.stickiness );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `${ this.root } [ ${ this.path.join( ', ' ) } ]`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelPosition: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\n/**\n * A flag indicating whether this position is `'before'` or `'after'` or `'same'` as given position.\n * If positions are in different roots `'different'` flag is returned.\n *\n * @typedef {String} module:engine/model/position~PositionRelation\n */\n\n/**\n * Represents how position is \"sticking\" with neighbour nodes. Used to define how position should be transformed (moved)\n * in edge cases. Possible values: `'toNone'`, `'toNext'`, `'toPrevious'`.\n *\n * Examples:\n *\n *\t\tInsert. Position is at | and nodes are inserted at the same position, marked as ^:\n *\n *\t\t- sticks to none:           <p>f^|oo</p>  ->  <p>fbar|oo</p>\n *\t\t- sticks to next node:      <p>f^|oo</p>  ->  <p>fbar|oo</p>\n *\t\t- sticks to previous node:  <p>f|^oo</p>  ->  <p>f|baroo</p>\n *\n *\n *\t\tMove. Position is at | and range [oo] is moved to position ^:\n *\n *\t\t- sticks to none:           <p>f|[oo]</p><p>b^ar</p>  ->  <p>f|</p><p>booar</p>\n *\t\t- sticks to none:           <p>f[oo]|</p><p>b^ar</p>  ->  <p>f|</p><p>booar</p>\n *\n *\t\t- sticks to next node:      <p>f|[oo]</p><p>b^ar</p>  ->  <p>f</p><p>b|ooar</p>\n *\t\t- sticks to next node:      <p>f[oo]|</p><p>b^ar</p>  ->  <p>f|</p><p>booar</p>\n *\n *\t\t- sticks to previous node:  <p>f|[oo]</p><p>b^ar</p>  ->  <p>f|</p><p>booar</p>\n *\t\t- sticks to previous node:  <p>f[oo]|</p><p>b^ar</p>  ->  <p>f</p><p>boo|ar</p>\n *\n * @typedef {String} module:engine/model/position~PositionStickiness\n */\n\n/**\n * Returns a text node at the given position.\n *\n * This is a helper function optimized to reuse the position parent instance for performance reasons.\n *\n * Normally, you should use {@link module:engine/model/position~Position#textNode `Position#textNode`}.\n * If you start hitting performance issues with {@link module:engine/model/position~Position#parent `Position#parent`}\n * check if your algorithm does not access it multiple times (which can happen directly or indirectly via other position properties).\n *\n * See https://github.com/ckeditor/ckeditor5/issues/6579.\n *\n * See also:\n *\n * * {@link module:engine/model/position~getNodeAfterPosition}\n * * {@link module:engine/model/position~getNodeBeforePosition}\n *\n * @param {module:engine/model/position~Position} position\n * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} positionParent The parent of the\n * given position.\n * @returns {module:engine/model/text~Text|null}\n */\nexport function getTextNodeAtPosition( position, positionParent ) {\n\tconst node = positionParent.getChild( positionParent.offsetToIndex( position.offset ) );\n\n\tif ( node && node.is( '$text' ) && node.startOffset < position.offset ) {\n\t\treturn node;\n\t}\n\n\treturn null;\n}\n\n/**\n * Returns the node after the given position.\n *\n * This is a helper function optimized to reuse the position parent instance and the calculation of the text node at the\n * specific position for performance reasons.\n *\n * Normally, you should use {@link module:engine/model/position~Position#nodeAfter `Position#nodeAfter`}.\n * If you start hitting performance issues with {@link module:engine/model/position~Position#parent `Position#parent`} and/or\n * {@link module:engine/model/position~Position#textNode `Position#textNode`}\n * check if your algorithm does not access those properties multiple times\n * (which can happen directly or indirectly via other position properties).\n *\n * See https://github.com/ckeditor/ckeditor5/issues/6579 and https://github.com/ckeditor/ckeditor5/issues/6582.\n *\n * See also:\n *\n * * {@link module:engine/model/position~getTextNodeAtPosition}\n * * {@link module:engine/model/position~getNodeBeforePosition}\n *\n * @param {module:engine/model/position~Position} position\n * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} positionParent The parent of the\n * given position.\n * @param {module:engine/model/text~Text|null} textNode Text node at the given position.\n * @returns {module:engine/model/node~Node|null}\n */\nexport function getNodeAfterPosition( position, positionParent, textNode ) {\n\tif ( textNode !== null ) {\n\t\treturn null;\n\t}\n\n\treturn positionParent.getChild( positionParent.offsetToIndex( position.offset ) );\n}\n\n/**\n * Returns the node before the given position.\n *\n * Refer to {@link module:engine/model/position~getNodeBeforePosition} for documentation on when to use this util method.\n *\n * See also:\n *\n * * {@link module:engine/model/position~getTextNodeAtPosition}\n * * {@link module:engine/model/position~getNodeAfterPosition}\n *\n * @param {module:engine/model/position~Position} position\n * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} positionParent The parent of the\n * given position.\n * @param {module:engine/model/text~Text|null} textNode Text node at the given position.\n * @returns {module:engine/model/node~Node|null}\n */\nexport function getNodeBeforePosition( position, positionParent, textNode ) {\n\tif ( textNode !== null ) {\n\t\treturn null;\n\t}\n\n\treturn positionParent.getChild( positionParent.offsetToIndex( position.offset ) - 1 );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/range\n */\n\nimport Position from './position';\nimport TreeWalker from './treewalker';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\n\n/**\n * Represents a range in the model tree.\n *\n * A range is defined by its {@link module:engine/model/range~Range#start} and {@link module:engine/model/range~Range#end}\n * positions.\n *\n * You can create range instances via its constructor or the `createRange*()` factory methods of\n * {@link module:engine/model/model~Model} and {@link module:engine/model/writer~Writer}.\n */\nexport default class Range {\n\t/**\n\t * Creates a range spanning from `start` position to `end` position.\n\t *\n\t * @param {module:engine/model/position~Position} start Start position.\n\t * @param {module:engine/model/position~Position} [end] End position. If not set, range will be collapsed at `start` position.\n\t */\n\tconstructor( start, end = null ) {\n\t\t/**\n\t\t * Start position.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/position~Position}\n\t\t */\n\t\tthis.start = Position._createAt( start );\n\n\t\t/**\n\t\t * End position.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/position~Position}\n\t\t */\n\t\tthis.end = end ? Position._createAt( end ) : Position._createAt( start );\n\n\t\t// If the range is collapsed, treat in a similar way as a position and set its boundaries stickiness to 'toNone'.\n\t\t// In other case, make the boundaries stick to the \"inside\" of the range.\n\t\tthis.start.stickiness = this.isCollapsed ? 'toNone' : 'toNext';\n\t\tthis.end.stickiness = this.isCollapsed ? 'toNone' : 'toPrevious';\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over all {@link module:engine/model/item~Item items} that are in this range and returns\n\t * them together with additional information like length or {@link module:engine/model/position~Position positions},\n\t * grouped as {@link module:engine/model/treewalker~TreeWalkerValue}.\n\t * It iterates over all {@link module:engine/model/textproxy~TextProxy text contents} that are inside the range\n\t * and all the {@link module:engine/model/element~Element}s that are entered into when iterating over this range.\n\t *\n\t * This iterator uses {@link module:engine/model/treewalker~TreeWalker} with `boundaries` set to this range\n\t * and `ignoreElementEnd` option set to `true`.\n\t *\n\t * @returns {Iterable.<module:engine/model/treewalker~TreeWalkerValue>}\n\t */\n\t* [ Symbol.iterator ]() {\n\t\tyield* new TreeWalker( { boundaries: this, ignoreElementEnd: true } );\n\t}\n\n\t/**\n\t * Returns whether the range is collapsed, that is if {@link #start} and\n\t * {@link #end} positions are equal.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\treturn this.start.isEqual( this.end );\n\t}\n\n\t/**\n\t * Returns whether this range is flat, that is if {@link #start} position and\n\t * {@link #end} position are in the same {@link module:engine/model/position~Position#parent}.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isFlat() {\n\t\tconst startParentPath = this.start.getParentPath();\n\t\tconst endParentPath = this.end.getParentPath();\n\n\t\treturn compareArrays( startParentPath, endParentPath ) == 'same';\n\t}\n\n\t/**\n\t * Range root element.\n\t *\n\t * @type {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this.start.root;\n\t}\n\n\t/**\n\t * Checks whether this range contains given {@link module:engine/model/position~Position position}.\n\t *\n\t * @param {module:engine/model/position~Position} position Position to check.\n\t * @returns {Boolean} `true` if given {@link module:engine/model/position~Position position} is contained\n\t * in this range,`false` otherwise.\n\t */\n\tcontainsPosition( position ) {\n\t\treturn position.isAfter( this.start ) && position.isBefore( this.end );\n\t}\n\n\t/**\n\t * Checks whether this range contains given {@link ~Range range}.\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to check.\n\t * @param {Boolean} [loose=false] Whether the check is loose or strict. If the check is strict (`false`), compared range cannot\n\t * start or end at the same position as this range boundaries. If the check is loose (`true`), compared range can start, end or\n\t * even be equal to this range. Note that collapsed ranges are always compared in strict mode.\n\t * @returns {Boolean} `true` if given {@link ~Range range} boundaries are contained by this range, `false` otherwise.\n\t */\n\tcontainsRange( otherRange, loose = false ) {\n\t\tif ( otherRange.isCollapsed ) {\n\t\t\tloose = false;\n\t\t}\n\n\t\tconst containsStart = this.containsPosition( otherRange.start ) || ( loose && this.start.isEqual( otherRange.start ) );\n\t\tconst containsEnd = this.containsPosition( otherRange.end ) || ( loose && this.end.isEqual( otherRange.end ) );\n\n\t\treturn containsStart && containsEnd;\n\t}\n\n\t/**\n\t * Checks whether given {@link module:engine/model/item~Item} is inside this range.\n\t *\n\t * @param {module:engine/model/item~Item} item Model item to check.\n\t */\n\tcontainsItem( item ) {\n\t\tconst pos = Position._createBefore( item );\n\n\t\treturn this.containsPosition( pos ) || this.start.isEqual( pos );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\trange.is( 'range' ); // -> true\n\t *\t\trange.is( 'model:range' ); // -> true\n\t *\n\t *\t\trange.is( 'view:range' ); // -> false\n\t *\t\trange.is( 'documentSelection' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'range' || type === 'model:range';\n\t}\n\n\t/**\n\t * Two ranges are equal if their {@link #start} and {@link #end} positions are equal.\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to compare with.\n\t * @returns {Boolean} `true` if ranges are equal, `false` otherwise.\n\t */\n\tisEqual( otherRange ) {\n\t\treturn this.start.isEqual( otherRange.start ) && this.end.isEqual( otherRange.end );\n\t}\n\n\t/**\n\t * Checks and returns whether this range intersects with given range.\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to compare with.\n\t * @returns {Boolean} `true` if ranges intersect, `false` otherwise.\n\t */\n\tisIntersecting( otherRange ) {\n\t\treturn this.start.isBefore( otherRange.end ) && this.end.isAfter( otherRange.start );\n\t}\n\n\t/**\n\t * Computes which part(s) of this {@link ~Range range} is not a part of given {@link ~Range range}.\n\t * Returned array contains zero, one or two {@link ~Range ranges}.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet range = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2, 7 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 4, 0, 1 ] )\n\t *\t\t);\n\t *\t\tlet otherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 5 ] ) );\n\t *\t\tlet transformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has no ranges because `otherRange` contains `range`\n\t *\n\t *\t\totherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 3 ] ) );\n\t *\t\ttransformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has one range: from [ 3 ] to [ 4, 0, 1 ]\n\t *\n\t *\t\totherRange = model.createRange( model.createPositionFromPath( root, [ 3 ] ), model.createPositionFromPath( root, [ 4 ] ) );\n\t *\t\ttransformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has two ranges: from [ 2, 7 ] to [ 3 ] and from [ 4 ] to [ 4, 0, 1 ]\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to differentiate against.\n\t * @returns {Array.<module:engine/model/range~Range>} The difference between ranges.\n\t */\n\tgetDifference( otherRange ) {\n\t\tconst ranges = [];\n\n\t\tif ( this.isIntersecting( otherRange ) ) {\n\t\t\t// Ranges intersect.\n\n\t\t\tif ( this.containsPosition( otherRange.start ) ) {\n\t\t\t\t// Given range start is inside this range. This means that we have to\n\t\t\t\t// add shrunken range - from the start to the middle of this range.\n\t\t\t\tranges.push( new Range( this.start, otherRange.start ) );\n\t\t\t}\n\n\t\t\tif ( this.containsPosition( otherRange.end ) ) {\n\t\t\t\t// Given range end is inside this range. This means that we have to\n\t\t\t\t// add shrunken range - from the middle of this range to the end.\n\t\t\t\tranges.push( new Range( otherRange.end, this.end ) );\n\t\t\t}\n\t\t} else {\n\t\t\t// Ranges do not intersect, return the original range.\n\t\t\tranges.push( new Range( this.start, this.end ) );\n\t\t}\n\n\t\treturn ranges;\n\t}\n\n\t/**\n\t * Returns an intersection of this {@link ~Range range} and given {@link ~Range range}.\n\t * Intersection is a common part of both of those ranges. If ranges has no common part, returns `null`.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet range = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2, 7 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 4, 0, 1 ] )\n\t *\t\t);\n\t *\t\tlet otherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 2 ] ) );\n\t *\t\tlet transformed = range.getIntersection( otherRange ); // null - ranges have no common part\n\t *\n\t *\t\totherRange = model.createRange( model.createPositionFromPath( root, [ 3 ] ), model.createPositionFromPath( root, [ 5 ] ) );\n\t *\t\ttransformed = range.getIntersection( otherRange ); // range from [ 3 ] to [ 4, 0, 1 ]\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to check for intersection.\n\t * @returns {module:engine/model/range~Range|null} A common part of given ranges or `null` if ranges have no common part.\n\t */\n\tgetIntersection( otherRange ) {\n\t\tif ( this.isIntersecting( otherRange ) ) {\n\t\t\t// Ranges intersect, so a common range will be returned.\n\t\t\t// At most, it will be same as this range.\n\t\t\tlet commonRangeStart = this.start;\n\t\t\tlet commonRangeEnd = this.end;\n\n\t\t\tif ( this.containsPosition( otherRange.start ) ) {\n\t\t\t\t// Given range start is inside this range. This means thaNt we have to\n\t\t\t\t// shrink common range to the given range start.\n\t\t\t\tcommonRangeStart = otherRange.start;\n\t\t\t}\n\n\t\t\tif ( this.containsPosition( otherRange.end ) ) {\n\t\t\t\t// Given range end is inside this range. This means that we have to\n\t\t\t\t// shrink common range to the given range end.\n\t\t\t\tcommonRangeEnd = otherRange.end;\n\t\t\t}\n\n\t\t\treturn new Range( commonRangeStart, commonRangeEnd );\n\t\t}\n\n\t\t// Ranges do not intersect, so they do not have common part.\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns a range created by joining this {@link ~Range range} with the given {@link ~Range range}.\n\t * If ranges have no common part, returns `null`.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet range = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2, 7 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 4, 0, 1 ] )\n\t *\t\t);\n\t *\t\tlet otherRange = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 1 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2 ] )\n \t *\t\t);\n\t *\t\tlet transformed = range.getJoined( otherRange ); // null - ranges have no common part\n\t *\n\t *\t\totherRange = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 3 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 5 ] )\n\t *\t\t);\n\t *\t\ttransformed = range.getJoined( otherRange ); // range from [ 2, 7 ] to [ 5 ]\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to be joined.\n\t * @param {Boolean} [loose=false] Whether the intersection check is loose or strict. If the check is strict (`false`),\n\t * ranges are tested for intersection or whether start/end positions are equal. If the check is loose (`true`),\n\t * compared range is also checked if it's {@link module:engine/model/position~Position#isTouching touching} current range.\n\t * @returns {module:engine/model/range~Range|null} A sum of given ranges or `null` if ranges have no common part.\n\t */\n\tgetJoined( otherRange, loose = false ) {\n\t\tlet shouldJoin = this.isIntersecting( otherRange );\n\n\t\tif ( !shouldJoin ) {\n\t\t\tif ( this.start.isBefore( otherRange.start ) ) {\n\t\t\t\tshouldJoin = loose ? this.end.isTouching( otherRange.start ) : this.end.isEqual( otherRange.start );\n\t\t\t} else {\n\t\t\t\tshouldJoin = loose ? otherRange.end.isTouching( this.start ) : otherRange.end.isEqual( this.start );\n\t\t\t}\n\t\t}\n\n\t\tif ( !shouldJoin ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tlet startPosition = this.start;\n\t\tlet endPosition = this.end;\n\n\t\tif ( otherRange.start.isBefore( startPosition ) ) {\n\t\t\tstartPosition = otherRange.start;\n\t\t}\n\n\t\tif ( otherRange.end.isAfter( endPosition ) ) {\n\t\t\tendPosition = otherRange.end;\n\t\t}\n\n\t\treturn new Range( startPosition, endPosition );\n\t}\n\n\t/**\n\t * Computes and returns the smallest set of {@link #isFlat flat} ranges, that covers this range in whole.\n\t *\n\t * See an example of a model structure (`[` and `]` are range boundaries):\n\t *\n\t *\t\troot                                                            root\n\t *\t\t |- element DIV                         DIV             P2              P3             DIV\n\t *\t\t |   |- element H                   H        P1        f o o           b a r       H         P4\n\t *\t\t |   |   |- \"fir[st\"             fir[st     lorem                               se]cond     ipsum\n\t *\t\t |   |- element P1\n\t *\t\t |   |   |- \"lorem\"                                              ||\n\t *\t\t |- element P2                                                   ||\n\t *\t\t |   |- \"foo\"                                                    VV\n\t *\t\t |- element P3\n\t *\t\t |   |- \"bar\"                                                   root\n\t *\t\t |- element DIV                         DIV             [P2             P3]             DIV\n\t *\t\t |   |- element H                   H       [P1]       f o o           b a r        H         P4\n\t *\t\t |   |   |- \"se]cond\"            fir[st]    lorem                               [se]cond     ipsum\n\t *\t\t |   |- element P4\n\t *\t\t |   |   |- \"ipsum\"\n\t *\n\t * As it can be seen, letters contained in the range are: `stloremfoobarse`, spread across different parents.\n\t * We are looking for minimal set of flat ranges that contains the same nodes.\n\t *\n\t * Minimal flat ranges for above range `( [ 0, 0, 3 ], [ 3, 0, 2 ] )` will be:\n\t *\n\t *\t\t( [ 0, 0, 3 ], [ 0, 0, 5 ] ) = \"st\"\n\t *\t\t( [ 0, 1 ], [ 0, 2 ] ) = element P1 (\"lorem\")\n\t *\t\t( [ 1 ], [ 3 ] ) = element P2, element P3 (\"foobar\")\n\t *\t\t( [ 3, 0, 0 ], [ 3, 0, 2 ] ) = \"se\"\n\t *\n\t * **Note:** if an {@link module:engine/model/element~Element element} is not wholly contained in this range, it won't be returned\n\t * in any of the returned flat ranges. See in the example how `H` elements at the beginning and at the end of the range\n\t * were omitted. Only their parts that were wholly in the range were returned.\n\t *\n\t * **Note:** this method is not returning flat ranges that contain no nodes.\n\t *\n\t * @returns {Array.<module:engine/model/range~Range>} Array of flat ranges covering this range.\n\t */\n\tgetMinimalFlatRanges() {\n\t\tconst ranges = [];\n\t\tconst diffAt = this.start.getCommonPath( this.end ).length;\n\n\t\tconst pos = Position._createAt( this.start );\n\t\tlet posParent = pos.parent;\n\n\t\t// Go up.\n\t\twhile ( pos.path.length > diffAt + 1 ) {\n\t\t\tconst howMany = posParent.maxOffset - pos.offset;\n\n\t\t\tif ( howMany !== 0 ) {\n\t\t\t\tranges.push( new Range( pos, pos.getShiftedBy( howMany ) ) );\n\t\t\t}\n\n\t\t\tpos.path = pos.path.slice( 0, -1 );\n\t\t\tpos.offset++;\n\t\t\tposParent = posParent.parent;\n\t\t}\n\n\t\t// Go down.\n\t\twhile ( pos.path.length <= this.end.path.length ) {\n\t\t\tconst offset = this.end.path[ pos.path.length - 1 ];\n\t\t\tconst howMany = offset - pos.offset;\n\n\t\t\tif ( howMany !== 0 ) {\n\t\t\t\tranges.push( new Range( pos, pos.getShiftedBy( howMany ) ) );\n\t\t\t}\n\n\t\t\tpos.offset = offset;\n\t\t\tpos.path.push( 0 );\n\t\t}\n\n\t\treturn ranges;\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/model/treewalker~TreeWalker TreeWalker} instance with this range as a boundary.\n\t *\n\t * For example, to iterate over all items in the entire document root:\n\t *\n\t *\t\t// Create a range spanning over the entire root content:\n\t *\t\tconst range = editor.model.createRangeIn( editor.model.document.getRoot() );\n\t *\n\t *\t\t// Iterate over all items in this range:\n\t *\t\tfor ( const value of range.getWalker() ) {\n\t *\t\t\tconsole.log( value.item );\n\t *\t\t}\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.\n\t * @param {module:engine/model/position~Position} [options.startPosition]\n\t * @param {Boolean} [options.singleCharacters=false]\n\t * @param {Boolean} [options.shallow=false]\n\t * @param {Boolean} [options.ignoreElementEnd=false]\n\t */\n\tgetWalker( options = {} ) {\n\t\toptions.boundaries = this;\n\n\t\treturn new TreeWalker( options );\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all {@link module:engine/model/item~Item items} that are in this range and returns\n\t * them.\n\t *\n\t * This method uses {@link module:engine/model/treewalker~TreeWalker} with `boundaries` set to this range and `ignoreElementEnd` option\n\t * set to `true`. However it returns only {@link module:engine/model/item~Item model items},\n\t * not {@link module:engine/model/treewalker~TreeWalkerValue}.\n\t *\n\t * You may specify additional options for the tree walker. See {@link module:engine/model/treewalker~TreeWalker} for\n\t * a full list of available options.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.\n\t * @returns {Iterable.<module:engine/model/item~Item>}\n\t */\n\t* getItems( options = {} ) {\n\t\toptions.boundaries = this;\n\t\toptions.ignoreElementEnd = true;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\n\t\tfor ( const value of treeWalker ) {\n\t\t\tyield value.item;\n\t\t}\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all {@link module:engine/model/position~Position positions} that are boundaries or\n\t * contained in this range.\n\t *\n\t * This method uses {@link module:engine/model/treewalker~TreeWalker} with `boundaries` set to this range. However it returns only\n\t * {@link module:engine/model/position~Position positions}, not {@link module:engine/model/treewalker~TreeWalkerValue}.\n\t *\n\t * You may specify additional options for the tree walker. See {@link module:engine/model/treewalker~TreeWalker} for\n\t * a full list of available options.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.\n\t * @returns {Iterable.<module:engine/model/position~Position>}\n\t */\n\t* getPositions( options = {} ) {\n\t\toptions.boundaries = this;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\n\t\tyield treeWalker.position;\n\n\t\tfor ( const value of treeWalker ) {\n\t\t\tyield value.nextPosition;\n\t\t}\n\t}\n\n\t/**\n\t * Returns a range that is a result of transforming this range by given `operation`.\n\t *\n\t * **Note:** transformation may break one range into multiple ranges (for example, when a part of the range is\n\t * moved to a different part of document tree). For this reason, an array is returned by this method and it\n\t * may contain one or more `Range` instances.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation Operation to transform range by.\n\t * @returns {Array.<module:engine/model/range~Range>} Range which is the result of transformation.\n\t */\n\tgetTransformedByOperation( operation ) {\n\t\tswitch ( operation.type ) {\n\t\t\tcase 'insert':\n\t\t\t\treturn this._getTransformedByInsertOperation( operation );\n\t\t\tcase 'move':\n\t\t\tcase 'remove':\n\t\t\tcase 'reinsert':\n\t\t\t\treturn this._getTransformedByMoveOperation( operation );\n\t\t\tcase 'split':\n\t\t\t\treturn [ this._getTransformedBySplitOperation( operation ) ];\n\t\t\tcase 'merge':\n\t\t\t\treturn [ this._getTransformedByMergeOperation( operation ) ];\n\t\t}\n\n\t\treturn [ new Range( this.start, this.end ) ];\n\t}\n\n\t/**\n\t * Returns a range that is a result of transforming this range by multiple `operations`.\n\t *\n\t * @see ~Range#getTransformedByOperation\n\t * @param {Iterable.<module:engine/model/operation/operation~Operation>} operations Operations to transform the range by.\n\t * @returns {Array.<module:engine/model/range~Range>} Range which is the result of transformation.\n\t */\n\tgetTransformedByOperations( operations ) {\n\t\tconst ranges = [ new Range( this.start, this.end ) ];\n\n\t\tfor ( const operation of operations ) {\n\t\t\tfor ( let i = 0; i < ranges.length; i++ ) {\n\t\t\t\tconst result = ranges[ i ].getTransformedByOperation( operation );\n\n\t\t\t\tranges.splice( i, 1, ...result );\n\t\t\t\ti += result.length - 1;\n\t\t\t}\n\t\t}\n\n\t\t// It may happen that a range is split into two, and then the part of second \"piece\" is moved into first\n\t\t// \"piece\". In this case we will have incorrect third range, which should not be included in the result --\n\t\t// because it is already included in the first \"piece\". In this loop we are looking for all such ranges that\n\t\t// are inside other ranges and we simply remove them.\n\t\tfor ( let i = 0; i < ranges.length; i++ ) {\n\t\t\tconst range = ranges[ i ];\n\n\t\t\tfor ( let j = i + 1; j < ranges.length; j++ ) {\n\t\t\t\tconst next = ranges[ j ];\n\n\t\t\t\tif ( range.containsRange( next ) || next.containsRange( range ) || range.isEqual( next ) ) {\n\t\t\t\t\tranges.splice( j, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn ranges;\n\t}\n\n\t/**\n\t * Returns an {@link module:engine/model/element~Element} or {@link module:engine/model/documentfragment~DocumentFragment}\n\t * which is a common ancestor of the range's both ends (in which the entire range is contained).\n\t *\n\t * @returns {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor() {\n\t\treturn this.start.getCommonAncestor( this.end );\n\t}\n\n\t/**\n\t * Returns an {@link module:engine/model/element~Element Element} contained by the range.\n\t * The element will be returned when it is the **only** node within the range and **fully–contained**\n\t * at the same time.\n\t *\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\tgetContainedElement() {\n\t\tif ( this.isCollapsed ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst nodeAfterStart = this.start.nodeAfter;\n\t\tconst nodeBeforeEnd = this.end.nodeBefore;\n\n\t\tif ( nodeAfterStart && nodeAfterStart.is( 'element' ) && nodeAfterStart === nodeBeforeEnd ) {\n\t\t\treturn nodeAfterStart;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Converts `Range` to plain object and returns it.\n\t *\n\t * @returns {Object} `Node` converted to plain object.\n\t */\n\ttoJSON() {\n\t\treturn {\n\t\t\tstart: this.start.toJSON(),\n\t\t\tend: this.end.toJSON()\n\t\t};\n\t}\n\n\t/**\n\t * Returns a new range that is equal to current range.\n\t *\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tclone() {\n\t\treturn new this.constructor( this.start, this.end );\n\t}\n\n\t/**\n\t * Returns a result of transforming a copy of this range by insert operation.\n\t *\n\t * One or more ranges may be returned as a result of this transformation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/insertoperation~InsertOperation} operation\n\t * @returns {Array.<module:engine/model/range~Range>}\n\t */\n\t_getTransformedByInsertOperation( operation, spread = false ) {\n\t\treturn this._getTransformedByInsertion( operation.position, operation.howMany, spread );\n\t}\n\n\t/**\n\t * Returns a result of transforming a copy of this range by move operation.\n\t *\n\t * One or more ranges may be returned as a result of this transformation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/moveoperation~MoveOperation} operation\n\t * @returns {Array.<module:engine/model/range~Range>}\n\t */\n\t_getTransformedByMoveOperation( operation, spread = false ) {\n\t\tconst sourcePosition = operation.sourcePosition;\n\t\tconst howMany = operation.howMany;\n\t\tconst targetPosition = operation.targetPosition;\n\n\t\treturn this._getTransformedByMove( sourcePosition, targetPosition, howMany, spread );\n\t}\n\n\t/**\n\t * Returns a result of transforming a copy of this range by split operation.\n\t *\n\t * Always one range is returned. The transformation is done in a way to not break the range.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/splitoperation~SplitOperation} operation\n\t * @returns {module:engine/model/range~Range}\n\t */\n\t_getTransformedBySplitOperation( operation ) {\n\t\tconst start = this.start._getTransformedBySplitOperation( operation );\n\t\tlet end = this.end._getTransformedBySplitOperation( operation );\n\n\t\tif ( this.end.isEqual( operation.insertionPosition ) ) {\n\t\t\tend = this.end.getShiftedBy( 1 );\n\t\t}\n\n\t\t// Below may happen when range contains graveyard element used by split operation.\n\t\tif ( start.root != end.root ) {\n\t\t\t// End position was next to the moved graveyard element and was moved with it.\n\t\t\t// Fix it by using old `end` which has proper `root`.\n\t\t\tend = this.end.getShiftedBy( -1 );\n\t\t}\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Returns a result of transforming a copy of this range by merge operation.\n\t *\n\t * Always one range is returned. The transformation is done in a way to not break the range.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/mergeoperation~MergeOperation} operation\n\t * @returns {module:engine/model/range~Range}\n\t */\n\t_getTransformedByMergeOperation( operation ) {\n\t\t// Special case when the marker is set on \"the closing tag\" of an element. Marker can be set like that during\n\t\t// transformations, especially when a content of a few block elements were removed. For example:\n\t\t//\n\t\t// {} is the transformed range, [] is the removed range.\n\t\t// <p>F[o{o</p><p>B}ar</p><p>Xy]z</p>\n\t\t//\n\t\t// <p>Fo{o</p><p>B}ar</p><p>z</p>\n\t\t// <p>F{</p><p>B}ar</p><p>z</p>\n\t\t// <p>F{</p>}<p>z</p>\n\t\t// <p>F{}z</p>\n\t\t//\n\t\tif ( this.start.isEqual( operation.targetPosition ) && this.end.isEqual( operation.deletionPosition ) ) {\n\t\t\treturn new Range( this.start );\n\t\t}\n\n\t\tlet start = this.start._getTransformedByMergeOperation( operation );\n\t\tlet end = this.end._getTransformedByMergeOperation( operation );\n\n\t\tif ( start.root != end.root ) {\n\t\t\t// This happens when the end position was next to the merged (deleted) element.\n\t\t\t// Then, the end position was moved to the graveyard root. In this case we need to fix\n\t\t\t// the range cause its boundaries would be in different roots.\n\t\t\tend = this.end.getShiftedBy( -1 );\n\t\t}\n\n\t\tif ( start.isAfter( end ) ) {\n\t\t\t// This happens in three following cases:\n\t\t\t//\n\t\t\t// Case 1: Merge operation source position is before the target position (due to some transformations, OT, etc.)\n\t\t\t//         This means that start can be moved before the end of the range.\n\t\t\t//\n\t\t\t// Before: <p>a{a</p><p>b}b</p><p>cc</p>\n\t\t\t// Merge:  <p>b}b</p><p>cca{a</p>\n\t\t\t// Fix:    <p>{b}b</p><p>ccaa</p>\n\t\t\t//\n\t\t\t// Case 2: Range start is before merged node but not directly.\n\t\t\t//         Result should include all nodes that were in the original range.\n\t\t\t//\n\t\t\t// Before: <p>aa</p>{<p>cc</p><p>b}b</p>\n\t\t\t// Merge:  <p>aab}b</p>{<p>cc</p>\n\t\t\t// Fix:    <p>aa{bb</p><p>cc</p>}\n\t\t\t//\n\t\t\t//         The range is expanded by an additional `b` letter but it is better than dropping the whole `cc` paragraph.\n\t\t\t//\n\t\t\t// Case 3: Range start is directly before merged node.\n\t\t\t//         Resulting range should include only nodes from the merged element:\n\t\t\t//\n\t\t\t// Before: <p>aa</p>{<p>b}b</p><p>cc</p>\n\t\t\t// Merge:  <p>aab}b</p>{<p>cc</p>\n\t\t\t// Fix:    <p>aa{b}b</p><p>cc</p>\n\t\t\t//\n\n\t\t\tif ( operation.sourcePosition.isBefore( operation.targetPosition ) ) {\n\t\t\t\t// Case 1.\n\t\t\t\tstart = Position._createAt( end );\n\t\t\t\tstart.offset = 0;\n\t\t\t} else {\n\t\t\t\tif ( !operation.deletionPosition.isEqual( start ) ) {\n\t\t\t\t\t// Case 2.\n\t\t\t\t\tend = operation.deletionPosition;\n\t\t\t\t}\n\n\t\t\t\t// In both case 2 and 3 start is at the end of the merge-to element.\n\t\t\t\tstart = operation.targetPosition;\n\t\t\t}\n\n\t\t\treturn new Range( start, end );\n\t\t}\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Returns an array containing one or two {@link ~Range ranges} that are a result of transforming this\n\t * {@link ~Range range} by inserting `howMany` nodes at `insertPosition`. Two {@link ~Range ranges} are\n\t * returned if the insertion was inside this {@link ~Range range} and `spread` is set to `true`.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet range = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2, 7 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 4, 0, 1 ] )\n\t *\t\t);\n\t *\t\tlet transformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 1 ] ), 2 );\n\t *\t\t// transformed array has one range from [ 4, 7 ] to [ 6, 0, 1 ]\n\t *\n\t *\t\ttransformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 4, 0, 0 ] ), 4 );\n\t *\t\t// transformed array has one range from [ 2, 7 ] to [ 4, 0, 5 ]\n\t *\n\t *\t\ttransformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 3, 2 ] ), 4 );\n\t *\t\t// transformed array has one range, which is equal to original range\n\t *\n\t *\t\ttransformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 3, 2 ] ), 4, true );\n\t *\t\t// transformed array has two ranges: from [ 2, 7 ] to [ 3, 2 ] and from [ 3, 6 ] to [ 4, 0, 1 ]\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} insertPosition Position where nodes are inserted.\n\t * @param {Number} howMany How many nodes are inserted.\n\t * @param {Boolean} [spread] Flag indicating whether this {~Range range} should be spread if insertion\n\t * was inside the range. Defaults to `false`.\n\t * @returns {Array.<module:engine/model/range~Range>} Result of the transformation.\n\t */\n\t_getTransformedByInsertion( insertPosition, howMany, spread = false ) {\n\t\tif ( spread && this.containsPosition( insertPosition ) ) {\n\t\t\t// Range has to be spread. The first part is from original start to the spread point.\n\t\t\t// The other part is from spread point to the original end, but transformed by\n\t\t\t// insertion to reflect insertion changes.\n\n\t\t\treturn [\n\t\t\t\tnew Range( this.start, insertPosition ),\n\t\t\t\tnew Range(\n\t\t\t\t\tinsertPosition.getShiftedBy( howMany ),\n\t\t\t\t\tthis.end._getTransformedByInsertion( insertPosition, howMany )\n\t\t\t\t)\n\t\t\t];\n\t\t} else {\n\t\t\tconst range = new Range( this.start, this.end );\n\n\t\t\trange.start = range.start._getTransformedByInsertion( insertPosition, howMany );\n\t\t\trange.end = range.end._getTransformedByInsertion( insertPosition, howMany );\n\n\t\t\treturn [ range ];\n\t\t}\n\t}\n\n\t/**\n\t * Returns an array containing {@link ~Range ranges} that are a result of transforming this\n\t * {@link ~Range range} by moving `howMany` nodes from `sourcePosition` to `targetPosition`.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} sourcePosition Position from which nodes are moved.\n\t * @param {module:engine/model/position~Position} targetPosition Position to where nodes are moved.\n\t * @param {Number} howMany How many nodes are moved.\n\t * @param {Boolean} [spread=false] Whether the range should be spread if the move points inside the range.\n\t * @returns {Array.<module:engine/model/range~Range>} Result of the transformation.\n\t */\n\t_getTransformedByMove( sourcePosition, targetPosition, howMany, spread = false ) {\n\t\t// Special case for transforming a collapsed range. Just transform it like a position.\n\t\tif ( this.isCollapsed ) {\n\t\t\tconst newPos = this.start._getTransformedByMove( sourcePosition, targetPosition, howMany );\n\n\t\t\treturn [ new Range( newPos ) ];\n\t\t}\n\n\t\t// Special case for transformation when a part of the range is moved towards the range.\n\t\t//\n\t\t// Examples:\n\t\t//\n\t\t// <div><p>ab</p><p>c[d</p></div><p>e]f</p> --> <div><p>ab</p></div><p>c[d</p><p>e]f</p>\n\t\t// <p>e[f</p><div><p>a]b</p><p>cd</p></div> --> <p>e[f</p><p>a]b</p><div><p>cd</p></div>\n\t\t//\n\t\t// Without this special condition, the default algorithm leaves an \"artifact\" range from one of `differenceSet` parts:\n\t\t//\n\t\t// <div><p>ab</p><p>c[d</p></div><p>e]f</p> --> <div><p>ab</p>{</div>}<p>c[d</p><p>e]f</p>\n\t\t//\n\t\t// This special case is applied only if the range is to be kept together (not spread).\n\t\tconst moveRange = Range._createFromPositionAndShift( sourcePosition, howMany );\n\t\tconst insertPosition = targetPosition._getTransformedByDeletion( sourcePosition, howMany );\n\n\t\tif ( this.containsPosition( targetPosition ) && !spread ) {\n\t\t\tif ( moveRange.containsPosition( this.start ) || moveRange.containsPosition( this.end ) ) {\n\t\t\t\tconst start = this.start._getTransformedByMove( sourcePosition, targetPosition, howMany );\n\t\t\t\tconst end = this.end._getTransformedByMove( sourcePosition, targetPosition, howMany );\n\n\t\t\t\treturn [ new Range( start, end ) ];\n\t\t\t}\n\t\t}\n\n\t\t// Default algorithm.\n\t\tlet result;\n\n\t\tconst differenceSet = this.getDifference( moveRange );\n\t\tlet difference = null;\n\n\t\tconst common = this.getIntersection( moveRange );\n\n\t\tif ( differenceSet.length == 1 ) {\n\t\t\t// `moveRange` and this range may intersect but may be separate.\n\t\t\tdifference = new Range(\n\t\t\t\tdifferenceSet[ 0 ].start._getTransformedByDeletion( sourcePosition, howMany ),\n\t\t\t\tdifferenceSet[ 0 ].end._getTransformedByDeletion( sourcePosition, howMany )\n\t\t\t);\n\t\t} else if ( differenceSet.length == 2 ) {\n\t\t\t// `moveRange` is inside this range.\n\t\t\tdifference = new Range(\n\t\t\t\tthis.start,\n\t\t\t\tthis.end._getTransformedByDeletion( sourcePosition, howMany )\n\t\t\t);\n\t\t} // else, `moveRange` contains this range.\n\n\t\tif ( difference ) {\n\t\t\tresult = difference._getTransformedByInsertion( insertPosition, howMany, common !== null || spread );\n\t\t} else {\n\t\t\tresult = [];\n\t\t}\n\n\t\tif ( common ) {\n\t\t\tconst transformedCommon = new Range(\n\t\t\t\tcommon.start._getCombined( moveRange.start, insertPosition ),\n\t\t\t\tcommon.end._getCombined( moveRange.start, insertPosition )\n\t\t\t);\n\n\t\t\tif ( result.length == 2 ) {\n\t\t\t\tresult.splice( 1, 0, transformedCommon );\n\t\t\t} else {\n\t\t\t\tresult.push( transformedCommon );\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns a copy of this range that is transformed by deletion of `howMany` nodes from `deletePosition`.\n\t *\n\t * If the deleted range is intersecting with the transformed range, the transformed range will be shrank.\n\t *\n\t * If the deleted range contains transformed range, `null` will be returned.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} deletionPosition Position from which nodes are removed.\n\t * @param {Number} howMany How many nodes are removed.\n\t * @returns {module:engine/model/range~Range|null} Result of the transformation.\n\t */\n\t_getTransformedByDeletion( deletePosition, howMany ) {\n\t\tlet newStart = this.start._getTransformedByDeletion( deletePosition, howMany );\n\t\tlet newEnd = this.end._getTransformedByDeletion( deletePosition, howMany );\n\n\t\tif ( newStart == null && newEnd == null ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( newStart == null ) {\n\t\t\tnewStart = deletePosition;\n\t\t}\n\n\t\tif ( newEnd == null ) {\n\t\t\tnewEnd = deletePosition;\n\t\t}\n\n\t\treturn new Range( newStart, newEnd );\n\t}\n\n\t/**\n\t * Creates a new range, spreading from specified {@link module:engine/model/position~Position position} to a position moved by\n\t * given `shift`. If `shift` is a negative value, shifted position is treated as the beginning of the range.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} position Beginning of the range.\n\t * @param {Number} shift How long the range should be.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tstatic _createFromPositionAndShift( position, shift ) {\n\t\tconst start = position;\n\t\tconst end = position.getShiftedBy( shift );\n\n\t\treturn shift > 0 ? new this( start, end ) : new this( end, start );\n\t}\n\n\t/**\n\t * Creates a range inside an {@link module:engine/model/element~Element element} which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t * @protected\n\t * @param {module:engine/model/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tstatic _createIn( element ) {\n\t\treturn new this( Position._createAt( element, 0 ), Position._createAt( element, element.maxOffset ) );\n\t}\n\n\t/**\n\t * Creates a range that starts before given {@link module:engine/model/item~Item model item} and ends after it.\n\t *\n\t * @protected\n\t * @param {module:engine/model/item~Item} item\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tstatic _createOn( item ) {\n\t\treturn this._createFromPositionAndShift( Position._createBefore( item ), item.offsetSize );\n\t}\n\n\t/**\n\t * Combines all ranges from the passed array into a one range. At least one range has to be passed.\n\t * Passed ranges must not have common parts.\n\t *\n\t * The first range from the array is a reference range. If other ranges start or end on the exactly same position where\n\t * the reference range, they get combined into one range.\n\t *\n\t *\t\t[  ][]  [    ][ ][             ][ ][]  [  ]  // Passed ranges, shown sorted\n\t *\t\t[    ]                                       // The result of the function if the first range was a reference range.\n\t *\t            [                           ]        // The result of the function if the third-to-seventh range was a reference range.\n\t *\t                                           [  ]  // The result of the function if the last range was a reference range.\n\t *\n\t * @param {Array.<module:engine/model/range~Range>} ranges Ranges to combine.\n\t * @returns {module:engine/model/range~Range} Combined range.\n\t */\n\tstatic _createFromRanges( ranges ) {\n\t\tif ( ranges.length === 0 ) {\n\t\t\t/**\n\t\t\t * At least one range has to be passed to\n\t\t\t * {@link module:engine/model/range~Range._createFromRanges `Range._createFromRanges()`}.\n\t\t\t *\n\t\t\t * @error range-create-from-ranges-empty-array\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'range-create-from-ranges-empty-array',\n\t\t\t\tnull\n\t\t\t);\n\t\t} else if ( ranges.length == 1 ) {\n\t\t\treturn ranges[ 0 ].clone();\n\t\t}\n\n\t\t// 1. Set the first range in `ranges` array as a reference range.\n\t\t// If we are going to return just a one range, one of the ranges need to be the reference one.\n\t\t// Other ranges will be stuck to that range, if possible.\n\t\tconst ref = ranges[ 0 ];\n\n\t\t// 2. Sort all the ranges so it's easier to process them.\n\t\tranges.sort( ( a, b ) => {\n\t\t\treturn a.start.isAfter( b.start ) ? 1 : -1;\n\t\t} );\n\n\t\t// 3. Check at which index the reference range is now.\n\t\tconst refIndex = ranges.indexOf( ref );\n\n\t\t// 4. At this moment we don't need the original range.\n\t\t// We are going to modify the result and we need to return a new instance of Range.\n\t\t// We have to create a copy of the reference range.\n\t\tconst result = new this( ref.start, ref.end );\n\n\t\t// 5. Ranges should be checked and glued starting from the range that is closest to the reference range.\n\t\t// Since ranges are sorted, start with the range with index that is closest to reference range index.\n\t\tif ( refIndex > 0 ) {\n\t\t\tfor ( let i = refIndex - 1; true; i++ ) {\n\t\t\t\tif ( ranges[ i ].end.isEqual( result.start ) ) {\n\t\t\t\t\tresult.start = Position._createAt( ranges[ i ].start );\n\t\t\t\t} else {\n\t\t\t\t\t// If ranges are not starting/ending at the same position there is no point in looking further.\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// 6. Ranges should be checked and glued starting from the range that is closest to the reference range.\n\t\t// Since ranges are sorted, start with the range with index that is closest to reference range index.\n\t\tfor ( let i = refIndex + 1; i < ranges.length; i++ ) {\n\t\t\tif ( ranges[ i ].start.isEqual( result.end ) ) {\n\t\t\t\tresult.end = Position._createAt( ranges[ i ].end );\n\t\t\t} else {\n\t\t\t\t// If ranges are not starting/ending at the same position there is no point in looking further.\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Creates a `Range` instance from given plain object (i.e. parsed JSON string).\n\t *\n\t * @param {Object} json Plain object to be converted to `Range`.\n\t * @param {module:engine/model/document~Document} doc Document object that will be range owner.\n\t * @returns {module:engine/model/element~Element} `Range` instance created using given plain object.\n\t */\n\tstatic fromJSON( json, doc ) {\n\t\treturn new this( Position.fromJSON( json.start, doc ), Position.fromJSON( json.end, doc ) );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `${ this.root } [ ${ this.start.path.join( ', ' ) } ] - [ ${ this.end.path.join( ', ' ) } ]`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelPosition: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/conversion/mapper\n */\n\nimport ModelPosition from '../model/position';\nimport ModelRange from '../model/range';\n\nimport ViewPosition from '../view/position';\nimport ViewRange from '../view/range';\nimport ViewText from '../view/text';\n\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Maps elements, positions and markers between {@link module:engine/view/document~Document the view} and\n * {@link module:engine/model/model the model}.\n *\n * The instance of the Mapper used for the editing pipeline is available in\n * {@link module:engine/controller/editingcontroller~EditingController#mapper `editor.editing.mapper`}.\n *\n * Mapper uses bound elements to find corresponding elements and positions, so, to get proper results,\n * all model elements should be {@link module:engine/conversion/mapper~Mapper#bindElements bound}.\n *\n * To map complex model to/from view relations, you may provide custom callbacks for\n * {@link module:engine/conversion/mapper~Mapper#event:modelToViewPosition modelToViewPosition event} and\n * {@link module:engine/conversion/mapper~Mapper#event:viewToModelPosition viewToModelPosition event} that are fired whenever\n * a position mapping request occurs.\n * Those events are fired by {@link module:engine/conversion/mapper~Mapper#toViewPosition toViewPosition}\n * and {@link module:engine/conversion/mapper~Mapper#toModelPosition toModelPosition} methods. `Mapper` adds it's own default callbacks\n * with `'lowest'` priority. To override default `Mapper` mapping, add custom callback with higher priority and\n * stop the event.\n */\nexport default class Mapper {\n\t/**\n\t * Creates an instance of the mapper.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Model element to view element mapping.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap}\n\t\t */\n\t\tthis._modelToViewMapping = new WeakMap();\n\n\t\t/**\n\t\t * View element to model element mapping.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap}\n\t\t */\n\t\tthis._viewToModelMapping = new WeakMap();\n\n\t\t/**\n\t\t * A map containing callbacks between view element names and functions evaluating length of view elements\n\t\t * in model.\n\t\t *\n\t\t * @private\n\t\t * @member {Map}\n\t\t */\n\t\tthis._viewToModelLengthCallbacks = new Map();\n\n\t\t/**\n\t\t * Model marker name to view elements mapping.\n\t\t *\n\t\t * Keys are `String`s while values are `Set`s with {@link module:engine/view/element~Element view elements}.\n\t\t * One marker (name) can be mapped to multiple elements.\n\t\t *\n\t\t * @private\n\t\t * @member {Map}\n\t\t */\n\t\tthis._markerNameToElements = new Map();\n\n\t\t/**\n\t\t * View element to model marker names mapping.\n\t\t *\n\t\t * This is reverse to {@link ~Mapper#_markerNameToElements} map.\n\t\t *\n\t\t * @private\n\t\t * @member {Map}\n\t\t */\n\t\tthis._elementToMarkerNames = new Map();\n\n\t\t/**\n\t\t * Stores marker names of markers which has changed due to unbinding a view element (so it is assumed that the view element\n\t\t * has been removed, moved or renamed).\n\t\t *\n\t\t * @private\n\t\t * @member {Set.<module:engine/model/markercollection~Marker>}\n\t\t */\n\t\tthis._unboundMarkerNames = new Set();\n\n\t\t// Default mapper algorithm for mapping model position to view position.\n\t\tthis.on( 'modelToViewPosition', ( evt, data ) => {\n\t\t\tif ( data.viewPosition ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst viewContainer = this._modelToViewMapping.get( data.modelPosition.parent );\n\n\t\t\tdata.viewPosition = this.findPositionIn( viewContainer, data.modelPosition.offset );\n\t\t}, { priority: 'low' } );\n\n\t\t// Default mapper algorithm for mapping view position to model position.\n\t\tthis.on( 'viewToModelPosition', ( evt, data ) => {\n\t\t\tif ( data.modelPosition ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst viewBlock = this.findMappedViewAncestor( data.viewPosition );\n\t\t\tconst modelParent = this._viewToModelMapping.get( viewBlock );\n\t\t\tconst modelOffset = this._toModelOffset( data.viewPosition.parent, data.viewPosition.offset, viewBlock );\n\n\t\t\tdata.modelPosition = ModelPosition._createAt( modelParent, modelOffset );\n\t\t}, { priority: 'low' } );\n\t}\n\n\t/**\n\t * Marks model and view elements as corresponding. Corresponding elements can be retrieved by using\n\t * the {@link module:engine/conversion/mapper~Mapper#toModelElement toModelElement} and\n\t * {@link module:engine/conversion/mapper~Mapper#toViewElement toViewElement} methods.\n\t * The information that elements are bound is also used to translate positions.\n\t *\n\t * @param {module:engine/model/element~Element} modelElement Model element.\n\t * @param {module:engine/view/element~Element} viewElement View element.\n\t */\n\tbindElements( modelElement, viewElement ) {\n\t\tthis._modelToViewMapping.set( modelElement, viewElement );\n\t\tthis._viewToModelMapping.set( viewElement, modelElement );\n\t}\n\n\t/**\n\t * Unbinds given {@link module:engine/view/element~Element view element} from the map.\n\t *\n\t * **Note:** view-to-model binding will be removed, if it existed. However, corresponding model-to-view binding\n\t * will be removed only if model element is still bound to passed `viewElement`.\n\t *\n\t * This behavior lets for re-binding model element to another view element without fear of losing the new binding\n\t * when the previously bound view element is unbound.\n\t *\n\t * @param {module:engine/view/element~Element} viewElement View element to unbind.\n\t */\n\tunbindViewElement( viewElement ) {\n\t\tconst modelElement = this.toModelElement( viewElement );\n\n\t\tthis._viewToModelMapping.delete( viewElement );\n\n\t\tif ( this._elementToMarkerNames.has( viewElement ) ) {\n\t\t\tfor ( const markerName of this._elementToMarkerNames.get( viewElement ) ) {\n\t\t\t\tthis._unboundMarkerNames.add( markerName );\n\t\t\t}\n\t\t}\n\n\t\tif ( this._modelToViewMapping.get( modelElement ) == viewElement ) {\n\t\t\tthis._modelToViewMapping.delete( modelElement );\n\t\t}\n\t}\n\n\t/**\n\t * Unbinds given {@link module:engine/model/element~Element model element} from the map.\n\t *\n\t * **Note:** model-to-view binding will be removed, if it existed. However, corresponding view-to-model binding\n\t * will be removed only if view element is still bound to passed `modelElement`.\n\t *\n\t * This behavior lets for re-binding view element to another model element without fear of losing the new binding\n\t * when the previously bound model element is unbound.\n\t *\n\t * @param {module:engine/model/element~Element} modelElement Model element to unbind.\n\t */\n\tunbindModelElement( modelElement ) {\n\t\tconst viewElement = this.toViewElement( modelElement );\n\n\t\tthis._modelToViewMapping.delete( modelElement );\n\n\t\tif ( this._viewToModelMapping.get( viewElement ) == modelElement ) {\n\t\t\tthis._viewToModelMapping.delete( viewElement );\n\t\t}\n\t}\n\n\t/**\n\t * Binds given marker name with given {@link module:engine/view/element~Element view element}. The element\n\t * will be added to the current set of elements bound with given marker name.\n\t *\n\t * @param {module:engine/view/element~Element} element Element to bind.\n\t * @param {String} name Marker name.\n\t */\n\tbindElementToMarker( element, name ) {\n\t\tconst elements = this._markerNameToElements.get( name ) || new Set();\n\t\telements.add( element );\n\n\t\tconst names = this._elementToMarkerNames.get( element ) || new Set();\n\t\tnames.add( name );\n\n\t\tthis._markerNameToElements.set( name, elements );\n\t\tthis._elementToMarkerNames.set( element, names );\n\t}\n\n\t/**\n\t * Unbinds an element from given marker name.\n\t *\n\t * @param {module:engine/view/element~Element} element Element to unbind.\n\t * @param {String} name Marker name.\n\t */\n\tunbindElementFromMarkerName( element, name ) {\n\t\tconst nameToElements = this._markerNameToElements.get( name );\n\n\t\tif ( nameToElements ) {\n\t\t\tnameToElements.delete( element );\n\n\t\t\tif ( nameToElements.size == 0 ) {\n\t\t\t\tthis._markerNameToElements.delete( name );\n\t\t\t}\n\t\t}\n\n\t\tconst elementToNames = this._elementToMarkerNames.get( element );\n\n\t\tif ( elementToNames ) {\n\t\t\telementToNames.delete( name );\n\n\t\t\tif ( elementToNames.size == 0 ) {\n\t\t\t\tthis._elementToMarkerNames.delete( element );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns all marker names of markers which has changed due to unbinding a view element (so it is assumed that the view element\n\t * has been removed, moved or renamed) since the last flush. After returning, the marker names list is cleared.\n\t *\n\t * @returns {Array.<String>}\n\t */\n\tflushUnboundMarkerNames() {\n\t\tconst markerNames = Array.from( this._unboundMarkerNames );\n\n\t\tthis._unboundMarkerNames.clear();\n\n\t\treturn markerNames;\n\t}\n\n\t/**\n\t * Removes all model to view and view to model bindings.\n\t */\n\tclearBindings() {\n\t\tthis._modelToViewMapping = new WeakMap();\n\t\tthis._viewToModelMapping = new WeakMap();\n\t\tthis._markerNameToElements = new Map();\n\t\tthis._elementToMarkerNames = new Map();\n\t\tthis._unboundMarkerNames = new Set();\n\t}\n\n\t/**\n\t * Gets the corresponding model element.\n\t *\n\t * **Note:** {@link module:engine/view/uielement~UIElement} does not have corresponding element in model.\n\t *\n\t * @param {module:engine/view/element~Element} viewElement View element.\n\t * @returns {module:engine/model/element~Element|undefined} Corresponding model element or `undefined` if not found.\n\t */\n\ttoModelElement( viewElement ) {\n\t\treturn this._viewToModelMapping.get( viewElement );\n\t}\n\n\t/**\n\t * Gets the corresponding view element.\n\t *\n\t * @param {module:engine/model/element~Element} modelElement Model element.\n\t * @returns {module:engine/view/element~Element|undefined} Corresponding view element or `undefined` if not found.\n\t */\n\ttoViewElement( modelElement ) {\n\t\treturn this._modelToViewMapping.get( modelElement );\n\t}\n\n\t/**\n\t * Gets the corresponding model range.\n\t *\n\t * @param {module:engine/view/range~Range} viewRange View range.\n\t * @returns {module:engine/model/range~Range} Corresponding model range.\n\t */\n\ttoModelRange( viewRange ) {\n\t\treturn new ModelRange( this.toModelPosition( viewRange.start ), this.toModelPosition( viewRange.end ) );\n\t}\n\n\t/**\n\t * Gets the corresponding view range.\n\t *\n\t * @param {module:engine/model/range~Range} modelRange Model range.\n\t * @returns {module:engine/view/range~Range} Corresponding view range.\n\t */\n\ttoViewRange( modelRange ) {\n\t\treturn new ViewRange( this.toViewPosition( modelRange.start ), this.toViewPosition( modelRange.end ) );\n\t}\n\n\t/**\n\t * Gets the corresponding model position.\n\t *\n\t * @fires viewToModelPosition\n\t * @param {module:engine/view/position~Position} viewPosition View position.\n\t * @returns {module:engine/model/position~Position} Corresponding model position.\n\t */\n\ttoModelPosition( viewPosition ) {\n\t\tconst data = {\n\t\t\tviewPosition,\n\t\t\tmapper: this\n\t\t};\n\n\t\tthis.fire( 'viewToModelPosition', data );\n\n\t\treturn data.modelPosition;\n\t}\n\n\t/**\n\t * Gets the corresponding view position.\n\t *\n\t * @fires modelToViewPosition\n\t * @param {module:engine/model/position~Position} modelPosition Model position.\n\t * @param {Object} [options] Additional options for position mapping process.\n\t * @param {Boolean} [options.isPhantom=false] Should be set to `true` if the model position to map is pointing to a place\n\t * in model tree which no longer exists. For example, it could be an end of a removed model range.\n\t * @returns {module:engine/view/position~Position} Corresponding view position.\n\t */\n\ttoViewPosition( modelPosition, options = { isPhantom: false } ) {\n\t\tconst data = {\n\t\t\tmodelPosition,\n\t\t\tmapper: this,\n\t\t\tisPhantom: options.isPhantom\n\t\t};\n\n\t\tthis.fire( 'modelToViewPosition', data );\n\n\t\treturn data.viewPosition;\n\t}\n\n\t/**\n\t * Gets all view elements bound to the given marker name.\n\t *\n\t * @param {String} name Marker name.\n\t * @returns {Set.<module:engine/view/element~Element>|null} View elements bound with given marker name or `null`\n\t * if no elements are bound to given marker name.\n\t */\n\tmarkerNameToElements( name ) {\n\t\tconst boundElements = this._markerNameToElements.get( name );\n\n\t\tif ( !boundElements ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst elements = new Set();\n\n\t\tfor ( const element of boundElements ) {\n\t\t\tif ( element.is( 'attributeElement' ) ) {\n\t\t\t\tfor ( const clone of element.getElementsWithSameId() ) {\n\t\t\t\t\telements.add( clone );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\telements.add( element );\n\t\t\t}\n\t\t}\n\n\t\treturn elements;\n\t}\n\n\t/**\n\t * Registers a callback that evaluates the length in the model of a view element with given name.\n\t *\n\t * The callback is fired with one argument, which is a view element instance. The callback is expected to return\n\t * a number representing the length of view element in model.\n\t *\n\t *\t\t// List item in view may contain nested list, which have other list items. In model though,\n\t *\t\t// the lists are represented by flat structure. Because of those differences, length of list view element\n\t *\t\t// may be greater than one. In the callback it's checked how many nested list items are in evaluated list item.\n\t *\n\t *\t\tfunction getViewListItemLength( element ) {\n\t *\t\t\tlet length = 1;\n\t *\n\t *\t\t\tfor ( let child of element.getChildren() ) {\n\t *\t\t\t\tif ( child.name == 'ul' || child.name == 'ol' ) {\n\t *\t\t\t\t\tfor ( let item of child.getChildren() ) {\n\t *\t\t\t\t\t\tlength += getViewListItemLength( item );\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\n\t *\t\t\treturn length;\n\t *\t\t}\n\t *\n\t *\t\tmapper.registerViewToModelLength( 'li', getViewListItemLength );\n\t *\n\t * @param {String} viewElementName Name of view element for which callback is registered.\n\t * @param {Function} lengthCallback Function return a length of view element instance in model.\n\t */\n\tregisterViewToModelLength( viewElementName, lengthCallback ) {\n\t\tthis._viewToModelLengthCallbacks.set( viewElementName, lengthCallback );\n\t}\n\n\t/**\n\t * For given `viewPosition`, finds and returns the closest ancestor of this position that has a mapping to\n\t * the model.\n\t *\n\t * @param {module:engine/view/position~Position} viewPosition Position for which mapped ancestor should be found.\n\t * @returns {module:engine/view/element~Element}\n\t */\n\tfindMappedViewAncestor( viewPosition ) {\n\t\tlet parent = viewPosition.parent;\n\n\t\twhile ( !this._viewToModelMapping.has( parent ) ) {\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn parent;\n\t}\n\n\t/**\n\t * Calculates model offset based on the view position and the block element.\n\t *\n\t * Example:\n\t *\n\t *\t\t<p>foo<b>ba|r</b></p> // _toModelOffset( b, 2, p ) -> 5\n\t *\n\t * Is a sum of:\n\t *\n\t *\t\t<p>foo|<b>bar</b></p> // _toModelOffset( p, 3, p ) -> 3\n\t *\t\t<p>foo<b>ba|r</b></p> // _toModelOffset( b, 2, b ) -> 2\n\t *\n\t * @private\n\t * @param {module:engine/view/element~Element} viewParent Position parent.\n\t * @param {Number} viewOffset Position offset.\n\t * @param {module:engine/view/element~Element} viewBlock Block used as a base to calculate offset.\n\t * @returns {Number} Offset in the model.\n\t */\n\t_toModelOffset( viewParent, viewOffset, viewBlock ) {\n\t\tif ( viewBlock != viewParent ) {\n\t\t\t// See example.\n\t\t\tconst offsetToParentStart = this._toModelOffset( viewParent.parent, viewParent.index, viewBlock );\n\t\t\tconst offsetInParent = this._toModelOffset( viewParent, viewOffset, viewParent );\n\n\t\t\treturn offsetToParentStart + offsetInParent;\n\t\t}\n\n\t\t// viewBlock == viewParent, so we need to calculate the offset in the parent element.\n\n\t\t// If the position is a text it is simple (\"ba|r\" -> 2).\n\t\tif ( viewParent.is( '$text' ) ) {\n\t\t\treturn viewOffset;\n\t\t}\n\n\t\t// If the position is in an element we need to sum lengths of siblings ( <b> bar </b> foo | -> 3 + 3 = 6 ).\n\t\tlet modelOffset = 0;\n\n\t\tfor ( let i = 0; i < viewOffset; i++ ) {\n\t\t\tmodelOffset += this.getModelLength( viewParent.getChild( i ) );\n\t\t}\n\n\t\treturn modelOffset;\n\t}\n\n\t/**\n\t * Gets the length of the view element in the model.\n\t *\n\t * The length is calculated as follows:\n\t * * if {@link #registerViewToModelLength length mapping callback} is provided for given `viewNode` it is used to\n\t * evaluate model length (`viewNode` is used as first and only parameter passed to the callback),\n\t * * length of a {@link module:engine/view/text~Text text node} is equal to the length of it's\n\t * {@link module:engine/view/text~Text#data data},\n\t * * length of a {@link module:engine/view/uielement~UIElement ui element} is equal to 0,\n\t * * length of a mapped {@link module:engine/view/element~Element element} is equal to 1,\n\t * * length of a not-mapped {@link module:engine/view/element~Element element} is equal to the length of it's children.\n\t *\n\t * Examples:\n\t *\n\t *\t\tfoo                          -> 3 // Text length is equal to it's data length.\n\t *\t\t<p>foo</p>                   -> 1 // Length of an element which is mapped is by default equal to 1.\n\t *\t\t<b>foo</b>                   -> 3 // Length of an element which is not mapped is a length of its children.\n\t *\t\t<div><p>x</p><p>y</p></div>  -> 2 // Assuming that <div> is not mapped and <p> are mapped.\n\t *\n\t * @param {module:engine/view/element~Element} viewNode View node.\n\t * @returns {Number} Length of the node in the tree model.\n\t */\n\tgetModelLength( viewNode ) {\n\t\tif ( this._viewToModelLengthCallbacks.get( viewNode.name ) ) {\n\t\t\tconst callback = this._viewToModelLengthCallbacks.get( viewNode.name );\n\n\t\t\treturn callback( viewNode );\n\t\t} else if ( this._viewToModelMapping.has( viewNode ) ) {\n\t\t\treturn 1;\n\t\t} else if ( viewNode.is( '$text' ) ) {\n\t\t\treturn viewNode.data.length;\n\t\t} else if ( viewNode.is( 'uiElement' ) ) {\n\t\t\treturn 0;\n\t\t} else {\n\t\t\tlet len = 0;\n\n\t\t\tfor ( const child of viewNode.getChildren() ) {\n\t\t\t\tlen += this.getModelLength( child );\n\t\t\t}\n\n\t\t\treturn len;\n\t\t}\n\t}\n\n\t/**\n\t * Finds the position in the view node (or its children) with the expected model offset.\n\t *\n\t * Example:\n\t *\n\t *\t\t<p>fo<b>bar</b>bom</p> -> expected offset: 4\n\t *\n\t *\t\tfindPositionIn( p, 4 ):\n\t *\t\t<p>|fo<b>bar</b>bom</p> -> expected offset: 4, actual offset: 0\n\t *\t\t<p>fo|<b>bar</b>bom</p> -> expected offset: 4, actual offset: 2\n\t *\t\t<p>fo<b>bar</b>|bom</p> -> expected offset: 4, actual offset: 5 -> we are too far\n\t *\n\t *\t\tfindPositionIn( b, 4 - ( 5 - 3 ) ):\n\t *\t\t<p>fo<b>|bar</b>bom</p> -> expected offset: 2, actual offset: 0\n\t *\t\t<p>fo<b>bar|</b>bom</p> -> expected offset: 2, actual offset: 3 -> we are too far\n\t *\n\t *\t\tfindPositionIn( bar, 2 - ( 3 - 3 ) ):\n\t *\t\tWe are in the text node so we can simple find the offset.\n\t *\t\t<p>fo<b>ba|r</b>bom</p> -> expected offset: 2, actual offset: 2 -> position found\n\t *\n\t * @param {module:engine/view/element~Element} viewParent Tree view element in which we are looking for the position.\n\t * @param {Number} expectedOffset Expected offset.\n\t * @returns {module:engine/view/position~Position} Found position.\n\t */\n\tfindPositionIn( viewParent, expectedOffset ) {\n\t\t// Last scanned view node.\n\t\tlet viewNode;\n\t\t// Length of the last scanned view node.\n\t\tlet lastLength = 0;\n\n\t\tlet modelOffset = 0;\n\t\tlet viewOffset = 0;\n\n\t\t// In the text node it is simple: offset in the model equals offset in the text.\n\t\tif ( viewParent.is( '$text' ) ) {\n\t\t\treturn new ViewPosition( viewParent, expectedOffset );\n\t\t}\n\n\t\t// In other cases we add lengths of child nodes to find the proper offset.\n\n\t\t// If it is smaller we add the length.\n\t\twhile ( modelOffset < expectedOffset ) {\n\t\t\tviewNode = viewParent.getChild( viewOffset );\n\t\t\tlastLength = this.getModelLength( viewNode );\n\t\t\tmodelOffset += lastLength;\n\t\t\tviewOffset++;\n\t\t}\n\n\t\t// If it equals we found the position.\n\t\tif ( modelOffset == expectedOffset ) {\n\t\t\treturn this._moveViewPositionToTextNode( new ViewPosition( viewParent, viewOffset ) );\n\t\t}\n\t\t// If it is higher we need to enter last child.\n\t\telse {\n\t\t\t// ( modelOffset - lastLength ) is the offset to the child we enter,\n\t\t\t// so we subtract it from the expected offset to fine the offset in the child.\n\t\t\treturn this.findPositionIn( viewNode, expectedOffset - ( modelOffset - lastLength ) );\n\t\t}\n\t}\n\n\t/**\n\t * Because we prefer positions in text nodes over positions next to text node moves view position to the text node\n\t * if it was next to it.\n\t *\n\t *\t\t<p>[]<b>foo</b></p> -> <p>[]<b>foo</b></p> // do not touch if position is not directly next to text\n\t *\t\t<p>foo[]<b>foo</b></p> -> <p>foo{}<b>foo</b></p> // move to text node\n\t *\t\t<p><b>[]foo</b></p> -> <p><b>{}foo</b></p> // move to text node\n\t *\n\t * @private\n\t * @param {module:engine/view/position~Position} viewPosition Position potentially next to text node.\n\t * @returns {module:engine/view/position~Position} Position in text node if possible.\n\t */\n\t_moveViewPositionToTextNode( viewPosition ) {\n\t\t// If the position is just after text node, put it at the end of that text node.\n\t\t// If the position is just before text node, put it at the beginning of that text node.\n\t\tconst nodeBefore = viewPosition.nodeBefore;\n\t\tconst nodeAfter = viewPosition.nodeAfter;\n\n\t\tif ( nodeBefore instanceof ViewText ) {\n\t\t\treturn new ViewPosition( nodeBefore, nodeBefore.data.length );\n\t\t} else if ( nodeAfter instanceof ViewText ) {\n\t\t\treturn new ViewPosition( nodeAfter, 0 );\n\t\t}\n\n\t\t// Otherwise, just return the given position.\n\t\treturn viewPosition;\n\t}\n\n\t/**\n\t * Fired for each model-to-view position mapping request. The purpose of this event is to enable custom model-to-view position\n\t * mapping. Callbacks added to this event take {@link module:engine/model/position~Position model position} and are expected to\n\t * calculate {@link module:engine/view/position~Position view position}. Calculated view position should be added as `viewPosition`\n\t * value in `data` object that is passed as one of parameters to the event callback.\n\t *\n\t * \t\t// Assume that \"captionedImage\" model element is converted to <img> and following <span> elements in view,\n\t * \t\t// and the model element is bound to <img> element. Force mapping model positions inside \"captionedImage\" to that\n\t * \t\t// <span> element.\n\t *\t\tmapper.on( 'modelToViewPosition', ( evt, data ) => {\n\t *\t\t\tconst positionParent = modelPosition.parent;\n\t *\n\t *\t\t\tif ( positionParent.name == 'captionedImage' ) {\n\t *\t\t\t\tconst viewImg = data.mapper.toViewElement( positionParent );\n\t *\t\t\t\tconst viewCaption = viewImg.nextSibling; // The <span> element.\n\t *\n\t *\t\t\t\tdata.viewPosition = new ViewPosition( viewCaption, modelPosition.offset );\n\t *\n\t *\t\t\t\t// Stop the event if other callbacks should not modify calculated value.\n\t *\t\t\t\tevt.stop();\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * **Note:** keep in mind that sometimes a \"phantom\" model position is being converted. \"Phantom\" model position is\n\t * a position that points to a non-existing place in model. Such position might still be valid for conversion, though\n\t * (it would point to a correct place in view when converted). One example of such situation is when a range is\n\t * removed from model, there may be a need to map the range's end (which is no longer valid model position). To\n\t * handle such situation, check `data.isPhantom` flag:\n\t *\n\t * \t\t// Assume that there is \"customElement\" model element and whenever position is before it, we want to move it\n\t * \t\t// to the inside of the view element bound to \"customElement\".\n\t *\t\tmapper.on( 'modelToViewPosition', ( evt, data ) => {\n\t *\t\t\tif ( data.isPhantom ) {\n\t *\t\t\t\treturn;\n\t *\t\t\t}\n\t *\n\t *\t\t\t// Below line might crash for phantom position that does not exist in model.\n\t *\t\t\tconst sibling = data.modelPosition.nodeBefore;\n\t *\n\t *\t\t\t// Check if this is the element we are interested in.\n\t *\t\t\tif ( !sibling.is( 'element', 'customElement' ) ) {\n\t *\t\t\t\treturn;\n\t *\t\t\t}\n\t *\n\t *\t\t\tconst viewElement = data.mapper.toViewElement( sibling );\n\t *\n\t *\t\t\tdata.viewPosition = new ViewPosition( sibling, 0 );\n\t *\n\t *\t\t\tevt.stop();\n\t *\t\t} );\n\t *\n\t * **Note:** default mapping callback is provided with `low` priority setting and does not cancel the event, so it is possible to\n\t * attach a custom callback after default callback and also use `data.viewPosition` calculated by default callback\n\t * (for example to fix it).\n\t *\n\t * **Note:** default mapping callback will not fire if `data.viewPosition` is already set.\n\t *\n\t * **Note:** these callbacks are called **very often**. For efficiency reasons, it is advised to use them only when position\n\t * mapping between given model and view elements is unsolvable using just elements mapping and default algorithm. Also,\n\t * the condition that checks if special case scenario happened should be as simple as possible.\n\t *\n\t * @event modelToViewPosition\n\t * @param {Object} data Data pipeline object that can store and pass data between callbacks. The callback should add\n\t * `viewPosition` value to that object with calculated {@link module:engine/view/position~Position view position}.\n\t * @param {module:engine/conversion/mapper~Mapper} data.mapper Mapper instance that fired the event.\n\t */\n\n\t/**\n\t * Fired for each view-to-model position mapping request. See {@link module:engine/conversion/mapper~Mapper#event:modelToViewPosition}.\n\t *\n\t * \t\t// See example in `modelToViewPosition` event description.\n\t * \t\t// This custom mapping will map positions from <span> element next to <img> to the \"captionedImage\" element.\n\t *\t\tmapper.on( 'viewToModelPosition', ( evt, data ) => {\n\t *\t\t\tconst positionParent = viewPosition.parent;\n\t *\n\t *\t\t\tif ( positionParent.hasClass( 'image-caption' ) ) {\n\t *\t\t\t\tconst viewImg = positionParent.previousSibling;\n\t *\t\t\t\tconst modelImg = data.mapper.toModelElement( viewImg );\n\t *\n\t *\t\t\t\tdata.modelPosition = new ModelPosition( modelImg, viewPosition.offset );\n\t *\t\t\t\tevt.stop();\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * **Note:** default mapping callback is provided with `low` priority setting and does not cancel the event, so it is possible to\n\t * attach a custom callback after default callback and also use `data.modelPosition` calculated by default callback\n\t * (for example to fix it).\n\t *\n\t * **Note:** default mapping callback will not fire if `data.modelPosition` is already set.\n\t *\n\t * **Note:** these callbacks are called **very often**. For efficiency reasons, it is advised to use them only when position\n\t * mapping between given model and view elements is unsolvable using just elements mapping and default algorithm. Also,\n\t * the condition that checks if special case scenario happened should be as simple as possible.\n\t *\n\t * @event viewToModelPosition\n\t * @param {Object} data Data pipeline object that can store and pass data between callbacks. The callback should add\n\t * `modelPosition` value to that object with calculated {@link module:engine/model/position~Position model position}.\n\t * @param {module:engine/conversion/mapper~Mapper} data.mapper Mapper instance that fired the event.\n\t */\n}\n\nmix( Mapper, EmitterMixin );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/conversion/modelconsumable\n */\n\nimport TextProxy from '../model/textproxy';\n\n/**\n * Manages a list of consumable values for {@link module:engine/model/item~Item model items}.\n *\n * Consumables are various aspects of the model. A model item can be broken down into singular properties that might be\n * taken into consideration when converting that item.\n *\n * `ModelConsumable` is used by {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher} while analyzing changed\n * parts of {@link module:engine/model/document~Document the document}. The added / changed / removed model items are broken down\n * into singular properties (the item itself and it's attributes). All those parts are saved in `ModelConsumable`. Then,\n * during conversion, when given part of model item is converted (i.e. the view element has been inserted into the view,\n * but without attributes), consumable value is removed from `ModelConsumable`.\n *\n * For model items, `ModelConsumable` stores consumable values of one of following types: `insert`, `addattribute:<attributeKey>`,\n * `changeattributes:<attributeKey>`, `removeattributes:<attributeKey>`.\n *\n * In most cases, it is enough to let {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}\n * gather consumable values, so there is no need to use\n * {@link module:engine/conversion/modelconsumable~ModelConsumable#add add method} directly.\n * However, it is important to understand how consumable values can be\n * {@link module:engine/conversion/modelconsumable~ModelConsumable#consume consumed}.\n * See {@link module:engine/conversion/downcasthelpers default downcast converters} for more information.\n *\n * Keep in mind, that one conversion event may have multiple callbacks (converters) attached to it. Each of those is\n * able to convert one or more parts of the model. However, when one of those callbacks actually converts\n * something, other should not, because they would duplicate the results. Using `ModelConsumable` helps avoiding\n * this situation, because callbacks should only convert those values, which were not yet consumed from `ModelConsumable`.\n *\n * Consuming multiple values in a single callback:\n *\n *\t\t// Converter for custom `image` element that might have a `caption` element inside which changes\n *\t\t// how the image is displayed in the view:\n *\t\t//\n *\t\t// Model:\n *\t\t//\n *\t\t// [image]\n *\t\t//   └─ [caption]\n *\t\t//       └─ foo\n *\t\t//\n *\t\t// View:\n *\t\t//\n *\t\t// <figure>\n *\t\t//   ├─ <img />\n *\t\t//   └─ <caption>\n *\t\t//       └─ foo\n *\t\tmodelConversionDispatcher.on( 'insert:image', ( evt, data, conversionApi ) => {\n *\t\t\t// First, consume the `image` element.\n *\t\t\tconversionApi.consumable.consume( data.item, 'insert' );\n *\n *\t\t\t// Just create normal image element for the view.\n *\t\t\t// Maybe it will be \"decorated\" later.\n *\t\t\tconst viewImage = new ViewElement( 'img' );\n *\t\t\tconst insertPosition = conversionApi.mapper.toViewPosition( data.range.start );\n *\t\t\tconst viewWriter = conversionApi.writer;\n *\n *\t\t\t// Check if the `image` element has children.\n *\t\t\tif ( data.item.childCount > 0 ) {\n *\t\t\t\tconst modelCaption = data.item.getChild( 0 );\n *\n *\t\t\t\t// `modelCaption` insertion change is consumed from consumable values.\n *\t\t\t\t// It will not be converted by other converters, but it's children (probably some text) will be.\n *\t\t\t\t// Through mapping, converters for text will know where to insert contents of `modelCaption`.\n *\t\t\t\tif ( conversionApi.consumable.consume( modelCaption, 'insert' ) ) {\n *\t\t\t\t\tconst viewCaption = new ViewElement( 'figcaption' );\n *\n *\t\t\t\t\tconst viewImageHolder = new ViewElement( 'figure', null, [ viewImage, viewCaption ] );\n *\n *\t\t\t\t\tconversionApi.mapper.bindElements( modelCaption, viewCaption );\n *\t\t\t\t\tconversionApi.mapper.bindElements( data.item, viewImageHolder );\n *\t\t\t\t\tviewWriter.insert( insertPosition, viewImageHolder );\n *\t\t\t\t}\n *\t\t\t} else {\n *\t\t\t\tconversionApi.mapper.bindElements( data.item, viewImage );\n *\t\t\t\tviewWriter.insert( insertPosition, viewImage );\n *\t\t\t}\n *\n *\t\t\tevt.stop();\n *\t\t} );\n */\nexport default class ModelConsumable {\n\t/**\n\t * Creates an empty consumables list.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Contains list of consumable values.\n\t\t *\n\t\t * @private\n\t\t * @member {Map} module:engine/conversion/modelconsumable~ModelConsumable#_consumable\n\t\t */\n\t\tthis._consumable = new Map();\n\n\t\t/**\n\t\t * For each {@link module:engine/model/textproxy~TextProxy} added to `ModelConsumable`, this registry holds parent\n\t\t * of that `TextProxy` and start and end indices of that `TextProxy`. This allows identification of `TextProxy`\n\t\t * instances that points to the same part of the model but are different instances. Each distinct `TextProxy`\n\t\t * is given unique `Symbol` which is then registered as consumable. This process is transparent for `ModelConsumable`\n\t\t * API user because whenever `TextProxy` is added, tested, consumed or reverted, internal mechanisms of\n\t\t * `ModelConsumable` translates `TextProxy` to that unique `Symbol`.\n\t\t *\n\t\t * @private\n\t\t * @member {Map} module:engine/conversion/modelconsumable~ModelConsumable#_textProxyRegistry\n\t\t */\n\t\tthis._textProxyRegistry = new Map();\n\t}\n\n\t/**\n\t * Adds a consumable value to the consumables list and links it with given model item.\n\t *\n\t *\t\tmodelConsumable.add( modelElement, 'insert' ); // Add `modelElement` insertion change to consumable values.\n\t *\t\tmodelConsumable.add( modelElement, 'addAttribute:bold' ); // Add `bold` attribute insertion on `modelElement` change.\n\t *\t\tmodelConsumable.add( modelElement, 'removeAttribute:bold' ); // Add `bold` attribute removal on `modelElement` change.\n\t *\t\tmodelConsumable.add( modelSelection, 'selection' ); // Add `modelSelection` to consumable values.\n\t *\t\tmodelConsumable.add( modelRange, 'range' ); // Add `modelRange` to consumable values.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/selection~Selection|module:engine/model/range~Range} item\n\t * Model item, range or selection that has the consumable.\n\t * @param {String} type Consumable type. Will be normalized to a proper form, that is either `<word>` or `<part>:<part>`.\n\t * Second colon and everything after will be cut. Passing event name is a safe and good practice.\n\t */\n\tadd( item, type ) {\n\t\ttype = _normalizeConsumableType( type );\n\n\t\tif ( item instanceof TextProxy ) {\n\t\t\titem = this._getSymbolForTextProxy( item );\n\t\t}\n\n\t\tif ( !this._consumable.has( item ) ) {\n\t\t\tthis._consumable.set( item, new Map() );\n\t\t}\n\n\t\tthis._consumable.get( item ).set( type, true );\n\t}\n\n\t/**\n\t * Removes given consumable value from given model item.\n\t *\n\t *\t\tmodelConsumable.consume( modelElement, 'insert' ); // Remove `modelElement` insertion change from consumable values.\n\t *\t\tmodelConsumable.consume( modelElement, 'addAttribute:bold' ); // Remove `bold` attribute insertion on `modelElement` change.\n\t *\t\tmodelConsumable.consume( modelElement, 'removeAttribute:bold' ); // Remove `bold` attribute removal on `modelElement` change.\n\t *\t\tmodelConsumable.consume( modelSelection, 'selection' ); // Remove `modelSelection` from consumable values.\n\t *\t\tmodelConsumable.consume( modelRange, 'range' ); // Remove 'modelRange' from consumable values.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/selection~Selection|module:engine/model/range~Range} item\n\t * Model item, range or selection from which consumable will be consumed.\n\t * @param {String} type Consumable type. Will be normalized to a proper form, that is either `<word>` or `<part>:<part>`.\n\t * Second colon and everything after will be cut. Passing event name is a safe and good practice.\n\t * @returns {Boolean} `true` if consumable value was available and was consumed, `false` otherwise.\n\t */\n\tconsume( item, type ) {\n\t\ttype = _normalizeConsumableType( type );\n\n\t\tif ( item instanceof TextProxy ) {\n\t\t\titem = this._getSymbolForTextProxy( item );\n\t\t}\n\n\t\tif ( this.test( item, type ) ) {\n\t\t\tthis._consumable.get( item ).set( type, false );\n\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Tests whether there is a consumable value of given type connected with given model item.\n\t *\n\t *\t\tmodelConsumable.test( modelElement, 'insert' ); // Check for `modelElement` insertion change.\n\t *\t\tmodelConsumable.test( modelElement, 'addAttribute:bold' ); // Check for `bold` attribute insertion on `modelElement` change.\n\t *\t\tmodelConsumable.test( modelElement, 'removeAttribute:bold' ); // Check for `bold` attribute removal on `modelElement` change.\n\t *\t\tmodelConsumable.test( modelSelection, 'selection' ); // Check if `modelSelection` is consumable.\n\t *\t\tmodelConsumable.test( modelRange, 'range' ); // Check if `modelRange` is consumable.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/selection~Selection|module:engine/model/range~Range} item\n\t * Model item, range or selection to be tested.\n\t * @param {String} type Consumable type. Will be normalized to a proper form, that is either `<word>` or `<part>:<part>`.\n\t * Second colon and everything after will be cut. Passing event name is a safe and good practice.\n\t * @returns {null|Boolean} `null` if such consumable was never added, `false` if the consumable values was\n\t * already consumed or `true` if it was added and not consumed yet.\n\t */\n\ttest( item, type ) {\n\t\ttype = _normalizeConsumableType( type );\n\n\t\tif ( item instanceof TextProxy ) {\n\t\t\titem = this._getSymbolForTextProxy( item );\n\t\t}\n\n\t\tconst itemConsumables = this._consumable.get( item );\n\n\t\tif ( itemConsumables === undefined ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst value = itemConsumables.get( type );\n\n\t\tif ( value === undefined ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn value;\n\t}\n\n\t/**\n\t * Reverts consuming of consumable value.\n\t *\n\t *\t\tmodelConsumable.revert( modelElement, 'insert' ); // Revert consuming `modelElement` insertion change.\n\t *\t\tmodelConsumable.revert( modelElement, 'addAttribute:bold' ); // Revert consuming `bold` attribute insert from `modelElement`.\n\t *\t\tmodelConsumable.revert( modelElement, 'removeAttribute:bold' ); // Revert consuming `bold` attribute remove from `modelElement`.\n\t *\t\tmodelConsumable.revert( modelSelection, 'selection' ); // Revert consuming `modelSelection`.\n\t *\t\tmodelConsumable.revert( modelRange, 'range' ); // Revert consuming `modelRange`.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/selection~Selection|module:engine/model/range~Range} item\n\t * Model item, range or selection to be reverted.\n\t * @param {String} type Consumable type.\n\t * @returns {null|Boolean} `true` if consumable has been reversed, `false` otherwise. `null` if the consumable has\n\t * never been added.\n\t */\n\trevert( item, type ) {\n\t\ttype = _normalizeConsumableType( type );\n\n\t\tif ( item instanceof TextProxy ) {\n\t\t\titem = this._getSymbolForTextProxy( item );\n\t\t}\n\n\t\tconst test = this.test( item, type );\n\n\t\tif ( test === false ) {\n\t\t\tthis._consumable.get( item ).set( type, true );\n\n\t\t\treturn true;\n\t\t} else if ( test === true ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Gets a unique symbol for passed {@link module:engine/model/textproxy~TextProxy} instance. All `TextProxy` instances that\n\t * have same parent, same start index and same end index will get the same symbol.\n\t *\n\t * Used internally to correctly consume `TextProxy` instances.\n\t *\n\t * @private\n\t * @param {module:engine/model/textproxy~TextProxy} textProxy `TextProxy` instance to get a symbol for.\n\t * @returns {Symbol} Symbol representing all equal instances of `TextProxy`.\n\t */\n\t_getSymbolForTextProxy( textProxy ) {\n\t\tlet symbol = null;\n\n\t\tconst startMap = this._textProxyRegistry.get( textProxy.startOffset );\n\n\t\tif ( startMap ) {\n\t\t\tconst endMap = startMap.get( textProxy.endOffset );\n\n\t\t\tif ( endMap ) {\n\t\t\t\tsymbol = endMap.get( textProxy.parent );\n\t\t\t}\n\t\t}\n\n\t\tif ( !symbol ) {\n\t\t\tsymbol = this._addSymbolForTextProxy( textProxy.startOffset, textProxy.endOffset, textProxy.parent );\n\t\t}\n\n\t\treturn symbol;\n\t}\n\n\t/**\n\t * Adds a symbol for given properties that characterizes a {@link module:engine/model/textproxy~TextProxy} instance.\n\t *\n\t * Used internally to correctly consume `TextProxy` instances.\n\t *\n\t * @private\n\t * @param {Number} startIndex Text proxy start index in it's parent.\n\t * @param {Number} endIndex Text proxy end index in it's parent.\n\t * @param {module:engine/model/element~Element} parent Text proxy parent.\n\t * @returns {Symbol} Symbol generated for given properties.\n\t */\n\t_addSymbolForTextProxy( start, end, parent ) {\n\t\tconst symbol = Symbol( 'textProxySymbol' );\n\t\tlet startMap, endMap;\n\n\t\tstartMap = this._textProxyRegistry.get( start );\n\n\t\tif ( !startMap ) {\n\t\t\tstartMap = new Map();\n\t\t\tthis._textProxyRegistry.set( start, startMap );\n\t\t}\n\n\t\tendMap = startMap.get( end );\n\n\t\tif ( !endMap ) {\n\t\t\tendMap = new Map();\n\t\t\tstartMap.set( end, endMap );\n\t\t}\n\n\t\tendMap.set( parent, symbol );\n\n\t\treturn symbol;\n\t}\n}\n\n// Returns a normalized consumable type name from given string. A normalized consumable type name is a string that has\n// at most one colon, for example: `insert` or `addMarker:highlight`. If string to normalize has more \"parts\" (more colons),\n// the other parts are dropped, for example: `addattribute:bold:$text` -> `addattributes:bold`.\n//\n// @param {String} type Consumable type.\n// @returns {String} Normalized consumable type.\nfunction _normalizeConsumableType( type ) {\n\tconst parts = type.split( ':' );\n\n\treturn parts.length > 1 ? parts[ 0 ] + ':' + parts[ 1 ] : parts[ 0 ];\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/conversion/downcastdispatcher\n */\n\nimport Consumable from './modelconsumable';\nimport Range from '../model/range';\nimport Position, { getNodeAfterPosition, getTextNodeAtPosition } from '../model/position';\n\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * The downcast dispatcher is a central point of downcasting (conversion from the model to the view), which is a process of reacting\n * to changes in the model and firing a set of events. Callbacks listening to these events are called converters. The\n * converters' role is to convert the model changes to changes in view (for example, adding view nodes or\n * changing attributes on view elements).\n *\n * During the conversion process, downcast dispatcher fires events basing on the state of the model and prepares\n * data for these events. It is important to understand that the events are connected with the changes done on the model,\n * for example: \"a node has been inserted\" or \"an attribute has changed\". This is in contrary to upcasting (a view-to-model conversion)\n * where you convert the view state (view nodes) to a model tree.\n *\n * The events are prepared basing on a diff created by {@link module:engine/model/differ~Differ Differ}, which buffers them\n * and then passes to the downcast dispatcher as a diff between the old model state and the new model state.\n *\n * Note that because the changes are converted, there is a need to have a mapping between the model structure and the view structure.\n * To map positions and elements during the downcast (a model-to-view conversion), use {@link module:engine/conversion/mapper~Mapper}.\n *\n * Downcast dispatcher fires the following events for model tree changes:\n *\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert `insert`} &ndash;\n * If a range of nodes was inserted to the model tree.\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:remove `remove`} &ndash;\n * If a range of nodes was removed from the model tree.\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute `attribute`} &ndash;\n * If an attribute was added, changed or removed from a model node.\n *\n * For {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert `insert`}\n * and {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute `attribute`},\n * downcast dispatcher generates {@link module:engine/conversion/modelconsumable~ModelConsumable consumables}.\n * These are used to have control over which changes have already been consumed. It is useful when some converters\n * overwrite others or convert multiple changes (for example, it converts an insertion of an element and also converts that\n * element's attributes during the insertion).\n *\n * Additionally, downcast dispatcher fires events for {@link module:engine/model/markercollection~Marker marker} changes:\n *\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker} &ndash; If a marker was added.\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:removeMarker} &ndash; If a marker was removed.\n *\n * Note that changing a marker is done through removing the marker from the old range and adding it to the new range,\n * so both events are fired.\n *\n * Finally, downcast dispatcher also handles firing events for the {@link module:engine/model/selection model selection}\n * conversion:\n *\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:selection}\n * &ndash; Converts the selection from the model to the view.\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute}\n * &ndash; Fired for every selection attribute.\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}\n * &ndash; Fired for every marker that contains a selection.\n *\n * Unlike the model tree and the markers, the events for selection are not fired for changes but for a selection state.\n *\n * When providing custom listeners for a downcast dispatcher, remember to check whether a given change has not been\n * {@link module:engine/conversion/modelconsumable~ModelConsumable#consume consumed} yet.\n *\n * When providing custom listeners for downcast dispatcher, keep in mind that any callback that has\n * {@link module:engine/conversion/modelconsumable~ModelConsumable#consume consumed} a value from a consumable and\n * converted the change should also stop the event (for efficiency purposes).\n *\n * When providing custom listeners for downcast dispatcher, remember to use the provided\n * {@link module:engine/view/downcastwriter~DowncastWriter view downcast writer} to apply changes to the view document.\n *\n * You can read more about conversion in the following guides:\n *\n * * {@glink framework/guides/deep-dive/conversion/conversion-introduction Advanced conversion concepts &mdash; attributes}\n * * {@glink framework/guides/deep-dive/conversion/conversion-extending-output Extending the editor output }\n * * {@glink framework/guides/deep-dive/conversion/custom-element-conversion Custom element conversion}\n *\n * An example of a custom converter for the downcast dispatcher:\n *\n *\t\t// You will convert inserting a \"paragraph\" model element into the model.\n *\t\tdowncastDispatcher.on( 'insert:paragraph', ( evt, data, conversionApi ) => {\n *\t\t\t// Remember to check whether the change has not been consumed yet and consume it.\n *\t\t\tif ( conversionApi.consumable.consume( data.item, 'insert' ) ) {\n *\t\t\t\treturn;\n *\t\t\t}\n *\n *\t\t\t// Translate the position in the model to a position in the view.\n *\t\t\tconst viewPosition = conversionApi.mapper.toViewPosition( data.range.start );\n *\n *\t\t\t// Create a <p> element that will be inserted into the view at the `viewPosition`.\n *\t\t\tconst viewElement = conversionApi.writer.createContainerElement( 'p' );\n *\n *\t\t\t// Bind the newly created view element to the model element so positions will map accordingly in the future.\n *\t\t\tconversionApi.mapper.bindElements( data.item, viewElement );\n *\n *\t\t\t// Add the newly created view element to the view.\n *\t\t\tconversionApi.writer.insert( viewPosition, viewElement );\n *\n *\t\t\t// Remember to stop the event propagation.\n *\t\t\tevt.stop();\n *\t\t} );\n */\nexport default class DowncastDispatcher {\n\t/**\n\t * Creates a downcast dispatcher instance.\n\t *\n\t * @see module:engine/conversion/downcastdispatcher~DowncastConversionApi\n\t * @param {Object} conversionApi Additional properties for an interface that will be passed to events fired\n\t * by the downcast dispatcher.\n\t */\n\tconstructor( conversionApi ) {\n\t\t/**\n\t\t * An interface passed by the dispatcher to the event callbacks.\n\t\t *\n\t\t * @member {module:engine/conversion/downcastdispatcher~DowncastConversionApi}\n\t\t */\n\t\tthis.conversionApi = Object.assign( { dispatcher: this }, conversionApi );\n\n\t\t/**\n\t\t * Maps conversion event names that will trigger element reconversion for a given element name.\n\t\t *\n\t\t * @type {Map<String, String>}\n\t\t * @private\n\t\t */\n\t\tthis._reconversionEventsMapping = new Map();\n\t}\n\n\t/**\n\t * Takes a {@link module:engine/model/differ~Differ model differ} object with buffered changes and fires conversion basing on it.\n\t *\n\t * @param {module:engine/model/differ~Differ} differ The differ object with buffered changes.\n\t * @param {module:engine/model/markercollection~MarkerCollection} markers Markers connected with the converted model.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer that should be used to modify the view document.\n\t */\n\tconvertChanges( differ, markers, writer ) {\n\t\t// Before the view is updated, remove markers which have changed.\n\t\tfor ( const change of differ.getMarkersToRemove() ) {\n\t\t\tthis.convertMarkerRemove( change.name, change.range, writer );\n\t\t}\n\n\t\tconst changes = this._mapChangesWithAutomaticReconversion( differ );\n\n\t\t// Convert changes that happened on model tree.\n\t\tfor ( const entry of changes ) {\n\t\t\tif ( entry.type === 'insert' ) {\n\t\t\t\tthis.convertInsert( Range._createFromPositionAndShift( entry.position, entry.length ), writer );\n\t\t\t} else if ( entry.type === 'remove' ) {\n\t\t\t\tthis.convertRemove( entry.position, entry.length, entry.name, writer );\n\t\t\t} else if ( entry.type === 'reconvert' ) {\n\t\t\t\tthis.reconvertElement( entry.element, writer );\n\t\t\t} else {\n\t\t\t\t// Defaults to 'attribute' change.\n\t\t\t\tthis.convertAttribute( entry.range, entry.attributeKey, entry.attributeOldValue, entry.attributeNewValue, writer );\n\t\t\t}\n\t\t}\n\n\t\tfor ( const markerName of this.conversionApi.mapper.flushUnboundMarkerNames() ) {\n\t\t\tconst markerRange = markers.get( markerName ).getRange();\n\n\t\t\tthis.convertMarkerRemove( markerName, markerRange, writer );\n\t\t\tthis.convertMarkerAdd( markerName, markerRange, writer );\n\t\t}\n\n\t\t// After the view is updated, convert markers which have changed.\n\t\tfor ( const change of differ.getMarkersToAdd() ) {\n\t\t\tthis.convertMarkerAdd( change.name, change.range, writer );\n\t\t}\n\t}\n\n\t/**\n\t * Starts a conversion of a range insertion.\n\t *\n\t * For each node in the range, {@link #event:insert `insert` event is fired}. For each attribute on each node,\n\t * {@link #event:attribute `attribute` event is fired}.\n\t *\n\t * @fires insert\n\t * @fires attribute\n\t * @param {module:engine/model/range~Range} range The inserted range.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer that should be used to modify the view document.\n\t */\n\tconvertInsert( range, writer ) {\n\t\tthis.conversionApi.writer = writer;\n\n\t\t// Create a list of things that can be consumed, consisting of nodes and their attributes.\n\t\tthis.conversionApi.consumable = this._createInsertConsumable( range );\n\n\t\t// Fire a separate insert event for each node and text fragment contained in the range.\n\t\tfor ( const data of Array.from( range ).map( walkerValueToEventData ) ) {\n\t\t\tthis._convertInsertWithAttributes( data );\n\t\t}\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Fires conversion of a single node removal. Fires {@link #event:remove remove event} with provided data.\n\t *\n\t * @param {module:engine/model/position~Position} position Position from which node was removed.\n\t * @param {Number} length Offset size of removed node.\n\t * @param {String} name Name of removed node.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document.\n\t */\n\tconvertRemove( position, length, name, writer ) {\n\t\tthis.conversionApi.writer = writer;\n\n\t\tthis.fire( 'remove:' + name, { position, length }, this.conversionApi );\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Starts a conversion of an attribute change on a given `range`.\n\t *\n\t * For each node in the given `range`, {@link #event:attribute attribute event} is fired with the passed data.\n\t *\n\t * @fires attribute\n\t * @param {module:engine/model/range~Range} range Changed range.\n\t * @param {String} key Key of the attribute that has changed.\n\t * @param {*} oldValue Attribute value before the change or `null` if the attribute has not been set before.\n\t * @param {*} newValue New attribute value or `null` if the attribute has been removed.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document.\n\t */\n\tconvertAttribute( range, key, oldValue, newValue, writer ) {\n\t\tthis.conversionApi.writer = writer;\n\n\t\t// Create a list with attributes to consume.\n\t\tthis.conversionApi.consumable = this._createConsumableForRange( range, `attribute:${ key }` );\n\n\t\t// Create a separate attribute event for each node in the range.\n\t\tfor ( const value of range ) {\n\t\t\tconst item = value.item;\n\t\t\tconst itemRange = Range._createFromPositionAndShift( value.previousPosition, value.length );\n\t\t\tconst data = {\n\t\t\t\titem,\n\t\t\t\trange: itemRange,\n\t\t\t\tattributeKey: key,\n\t\t\t\tattributeOldValue: oldValue,\n\t\t\t\tattributeNewValue: newValue\n\t\t\t};\n\n\t\t\tthis._testAndFire( `attribute:${ key }`, data );\n\t\t}\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Starts the reconversion of an element. It will:\n\t *\n\t * * Fire an {@link #event:insert `insert` event} for the element to reconvert.\n\t * * Fire an {@link #event:attribute `attribute` event} for element attributes.\n\t *\n\t * This will not reconvert children of the element if they have existing (already converted) views. For newly inserted child elements\n\t * it will behave the same as {@link #convertInsert}.\n\t *\n\t * Element reconversion is defined by the `triggerBy` configuration for the\n\t * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`} conversion helper.\n\t *\n\t * @fires insert\n\t * @fires attribute\n\t * @param {module:engine/model/element~Element} element The element to be reconverted.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer that should be used to modify the view document.\n\t */\n\treconvertElement( element, writer ) {\n\t\tconst elementRange = Range._createOn( element );\n\n\t\tthis.conversionApi.writer = writer;\n\n\t\t// Create a list of things that can be consumed, consisting of nodes and their attributes.\n\t\tthis.conversionApi.consumable = this._createInsertConsumable( elementRange );\n\n\t\tconst mapper = this.conversionApi.mapper;\n\t\tconst currentView = mapper.toViewElement( element );\n\n\t\t// Remove the old view but do not remove mapper mappings - those will be used to revive existing elements.\n\t\twriter.remove( currentView );\n\n\t\t// Convert the element - without converting children.\n\t\tthis._convertInsertWithAttributes( {\n\t\t\titem: element,\n\t\t\trange: elementRange\n\t\t} );\n\n\t\tconst convertedViewElement = mapper.toViewElement( element );\n\n\t\t// Iterate over children of reconverted element in order to...\n\t\tfor ( const value of Range._createIn( element ) ) {\n\t\t\tconst { item } = value;\n\n\t\t\tconst view = elementOrTextProxyToView( item, mapper );\n\n\t\t\t// ...either bring back previously converted view...\n\t\t\tif ( view ) {\n\t\t\t\t// Do not move views that are already in converted element - those might be created by the main element converter in case\n\t\t\t\t// when main element converts also its direct children.\n\t\t\t\tif ( view.root !== convertedViewElement.root ) {\n\t\t\t\t\twriter.move(\n\t\t\t\t\t\twriter.createRangeOn( view ),\n\t\t\t\t\t\tmapper.toViewPosition( Position._createBefore( item ) )\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// ... or by converting newly inserted elements.\n\t\t\telse {\n\t\t\t\tthis._convertInsertWithAttributes( walkerValueToEventData( value ) );\n\t\t\t}\n\t\t}\n\n\t\t// After reconversion is done we can unbind the old view.\n\t\tmapper.unbindViewElement( currentView );\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Starts the model selection conversion.\n\t *\n\t * Fires events for a given {@link module:engine/model/selection~Selection selection} to start the selection conversion.\n\t *\n\t * @fires selection\n\t * @fires addMarker\n\t * @fires attribute\n\t * @param {module:engine/model/selection~Selection} selection The selection to convert.\n\t * @param {module:engine/model/markercollection~MarkerCollection} markers Markers connected with the converted model.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify the view document.\n\t */\n\tconvertSelection( selection, markers, writer ) {\n\t\tconst markersAtSelection = Array.from( markers.getMarkersAtPosition( selection.getFirstPosition() ) );\n\n\t\tthis.conversionApi.writer = writer;\n\t\tthis.conversionApi.consumable = this._createSelectionConsumable( selection, markersAtSelection );\n\n\t\tthis.fire( 'selection', { selection }, this.conversionApi );\n\n\t\tif ( !selection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const marker of markersAtSelection ) {\n\t\t\tconst markerRange = marker.getRange();\n\n\t\t\tif ( !shouldMarkerChangeBeConverted( selection.getFirstPosition(), marker, this.conversionApi.mapper ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst data = {\n\t\t\t\titem: selection,\n\t\t\t\tmarkerName: marker.name,\n\t\t\t\tmarkerRange\n\t\t\t};\n\n\t\t\tif ( this.conversionApi.consumable.test( selection, 'addMarker:' + marker.name ) ) {\n\t\t\t\tthis.fire( 'addMarker:' + marker.name, data, this.conversionApi );\n\t\t\t}\n\t\t}\n\n\t\tfor ( const key of selection.getAttributeKeys() ) {\n\t\t\tconst data = {\n\t\t\t\titem: selection,\n\t\t\t\trange: selection.getFirstRange(),\n\t\t\t\tattributeKey: key,\n\t\t\t\tattributeOldValue: null,\n\t\t\t\tattributeNewValue: selection.getAttribute( key )\n\t\t\t};\n\n\t\t\t// Do not fire event if the attribute has been consumed.\n\t\t\tif ( this.conversionApi.consumable.test( selection, 'attribute:' + data.attributeKey ) ) {\n\t\t\t\tthis.fire( 'attribute:' + data.attributeKey + ':$text', data, this.conversionApi );\n\t\t\t}\n\t\t}\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Converts the added marker. Fires the {@link #event:addMarker `addMarker`} event for each item\n\t * in the marker's range. If the range is collapsed, a single event is dispatched. See the event description for more details.\n\t *\n\t * @fires addMarker\n\t * @param {String} markerName Marker name.\n\t * @param {module:engine/model/range~Range} markerRange The marker range.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify the view document.\n\t */\n\tconvertMarkerAdd( markerName, markerRange, writer ) {\n\t\t// Do not convert if range is in graveyard or not in the document (e.g. in DocumentFragment).\n\t\tif ( !markerRange.root.document || markerRange.root.rootName == '$graveyard' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.conversionApi.writer = writer;\n\n\t\t// In markers' case, event name == consumable name.\n\t\tconst eventName = 'addMarker:' + markerName;\n\n\t\t//\n\t\t// First, fire an event for the whole marker.\n\t\t//\n\t\tconst consumable = new Consumable();\n\t\tconsumable.add( markerRange, eventName );\n\n\t\tthis.conversionApi.consumable = consumable;\n\n\t\tthis.fire( eventName, { markerName, markerRange }, this.conversionApi );\n\n\t\t//\n\t\t// Do not fire events for each item inside the range if the range got consumed.\n\t\t//\n\t\tif ( !consumable.test( markerRange, eventName ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t//\n\t\t// Then, fire an event for each item inside the marker range.\n\t\t//\n\t\tthis.conversionApi.consumable = this._createConsumableForRange( markerRange, eventName );\n\n\t\tfor ( const item of markerRange.getItems() ) {\n\t\t\t// Do not fire event for already consumed items.\n\t\t\tif ( !this.conversionApi.consumable.test( item, eventName ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst data = { item, range: Range._createOn( item ), markerName, markerRange };\n\n\t\t\tthis.fire( eventName, data, this.conversionApi );\n\t\t}\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Fires the conversion of the marker removal. Fires the {@link #event:removeMarker `removeMarker`} event with the provided data.\n\t *\n\t * @fires removeMarker\n\t * @param {String} markerName Marker name.\n\t * @param {module:engine/model/range~Range} markerRange The marker range.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify the view document.\n\t */\n\tconvertMarkerRemove( markerName, markerRange, writer ) {\n\t\t// Do not convert if range is in graveyard or not in the document (e.g. in DocumentFragment).\n\t\tif ( !markerRange.root.document || markerRange.root.rootName == '$graveyard' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.conversionApi.writer = writer;\n\n\t\tthis.fire( 'removeMarker:' + markerName, { markerName, markerRange }, this.conversionApi );\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Maps the model element \"insert\" reconversion for given event names. The event names must be fully specified:\n\t *\n\t * * For \"attribute\" change event, it should include the main element name, i.e: `'attribute:attributeName:elementName'`.\n\t * * For child node change events, these should use the child event name as well, i.e:\n\t *     * For adding a node: `'insert:childElementName'`.\n\t *     * For removing a node: `'remove:childElementName'`.\n\t *\n\t * **Note**: This method should not be used directly. The reconversion is defined by the `triggerBy()` configuration of the\n\t * `elementToElement()` conversion helper.\n\t *\n\t * @protected\n\t * @param {String} modelName The name of the main model element for which the events will trigger the reconversion.\n\t * @param {String} eventName The name of an event that would trigger conversion for a given model element.\n\t */\n\t_mapReconversionTriggerEvent( modelName, eventName ) {\n\t\tthis._reconversionEventsMapping.set( eventName, modelName );\n\t}\n\n\t/**\n\t * Creates {@link module:engine/conversion/modelconsumable~ModelConsumable} with values to consume from a given range,\n\t * assuming that the range has just been inserted to the model.\n\t *\n\t * @private\n\t * @param {module:engine/model/range~Range} range The inserted range.\n\t * @returns {module:engine/conversion/modelconsumable~ModelConsumable} The values to consume.\n\t */\n\t_createInsertConsumable( range ) {\n\t\tconst consumable = new Consumable();\n\n\t\tfor ( const value of range ) {\n\t\t\tconst item = value.item;\n\n\t\t\tconsumable.add( item, 'insert' );\n\n\t\t\tfor ( const key of item.getAttributeKeys() ) {\n\t\t\t\tconsumable.add( item, 'attribute:' + key );\n\t\t\t}\n\t\t}\n\n\t\treturn consumable;\n\t}\n\n\t/**\n\t * Creates {@link module:engine/conversion/modelconsumable~ModelConsumable} with values to consume for a given range.\n\t *\n\t * @private\n\t * @param {module:engine/model/range~Range} range The affected range.\n\t * @param {String} type Consumable type.\n\t * @returns {module:engine/conversion/modelconsumable~ModelConsumable} The values to consume.\n\t */\n\t_createConsumableForRange( range, type ) {\n\t\tconst consumable = new Consumable();\n\n\t\tfor ( const item of range.getItems() ) {\n\t\t\tconsumable.add( item, type );\n\t\t}\n\n\t\treturn consumable;\n\t}\n\n\t/**\n\t * Creates {@link module:engine/conversion/modelconsumable~ModelConsumable} with selection consumable values.\n\t *\n\t * @private\n\t * @param {module:engine/model/selection~Selection} selection The selection to create the consumable from.\n\t * @param {Iterable.<module:engine/model/markercollection~Marker>} markers Markers that contain the selection.\n\t * @returns {module:engine/conversion/modelconsumable~ModelConsumable} The values to consume.\n\t */\n\t_createSelectionConsumable( selection, markers ) {\n\t\tconst consumable = new Consumable();\n\n\t\tconsumable.add( selection, 'selection' );\n\n\t\tfor ( const marker of markers ) {\n\t\t\tconsumable.add( selection, 'addMarker:' + marker.name );\n\t\t}\n\n\t\tfor ( const key of selection.getAttributeKeys() ) {\n\t\t\tconsumable.add( selection, 'attribute:' + key );\n\t\t}\n\n\t\treturn consumable;\n\t}\n\n\t/**\n\t * Tests passed `consumable` to check whether given event can be fired and if so, fires it.\n\t *\n\t * @private\n\t * @fires insert\n\t * @fires attribute\n\t * @param {String} type Event type.\n\t * @param {Object} data Event data.\n\t */\n\t_testAndFire( type, data ) {\n\t\tif ( !this.conversionApi.consumable.test( data.item, type ) ) {\n\t\t\t// Do not fire event if the item was consumed.\n\t\t\treturn;\n\t\t}\n\n\t\tthis.fire( getEventName( type, data ), data, this.conversionApi );\n\t}\n\n\t/**\n\t * Clears the conversion API object.\n\t *\n\t * @private\n\t */\n\t_clearConversionApi() {\n\t\tdelete this.conversionApi.writer;\n\t\tdelete this.conversionApi.consumable;\n\t}\n\n\t/**\n\t * Internal method for converting element insertion. It will fire events for the inserted element and events for its attributes.\n\t *\n\t * @private\n\t * @fires insert\n\t * @fires attribute\n\t * @param {Object} data Event data.\n\t */\n\t_convertInsertWithAttributes( data ) {\n\t\tthis._testAndFire( 'insert', data );\n\n\t\t// Fire a separate addAttribute event for each attribute that was set on inserted items.\n\t\t// This is important because most attributes converters will listen only to add/change/removeAttribute events.\n\t\t// If we would not add this part, attributes on inserted nodes would not be converted.\n\t\tfor ( const key of data.item.getAttributeKeys() ) {\n\t\t\tdata.attributeKey = key;\n\t\t\tdata.attributeOldValue = null;\n\t\t\tdata.attributeNewValue = data.item.getAttribute( key );\n\n\t\t\tthis._testAndFire( `attribute:${ key }`, data );\n\t\t}\n\t}\n\n\t/**\n\t * Returns differ changes together with added \"reconvert\" type changes for {@link #reconvertElement}. These are defined by\n\t * a the `triggerBy()` configuration for the\n\t * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`} conversion helper.\n\t *\n\t * This method will remove every mapped insert or remove change with a single \"reconvert\" change.\n\t *\n\t * For instance: Having a `triggerBy()` configuration defined for the `<complex>` element that issues this element reconversion on\n\t * `foo` and `bar` attributes change, and a set of changes for this element:\n\t *\n\t *\t\tconst differChanges = [\n\t *\t\t\t{ type: 'attribute', attributeKey: 'foo', ... },\n\t *\t\t\t{ type: 'attribute', attributeKey: 'bar', ... },\n\t *\t\t\t{ type: 'attribute', attributeKey: 'baz', ... }\n\t *\t\t];\n\t *\n\t * This method will return:\n\t *\n\t *\t\tconst updatedChanges = [\n\t *\t\t\t{ type: 'reconvert', element: complexElementInstance },\n\t *\t\t\t{ type: 'attribute', attributeKey: 'baz', ... }\n\t *\t\t];\n\t *\n\t * In the example above, the `'baz'` attribute change will fire an {@link #event:attribute attribute event}\n\t *\n\t * @param {module:engine/model/differ~Differ} differ The differ object with buffered changes.\n\t * @returns {Array.<Object>} Updated set of changes.\n\t * @private\n\t */\n\t_mapChangesWithAutomaticReconversion( differ ) {\n\t\tconst itemsToReconvert = new Set();\n\t\tconst updated = [];\n\n\t\tfor ( const entry of differ.getChanges() ) {\n\t\t\tconst position = entry.position || entry.range.start;\n\t\t\t// Cached parent - just in case. See https://github.com/ckeditor/ckeditor5/issues/6579.\n\t\t\tconst positionParent = position.parent;\n\t\t\tconst textNode = getTextNodeAtPosition( position, positionParent );\n\n\t\t\t// Reconversion is done only on elements so skip text changes.\n\t\t\tif ( textNode ) {\n\t\t\t\tupdated.push( entry );\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst element = entry.type === 'attribute' ? getNodeAfterPosition( position, positionParent, null ) : positionParent;\n\n\t\t\t// Case of text node set directly in root. For now used only in tests but can be possible when enabled in paragraph-like roots.\n\t\t\t// See: https://github.com/ckeditor/ckeditor5/issues/762.\n\t\t\tif ( element.is( '$text' ) ) {\n\t\t\t\tupdated.push( entry );\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet eventName;\n\n\t\t\tif ( entry.type === 'attribute' ) {\n\t\t\t\teventName = `attribute:${ entry.attributeKey }:${ element.name }`;\n\t\t\t} else {\n\t\t\t\teventName = `${ entry.type }:${ entry.name }`;\n\t\t\t}\n\n\t\t\tif ( this._isReconvertTriggerEvent( eventName, element.name ) ) {\n\t\t\t\tif ( itemsToReconvert.has( element ) ) {\n\t\t\t\t\t// Element is already reconverted, so skip this change.\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\titemsToReconvert.add( element );\n\n\t\t\t\t// Add special \"reconvert\" change.\n\t\t\t\tupdated.push( { type: 'reconvert', element } );\n\t\t\t} else {\n\t\t\t\tupdated.push( entry );\n\t\t\t}\n\t\t}\n\n\t\treturn updated;\n\t}\n\n\t/**\n\t * Checks if the resulting change should trigger element reconversion.\n\t *\n\t * These are defined by a `triggerBy()` configuration for the\n\t * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`} conversion helper.\n\t *\n\t * @private\n\t * @param {String} eventName The event name to check.\n\t * @param {String} elementName The element name to check.\n\t * @returns {Boolean}\n\t */\n\t_isReconvertTriggerEvent( eventName, elementName ) {\n\t\treturn this._reconversionEventsMapping.get( eventName ) === elementName;\n\t}\n\n\t/**\n\t * Fired for inserted nodes.\n\t *\n\t * `insert` is a namespace for a class of events. Names of actually called events follow this pattern:\n\t * `insert:name`. `name` is either `'$text'`, when {@link module:engine/model/text~Text a text node} has been inserted,\n\t * or {@link module:engine/model/element~Element#name name} of inserted element.\n\t *\n\t * This way listeners can either listen to a general `insert` event or specific event (for example `insert:paragraph`).\n\t *\n\t * @event insert\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/model/item~Item} data.item Inserted item.\n\t * @param {module:engine/model/range~Range} data.range Range spanning over inserted item.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n\n\t/**\n\t * Fired for removed nodes.\n\t *\n\t * `remove` is a namespace for a class of events. Names of actually called events follow this pattern:\n\t * `remove:name`. `name` is either `'$text'`, when {@link module:engine/model/text~Text a text node} has been removed,\n\t * or the {@link module:engine/model/element~Element#name name} of removed element.\n\t *\n\t * This way listeners can either listen to a general `remove` event or specific event (for example `remove:paragraph`).\n\t *\n\t * @event remove\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/model/position~Position} data.position Position from which the node has been removed.\n\t * @param {Number} data.length Offset size of the removed node.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n\n\t/**\n\t * Fired in the following cases:\n\t *\n\t * * when an attribute has been added, changed, or removed from a node,\n\t * * when a node with an attribute is inserted,\n\t * * when collapsed model selection attribute is converted.\n\t *\n\t * `attribute` is a namespace for a class of events. Names of actually called events follow this pattern:\n\t * `attribute:attributeKey:name`. `attributeKey` is the key of added/changed/removed attribute.\n\t * `name` is either `'$text'` if change was on {@link module:engine/model/text~Text a text node},\n\t * or the {@link module:engine/model/element~Element#name name} of element which attribute has changed.\n\t *\n\t * This way listeners can either listen to a general `attribute:bold` event or specific event (for example `attribute:src:image`).\n\t *\n\t * @event attribute\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/model/item~Item|module:engine/model/documentselection~DocumentSelection} data.item Changed item\n\t * or converted selection.\n\t * @param {module:engine/model/range~Range} data.range Range spanning over changed item or selection range.\n\t * @param {String} data.attributeKey Attribute key.\n\t * @param {*} data.attributeOldValue Attribute value before the change. This is `null` when selection attribute is converted.\n\t * @param {*} data.attributeNewValue New attribute value.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n\n\t/**\n\t * Fired for {@link module:engine/model/selection~Selection selection} changes.\n\t *\n\t * @event selection\n\t * @param {module:engine/model/selection~Selection} selection Selection that is converted.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n\n\t/**\n\t * Fired when a new marker is added to the model. Also fired when a collapsed model selection that is inside a marker is converted.\n\t *\n\t * `addMarker` is a namespace for a class of events. Names of actually called events follow this pattern:\n\t * `addMarker:markerName`. By specifying certain marker names, you can make the events even more gradual. For example,\n\t * if markers are named `foo:abc`, `foo:bar`, then it is possible to listen to `addMarker:foo` or `addMarker:foo:abc` and\n\t * `addMarker:foo:bar` events.\n\t *\n\t * If the marker range is not collapsed:\n\t *\n\t * * the event is fired for each item in the marker range one by one,\n\t * * `conversionApi.consumable` includes each item of the marker range and the consumable value is same as the event name.\n\t *\n\t * If the marker range is collapsed:\n\t *\n\t * * there is only one event,\n\t * * `conversionApi.consumable` includes marker range with the event name.\n\t *\n\t * If the selection inside a marker is converted:\n\t *\n\t * * there is only one event,\n\t * * `conversionApi.consumable` includes the selection instance with the event name.\n\t *\n\t * @event addMarker\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/model/item~Item|module:engine/model/selection~Selection} data.item Item inside the new marker or\n\t * the selection that is being converted.\n\t * @param {module:engine/model/range~Range} [data.range] Range spanning over converted item. Available only in marker conversion, if\n\t * the marker range was not collapsed.\n\t * @param {module:engine/model/range~Range} data.markerRange Marker range.\n\t * @param {String} data.markerName Marker name.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n\n\t/**\n\t * Fired when a marker is removed from the model.\n\t *\n\t * `removeMarker` is a namespace for a class of events. Names of actually called events follow this pattern:\n\t * `removeMarker:markerName`. By specifying certain marker names, you can make the events even more gradual. For example,\n\t * if markers are named `foo:abc`, `foo:bar`, then it is possible to listen to `removeMarker:foo` or `removeMarker:foo:abc` and\n\t * `removeMarker:foo:bar` events.\n\t *\n\t * @event removeMarker\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/model/range~Range} data.markerRange Marker range.\n\t * @param {String} data.markerName Marker name.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n}\n\nmix( DowncastDispatcher, EmitterMixin );\n\n// Helper function, checks whether change of `marker` at `modelPosition` should be converted. Marker changes are not\n// converted if they happen inside an element with custom conversion method.\n//\n// @param {module:engine/model/position~Position} modelPosition\n// @param {module:engine/model/markercollection~Marker} marker\n// @param {module:engine/conversion/mapper~Mapper} mapper\n// @returns {Boolean}\nfunction shouldMarkerChangeBeConverted( modelPosition, marker, mapper ) {\n\tconst range = marker.getRange();\n\tconst ancestors = Array.from( modelPosition.getAncestors() );\n\tancestors.shift(); // Remove root element. It cannot be passed to `model.Range#containsItem`.\n\tancestors.reverse();\n\n\tconst hasCustomHandling = ancestors.some( element => {\n\t\tif ( range.containsItem( element ) ) {\n\t\t\tconst viewElement = mapper.toViewElement( element );\n\n\t\t\treturn !!viewElement.getCustomProperty( 'addHighlight' );\n\t\t}\n\t} );\n\n\treturn !hasCustomHandling;\n}\n\nfunction getEventName( type, data ) {\n\tconst name = data.item.name || '$text';\n\n\treturn `${ type }:${ name }`;\n}\n\nfunction walkerValueToEventData( value ) {\n\tconst item = value.item;\n\tconst itemRange = Range._createFromPositionAndShift( value.previousPosition, value.length );\n\n\treturn {\n\t\titem,\n\t\trange: itemRange\n\t};\n}\n\nfunction elementOrTextProxyToView( item, mapper ) {\n\tif ( item.is( 'textProxy' ) ) {\n\t\tconst mappedPosition = mapper.toViewPosition( Position._createBefore( item ) );\n\t\tconst positionParent = mappedPosition.parent;\n\n\t\treturn positionParent.is( '$text' ) ? positionParent : null;\n\t}\n\n\treturn mapper.toViewElement( item );\n}\n\n/**\n * Conversion interface that is registered for given {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}\n * and is passed as one of parameters when {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher dispatcher}\n * fires its events.\n *\n * @interface module:engine/conversion/downcastdispatcher~DowncastConversionApi\n */\n\n/**\n * The {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher} instance.\n *\n * @member {module:engine/conversion/downcastdispatcher~DowncastDispatcher} #dispatcher\n */\n\n/**\n * Stores the information about what parts of a processed model item are still waiting to be handled. After a piece of a model item was\n * converted, an appropriate consumable value should be {@link module:engine/conversion/modelconsumable~ModelConsumable#consume consumed}.\n *\n * @member {module:engine/conversion/modelconsumable~ModelConsumable} #consumable\n */\n\n/**\n * The {@link module:engine/conversion/mapper~Mapper} instance.\n *\n * @member {module:engine/conversion/mapper~Mapper} #mapper\n */\n\n/**\n * The {@link module:engine/model/schema~Schema} instance set for the model that is downcast.\n *\n * @member {module:engine/model/schema~Schema} #schema\n */\n\n/**\n * The {@link module:engine/view/downcastwriter~DowncastWriter} instance used to manipulate the data during conversion.\n *\n * @member {module:engine/view/downcastwriter~DowncastWriter} #writer\n */\n\n/**\n * An object with an additional configuration which can be used during the conversion process. Available only for data downcast conversion.\n *\n * @member {Object} #options\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/selection\n */\n\nimport Position from './position';\nimport Node from './node';\nimport Range from './range';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\n\n/**\n * Selection is a set of {@link module:engine/model/range~Range ranges}. It has a direction specified by its\n * {@link module:engine/model/selection~Selection#anchor anchor} and {@link module:engine/model/selection~Selection#focus focus}\n * (it can be {@link module:engine/model/selection~Selection#isBackward forward or backward}).\n * Additionally, selection may have its own attributes (think – whether text typed in in this selection\n * should have those attributes – e.g. whether you type a bolded text).\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class Selection {\n\t/**\n\t * Creates a new selection instance based on the given {@link module:engine/model/selection~Selectable selectable}\n\t * or creates an empty selection if no arguments were passed.\n\t *\n\t *\t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = writer.createSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tconst selection = writer.createSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t *\t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tconst selection = writer.createSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tconst selection = writer.createSelection( otherSelection );\n\t *\n\t *\t\t// Creates selection from the given document selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst documentSelection = model.document.selection;\n\t *\t\tconst selection = writer.createSelection( documentSelection );\n\t *\n\t *\t\t// Creates selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\tconst selection = writer.createSelection( position );\n\t *\n\t *\t\t// Creates selection at the given offset in the given element.\n\t *\t\tconst paragraph = writer.createElement( 'paragraph' );\n\t *\t\tconst selection = writer.createSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/model/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/model/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'on' );\n\t *\n\t * Selection's constructor allow passing additional options (`'backward'`) as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = writer.createSelection( range, { backward: true } );\n\t *\n\t * @param {module:engine/model/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t */\n\tconstructor( selectable, placeOrOffset, options ) {\n\t\t/**\n\t\t * Specifies whether the last added range was added as a backward or forward range.\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._lastRangeBackward = false;\n\n\t\t/**\n\t\t * Stores selection ranges.\n\t\t *\n\t\t * @protected\n\t\t * @type {Array.<module:engine/model/range~Range>}\n\t\t */\n\t\tthis._ranges = [];\n\n\t\t/**\n\t\t * List of attributes set on current selection.\n\t\t *\n\t\t * @protected\n\t\t * @type {Map.<String,*>}\n\t\t */\n\t\tthis._attrs = new Map();\n\n\t\tif ( selectable ) {\n\t\t\tthis.setTo( selectable, placeOrOffset, options );\n\t\t}\n\t}\n\n\t/**\n\t * Selection anchor. Anchor is the position from which the selection was started. If a user is making a selection\n\t * by dragging the mouse, the anchor is where the user pressed the mouse button (the beginning of the selection).\n\t *\n\t * Anchor and {@link #focus} define the direction of the selection, which is important\n\t * when expanding/shrinking selection. The focus moves, while the anchor should remain in the same place.\n\t *\n\t * Anchor is always set to the {@link module:engine/model/range~Range#start start} or\n\t * {@link module:engine/model/range~Range#end end} position of the last of selection's ranges. Whether it is\n\t * the `start` or `end` depends on the specified `options.backward`. See the {@link #setTo `setTo()`} method.\n\t *\n\t * May be set to `null` if there are no ranges in the selection.\n\t *\n\t * @see #focus\n\t * @readonly\n\t * @type {module:engine/model/position~Position|null}\n\t */\n\tget anchor() {\n\t\tif ( this._ranges.length > 0 ) {\n\t\t\tconst range = this._ranges[ this._ranges.length - 1 ];\n\n\t\t\treturn this._lastRangeBackward ? range.end : range.start;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Selection focus. Focus is the position where the selection ends. If a user is making a selection\n\t * by dragging the mouse, the focus is where the mouse cursor is.\n\t *\n\t * May be set to `null` if there are no ranges in the selection.\n\t *\n\t * @see #anchor\n\t * @readonly\n\t * @type {module:engine/model/position~Position|null}\n\t */\n\tget focus() {\n\t\tif ( this._ranges.length > 0 ) {\n\t\t\tconst range = this._ranges[ this._ranges.length - 1 ];\n\n\t\t\treturn this._lastRangeBackward ? range.start : range.end;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Whether the selection is collapsed. Selection is collapsed when there is exactly one range in it\n\t * and it is collapsed.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\tconst length = this._ranges.length;\n\n\t\tif ( length === 1 ) {\n\t\t\treturn this._ranges[ 0 ].isCollapsed;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Returns the number of ranges in the selection.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget rangeCount() {\n\t\treturn this._ranges.length;\n\t}\n\n\t/**\n\t * Specifies whether the selection's {@link #focus} precedes the selection's {@link #anchor}.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isBackward() {\n\t\treturn !this.isCollapsed && this._lastRangeBackward;\n\t}\n\n\t/**\n\t * Checks whether this selection is equal to the given selection. Selections are equal if they have the same directions,\n\t * the same number of ranges and all ranges from one selection equal to ranges from the another selection.\n\t *\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} otherSelection\n\t * Selection to compare with.\n\t * @returns {Boolean} `true` if selections are equal, `false` otherwise.\n\t */\n\tisEqual( otherSelection ) {\n\t\tif ( this.rangeCount != otherSelection.rangeCount ) {\n\t\t\treturn false;\n\t\t} else if ( this.rangeCount === 0 ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif ( !this.anchor.isEqual( otherSelection.anchor ) || !this.focus.isEqual( otherSelection.focus ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor ( const thisRange of this._ranges ) {\n\t\t\tlet found = false;\n\n\t\t\tfor ( const otherRange of otherSelection._ranges ) {\n\t\t\t\tif ( thisRange.isEqual( otherRange ) ) {\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( !found ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns an iterable object that iterates over copies of selection ranges.\n\t *\n\t * @returns {Iterable.<module:engine/model/range~Range>}\n\t */\n\t* getRanges() {\n\t\tfor ( const range of this._ranges ) {\n\t\t\tyield new Range( range.start, range.end );\n\t\t}\n\t}\n\n\t/**\n\t * Returns a copy of the first range in the selection.\n\t * First range is the one which {@link module:engine/model/range~Range#start start} position\n\t * {@link module:engine/model/position~Position#isBefore is before} start position of all other ranges\n\t * (not to confuse with the first range added to the selection).\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/range~Range|null}\n\t */\n\tgetFirstRange() {\n\t\tlet first = null;\n\n\t\tfor ( const range of this._ranges ) {\n\t\t\tif ( !first || range.start.isBefore( first.start ) ) {\n\t\t\t\tfirst = range;\n\t\t\t}\n\t\t}\n\n\t\treturn first ? new Range( first.start, first.end ) : null;\n\t}\n\n\t/**\n\t * Returns a copy of the last range in the selection.\n\t * Last range is the one which {@link module:engine/model/range~Range#end end} position\n\t * {@link module:engine/model/position~Position#isAfter is after} end position of all other ranges (not to confuse with the range most\n\t * recently added to the selection).\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/range~Range|null}\n\t */\n\tgetLastRange() {\n\t\tlet last = null;\n\n\t\tfor ( const range of this._ranges ) {\n\t\t\tif ( !last || range.end.isAfter( last.end ) ) {\n\t\t\t\tlast = range;\n\t\t\t}\n\t\t}\n\n\t\treturn last ? new Range( last.start, last.end ) : null;\n\t}\n\n\t/**\n\t * Returns the first position in the selection.\n\t * First position is the position that {@link module:engine/model/position~Position#isBefore is before}\n\t * any other position in the selection.\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/position~Position|null}\n\t */\n\tgetFirstPosition() {\n\t\tconst first = this.getFirstRange();\n\n\t\treturn first ? first.start.clone() : null;\n\t}\n\n\t/**\n\t * Returns the last position in the selection.\n\t * Last position is the position that {@link module:engine/model/position~Position#isAfter is after}\n\t * any other position in the selection.\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/position~Position|null}\n\t */\n\tgetLastPosition() {\n\t\tconst lastRange = this.getLastRange();\n\n\t\treturn lastRange ? lastRange.end.clone() : null;\n\t}\n\n\t/**\n\t * Sets this selection's ranges and direction to the specified location based on the given\n\t * {@link module:engine/model/selection~Selectable selectable}.\n\t *\n\t *\t\t// Removes all selection's ranges.\n\t *\t\tselection.setTo( null );\n\t *\n\t *\t\t// Sets selection to the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tselection.setTo( range );\n\t *\n\t *\t\t// Sets selection to given ranges.\n\t *\t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tselection.setTo( ranges );\n\t *\n\t *\t\t// Sets selection to other selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tselection.setTo( otherSelection );\n\t *\n\t *\t\t// Sets selection to the given document selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst documentSelection = new DocumentSelection( doc );\n\t *\t\tselection.setTo( documentSelection );\n\t *\n\t *\t\t// Sets collapsed selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\tselection.setTo( position );\n\t *\n\t *\t\t// Sets collapsed selection at the position of the given node and an offset.\n\t *\t\tselection.setTo( paragraph, offset );\n\t *\n\t * Creates a range inside an {@link module:engine/model/element~Element element} which starts before the first child of\n \t * that element and ends after the last child of that element.\n\t *\n\t *\t\tselection.setTo( paragraph, 'in' );\n\t *\n\t * Creates a range on an {@link module:engine/model/item~Item item} which starts before the item and ends just after the item.\n\t *\n\t *\t\tselection.setTo( paragraph, 'on' );\n\t *\n\t * `Selection#setTo()`' method allow passing additional options (`backward`) as the last argument.\n\t *\n\t *\t\t// Sets backward selection.\n\t *\t\tconst selection = writer.createSelection( range, { backward: true } );\n\t *\n\t * @param {module:engine/model/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t */\n\tsetTo( selectable, placeOrOffset, options ) {\n\t\tif ( selectable === null ) {\n\t\t\tthis._setRanges( [] );\n\t\t} else if ( selectable instanceof Selection ) {\n\t\t\tthis._setRanges( selectable.getRanges(), selectable.isBackward );\n\t\t} else if ( selectable && typeof selectable.getRanges == 'function' ) {\n\t\t\t// We assume that the selectable is a DocumentSelection.\n\t\t\t// It can't be imported here, because it would lead to circular imports.\n\t\t\tthis._setRanges( selectable.getRanges(), selectable.isBackward );\n\t\t} else if ( selectable instanceof Range ) {\n\t\t\tthis._setRanges( [ selectable ], !!placeOrOffset && !!placeOrOffset.backward );\n\t\t} else if ( selectable instanceof Position ) {\n\t\t\tthis._setRanges( [ new Range( selectable ) ] );\n\t\t} else if ( selectable instanceof Node ) {\n\t\t\tconst backward = !!options && !!options.backward;\n\t\t\tlet range;\n\n\t\t\tif ( placeOrOffset == 'in' ) {\n\t\t\t\trange = Range._createIn( selectable );\n\t\t\t} else if ( placeOrOffset == 'on' ) {\n\t\t\t\trange = Range._createOn( selectable );\n\t\t\t} else if ( placeOrOffset !== undefined ) {\n\t\t\t\trange = new Range( Position._createAt( selectable, placeOrOffset ) );\n\t\t\t} else {\n\t\t\t\t/**\n\t\t\t\t * selection.setTo requires the second parameter when the first parameter is a node.\n\t\t\t\t *\n\t\t\t\t * @error model-selection-setto-required-second-parameter\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'model-selection-setto-required-second-parameter', [ this, selectable ] );\n\t\t\t}\n\n\t\t\tthis._setRanges( [ range ], backward );\n\t\t} else if ( isIterable( selectable ) ) {\n\t\t\t// We assume that the selectable is an iterable of ranges.\n\t\t\tthis._setRanges( selectable, placeOrOffset && !!placeOrOffset.backward );\n\t\t} else {\n\t\t\t/**\n\t\t\t * Cannot set the selection to the given place.\n\t\t\t *\n\t\t\t * Invalid parameters were specified when setting the selection. Common issues:\n\t\t\t *\n\t\t\t * * A {@link module:engine/model/textproxy~TextProxy} instance was passed instead of\n\t\t\t * a real {@link module:engine/model/text~Text}.\n\t\t\t * * View nodes were passed instead of model nodes.\n\t\t\t * * `null`/`undefined` was passed.\n\t\t\t *\n\t\t\t * @error model-selection-setto-not-selectable\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-selection-setto-not-selectable', [ this, selectable ] );\n\t\t}\n\t}\n\n\t/**\n\t * Replaces all ranges that were added to the selection with given array of ranges. Last range of the array\n\t * is treated like the last added range and is used to set {@link module:engine/model/selection~Selection#anchor} and\n\t * {@link module:engine/model/selection~Selection#focus}. Accepts a flag describing in which direction the selection is made.\n\t *\n\t * @protected\n\t * @fires change:range\n\t * @param {Iterable.<module:engine/model/range~Range>} newRanges Ranges to set.\n\t * @param {Boolean} [isLastBackward=false] Flag describing if last added range was selected forward - from start to end (`false`)\n\t * or backward - from end to start (`true`).\n\t */\n\t_setRanges( newRanges, isLastBackward = false ) {\n\t\tnewRanges = Array.from( newRanges );\n\n\t\t// Check whether there is any range in new ranges set that is different than all already added ranges.\n\t\tconst anyNewRange = newRanges.some( newRange => {\n\t\t\tif ( !( newRange instanceof Range ) ) {\n\t\t\t\t/**\n\t\t\t\t * Selection range set to an object that is not an instance of {@link module:engine/model/range~Range}.\n\t\t\t\t *\n\t\t\t\t * Only {@link module:engine/model/range~Range} instances can be used to set a selection.\n\t\t\t\t * Common mistakes leading to this error are:\n\t\t\t\t *\n\t\t\t\t * * using DOM `Range` object,\n\t\t\t\t * * incorrect CKEditor 5 installation with multiple `ckeditor5-engine` packages having different versions.\n\t\t\t\t *\n\t\t\t\t * @error model-selection-set-ranges-not-range\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'model-selection-set-ranges-not-range',\n\t\t\t\t\t[ this, newRanges ]\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn this._ranges.every( oldRange => {\n\t\t\t\treturn !oldRange.isEqual( newRange );\n\t\t\t} );\n\t\t} );\n\n\t\t// Don't do anything if nothing changed.\n\t\tif ( newRanges.length === this._ranges.length && !anyNewRange ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._removeAllRanges();\n\n\t\tfor ( const range of newRanges ) {\n\t\t\tthis._pushRange( range );\n\t\t}\n\n\t\tthis._lastRangeBackward = !!isLastBackward;\n\n\t\tthis.fire( 'change:range', { directChange: true } );\n\t}\n\n\t/**\n\t * Moves {@link module:engine/model/selection~Selection#focus} to the specified location.\n\t *\n\t * The location can be specified in the same form as\n\t * {@link module:engine/model/writer~Writer#createPositionAt writer.createPositionAt()} parameters.\n\t *\n\t * @fires change:range\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\tsetFocus( itemOrPosition, offset ) {\n\t\tif ( this.anchor === null ) {\n\t\t\t/**\n\t\t\t * Cannot set selection focus if there are no ranges in selection.\n\t\t\t *\n\t\t\t * @error model-selection-setfocus-no-ranges\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-selection-setfocus-no-ranges', [ this, itemOrPosition ] );\n\t\t}\n\n\t\tconst newFocus = Position._createAt( itemOrPosition, offset );\n\n\t\tif ( newFocus.compareWith( this.focus ) == 'same' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst anchor = this.anchor;\n\n\t\tif ( this._ranges.length ) {\n\t\t\tthis._popRange();\n\t\t}\n\n\t\tif ( newFocus.compareWith( anchor ) == 'before' ) {\n\t\t\tthis._pushRange( new Range( newFocus, anchor ) );\n\t\t\tthis._lastRangeBackward = true;\n\t\t} else {\n\t\t\tthis._pushRange( new Range( anchor, newFocus ) );\n\t\t\tthis._lastRangeBackward = false;\n\t\t}\n\n\t\tthis.fire( 'change:range', { directChange: true } );\n\t}\n\n\t/**\n\t * Gets an attribute value for given key or `undefined` if that attribute is not set on the selection.\n\t *\n\t * @param {String} key Key of attribute to look for.\n\t * @returns {*} Attribute value or `undefined`.\n\t */\n\tgetAttribute( key ) {\n\t\treturn this._attrs.get( key );\n\t}\n\n\t/**\n\t * Returns iterable that iterates over this selection's attributes.\n\t *\n\t * Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.\n\t * This format is accepted by native `Map` object and also can be passed in `Node` constructor.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\tgetAttributes() {\n\t\treturn this._attrs.entries();\n\t}\n\n\t/**\n\t * Returns iterable that iterates over this selection's attribute keys.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetAttributeKeys() {\n\t\treturn this._attrs.keys();\n\t}\n\n\t/**\n\t * Checks if the selection has an attribute for given key.\n\t *\n\t * @param {String} key Key of attribute to check.\n\t * @returns {Boolean} `true` if attribute with given key is set on selection, `false` otherwise.\n\t */\n\thasAttribute( key ) {\n\t\treturn this._attrs.has( key );\n\t}\n\n\t/**\n\t * Removes an attribute with given key from the selection.\n\t *\n\t * If given attribute was set on the selection, fires the {@link #event:change:range} event with\n\t * removed attribute key.\n\t *\n\t * @fires change:attribute\n\t * @param {String} key Key of attribute to remove.\n\t */\n\tremoveAttribute( key ) {\n\t\tif ( this.hasAttribute( key ) ) {\n\t\t\tthis._attrs.delete( key );\n\n\t\t\tthis.fire( 'change:attribute', { attributeKeys: [ key ], directChange: true } );\n\t\t}\n\t}\n\n\t/**\n\t * Sets attribute on the selection. If attribute with the same key already is set, it's value is overwritten.\n\t *\n\t * If the attribute value has changed, fires the {@link #event:change:range} event with\n\t * the attribute key.\n\t *\n\t * @fires change:attribute\n\t * @param {String} key Key of attribute to set.\n\t * @param {*} value Attribute value.\n\t */\n\tsetAttribute( key, value ) {\n\t\tif ( this.getAttribute( key ) !== value ) {\n\t\t\tthis._attrs.set( key, value );\n\n\t\t\tthis.fire( 'change:attribute', { attributeKeys: [ key ], directChange: true } );\n\t\t}\n\t}\n\n\t/**\n\t * Returns the selected element. {@link module:engine/model/element~Element Element} is considered as selected if there is only\n\t * one range in the selection, and that range contains exactly one element.\n\t * Returns `null` if there is no selected element.\n\t *\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\tgetSelectedElement() {\n\t\tif ( this.rangeCount !== 1 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.getFirstRange().getContainedElement();\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tselection.is( 'selection' ); // -> true\n\t *\t\tselection.is( 'model:selection' ); // -> true\n\t *\n\t *\t\tselection.is( 'view:selection' ); // -> false\n\t *\t\tselection.is( 'range' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'selection' || type === 'model:selection';\n\t}\n\n\t/**\n\t * Gets elements of type {@link module:engine/model/schema~Schema#isBlock \"block\"} touched by the selection.\n\t *\n\t * This method's result can be used for example to apply block styling to all blocks covered by this selection.\n\t *\n\t * **Note:** `getSelectedBlocks()` returns blocks that are nested in other non-block elements\n\t * but will not return blocks nested in other blocks.\n\t *\n\t * In this case the function will return exactly all 3 paragraphs (note: `<blockQuote>` is not a block itself):\n\t *\n\t *\t\t<paragraph>[a</paragraph>\n\t *\t\t<blockQuote>\n\t *\t\t\t<paragraph>b</paragraph>\n\t *\t\t</blockQuote>\n\t *\t\t<paragraph>c]d</paragraph>\n\t *\n\t * In this case the paragraph will also be returned, despite the collapsed selection:\n\t *\n\t *\t\t<paragraph>[]a</paragraph>\n\t *\n\t * In such a scenario, however, only blocks A, B & E will be returned as blocks C & D are nested in block B:\n\t *\n\t *\t\t[<blockA></blockA>\n\t *\t\t<blockB>\n\t *\t\t\t<blockC></blockC>\n\t *\t\t\t<blockD></blockD>\n\t *\t\t</blockB>\n\t *\t\t<blockE></blockE>]\n\t *\n\t * If the selection is inside a block all the inner blocks (A & B) are returned:\n\t *\n\t * \t\t<block>\n\t *\t\t\t<blockA>[a</blockA>\n\t * \t\t\t<blockB>b]</blockB>\n\t * \t\t</block>\n\t *\n\t * **Special case**: If a selection ends at the beginning of a block, that block is not returned as from user perspective\n\t * this block wasn't selected. See [#984](https://github.com/ckeditor/ckeditor5-engine/issues/984) for more details.\n\t *\n\t *\t\t<paragraph>[a</paragraph>\n\t *\t\t<paragraph>b</paragraph>\n\t *\t\t<paragraph>]c</paragraph> // this block will not be returned\n\t *\n\t * @returns {Iterable.<module:engine/model/element~Element>}\n\t */\n\t* getSelectedBlocks() {\n\t\tconst visited = new WeakSet();\n\n\t\tfor ( const range of this.getRanges() ) {\n\t\t\t// Get start block of range in case of a collapsed range.\n\t\t\tconst startBlock = getParentBlock( range.start, visited );\n\n\t\t\tif ( startBlock && isTopBlockInRange( startBlock, range ) ) {\n\t\t\t\tyield startBlock;\n\t\t\t}\n\n\t\t\tfor ( const value of range.getWalker() ) {\n\t\t\t\tconst block = value.item;\n\n\t\t\t\tif ( value.type == 'elementEnd' && isUnvisitedTopBlock( block, visited, range ) ) {\n\t\t\t\t\tyield block;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst endBlock = getParentBlock( range.end, visited );\n\n\t\t\t// #984. Don't return the end block if the range ends right at its beginning.\n\t\t\tif ( endBlock && !range.end.isTouching( Position._createAt( endBlock, 0 ) ) && isTopBlockInRange( endBlock, range ) ) {\n\t\t\t\tyield endBlock;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks whether the selection contains the entire content of the given element. This means that selection must start\n\t * at a position {@link module:engine/model/position~Position#isTouching touching} the element's start and ends at position\n\t * touching the element's end.\n\t *\n\t * By default, this method will check whether the entire content of the selection's current root is selected.\n\t * Useful to check if e.g. the user has just pressed <kbd>Ctrl</kbd> + <kbd>A</kbd>.\n\t *\n\t * @param {module:engine/model/element~Element} [element=this.anchor.root]\n\t * @returns {Boolean}\n\t */\n\tcontainsEntireContent( element = this.anchor.root ) {\n\t\tconst limitStartPosition = Position._createAt( element, 0 );\n\t\tconst limitEndPosition = Position._createAt( element, 'end' );\n\n\t\treturn limitStartPosition.isTouching( this.getFirstPosition() ) &&\n\t\t\tlimitEndPosition.isTouching( this.getLastPosition() );\n\t}\n\n\t/**\n\t * Adds given range to internal {@link #_ranges ranges array}. Throws an error\n\t * if given range is intersecting with any range that is already stored in this selection.\n\t *\n\t * @protected\n\t * @param {module:engine/model/range~Range} range Range to add.\n\t */\n\t_pushRange( range ) {\n\t\tthis._checkRange( range );\n\t\tthis._ranges.push( new Range( range.start, range.end ) );\n\t}\n\n\t/**\n\t * Checks if given range intersects with ranges that are already in the selection. Throws an error if it does.\n\t *\n\t * @protected\n\t * @param {module:engine/model/range~Range} range Range to check.\n\t */\n\t_checkRange( range ) {\n\t\tfor ( let i = 0; i < this._ranges.length; i++ ) {\n\t\t\tif ( range.isIntersecting( this._ranges[ i ] ) ) {\n\t\t\t\t/**\n\t\t\t\t * Trying to add a range that intersects with another range in the selection.\n\t\t\t\t *\n\t\t\t\t * @error model-selection-range-intersects\n\t\t\t\t * @param {module:engine/model/range~Range} addedRange Range that was added to the selection.\n\t\t\t\t * @param {module:engine/model/range~Range} intersectingRange Range in the selection that intersects with `addedRange`.\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'model-selection-range-intersects',\n\t\t\t\t\t[ this, range ],\n\t\t\t\t\t{ addedRange: range, intersectingRange: this._ranges[ i ] }\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Deletes ranges from internal range array. Uses {@link #_popRange _popRange} to\n\t * ensure proper ranges removal.\n\t *\n\t * @protected\n\t */\n\t_removeAllRanges() {\n\t\twhile ( this._ranges.length > 0 ) {\n\t\t\tthis._popRange();\n\t\t}\n\t}\n\n\t/**\n\t * Removes most recently added range from the selection.\n\t *\n\t * @protected\n\t */\n\t_popRange() {\n\t\tthis._ranges.pop();\n\t}\n\n\t/**\n\t * Fired when selection range(s) changed.\n\t *\n\t * @event change:range\n\t * @param {Boolean} directChange In case of {@link module:engine/model/selection~Selection} class it is always set\n\t * to `true` which indicates that the selection change was caused by a direct use of selection's API.\n\t * The {@link module:engine/model/documentselection~DocumentSelection}, however, may change because its position\n\t * was directly changed through the {@link module:engine/model/writer~Writer writer} or because its position was\n\t * changed because the structure of the model has been changed (which means an indirect change).\n\t * The indirect change does not occur in case of normal (detached) selections because they are \"static\" (as \"not live\")\n\t * which mean that they are not updated once the document changes.\n\t */\n\n\t/**\n\t * Fired when selection attribute changed.\n\t *\n\t * @event change:attribute\n\t * @param {Boolean} directChange In case of {@link module:engine/model/selection~Selection} class it is always set\n\t * to `true` which indicates that the selection change was caused by a direct use of selection's API.\n\t * The {@link module:engine/model/documentselection~DocumentSelection}, however, may change because its attributes\n\t * were directly changed through the {@link module:engine/model/writer~Writer writer} or because its position was\n\t * changed in the model and its attributes were refreshed (which means an indirect change).\n\t * The indirect change does not occur in case of normal (detached) selections because they are \"static\" (as \"not live\")\n\t * which mean that they are not updated once the document changes.\n\t * @param {Array.<String>} attributeKeys Array containing keys of attributes that changed.\n\t */\n}\n\nmix( Selection, EmitterMixin );\n\n// Checks whether the given element extends $block in the schema and has a parent (is not a root).\n// Marks it as already visited.\nfunction isUnvisitedBlock( element, visited ) {\n\tif ( visited.has( element ) ) {\n\t\treturn false;\n\t}\n\n\tvisited.add( element );\n\n\treturn element.root.document.model.schema.isBlock( element ) && element.parent;\n}\n\n// Checks if the given element is a $block was not previously visited and is a top block in a range.\nfunction isUnvisitedTopBlock( element, visited, range ) {\n\treturn isUnvisitedBlock( element, visited ) && isTopBlockInRange( element, range );\n}\n\n// Finds the lowest element in position's ancestors which is a block.\n// It will search until first ancestor that is a limit element.\n// Marks all ancestors as already visited to not include any of them later on.\nfunction getParentBlock( position, visited ) {\n\tconst element = position.parent;\n\tconst schema = element.root.document.model.schema;\n\n\tconst ancestors = position.parent.getAncestors( { parentFirst: true, includeSelf: true } );\n\n\tlet hasParentLimit = false;\n\n\tconst block = ancestors.find( element => {\n\t\t// Stop searching after first parent node that is limit element.\n\t\tif ( hasParentLimit ) {\n\t\t\treturn false;\n\t\t}\n\n\t\thasParentLimit = schema.isLimit( element );\n\n\t\treturn !hasParentLimit && isUnvisitedBlock( element, visited );\n\t} );\n\n\t// Mark all ancestors of this position's parent, because find() might've stopped early and\n\t// the found block may be a child of another block.\n\tancestors.forEach( element => visited.add( element ) );\n\n\treturn block;\n}\n\n// Checks if the blocks is not nested in other block inside a range.\n//\n// @param {module:engine/model/element~Element} block Block to check.\n// @param {module:engine/model/range~Range} range Range to check.\nfunction isTopBlockInRange( block, range ) {\n\tconst parentBlock = findAncestorBlock( block );\n\n\tif ( !parentBlock ) {\n\t\treturn true;\n\t}\n\n\t// Add loose flag to check as parentRange can be equal to range.\n\tconst isParentInRange = range.containsRange( Range._createOn( parentBlock ), true );\n\n\treturn !isParentInRange;\n}\n\n// Returns first ancestor block of a node.\n//\n// @param {module:engine/model/node~Node} node\n// @returns {module:engine/model/node~Node|undefined}\nfunction findAncestorBlock( node ) {\n\tconst schema = node.root.document.model.schema;\n\n\tlet parent = node.parent;\n\n\twhile ( parent ) {\n\t\tif ( schema.isBlock( parent ) ) {\n\t\t\treturn parent;\n\t\t}\n\n\t\tparent = parent.parent;\n\t}\n}\n\n/**\n * An entity that is used to set selection.\n *\n * See also {@link module:engine/model/selection~Selection#setTo}\n *\n * @typedef {\n *     module:engine/model/selection~Selection|\n *     module:engine/model/documentselection~DocumentSelection|\n *     module:engine/model/position~Position|\n *     module:engine/model/range~Range|\n *     module:engine/model/node~Node|\n *     Iterable.<module:engine/model/range~Range>|\n *     null\n * } module:engine/model/selection~Selectable\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/liverange\n */\n\nimport Range from './range';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * `LiveRange` is a type of {@link module:engine/model/range~Range Range}\n * that updates itself as {@link module:engine/model/document~Document document}\n * is changed through operations. It may be used as a bookmark.\n *\n * **Note:** Be very careful when dealing with `LiveRange`. Each `LiveRange` instance bind events that might\n * have to be unbound. Use {@link module:engine/model/liverange~LiveRange#detach detach} whenever you don't need `LiveRange` anymore.\n */\nexport default class LiveRange extends Range {\n\t/**\n\t * Creates a live range.\n\t *\n\t * @see module:engine/model/range~Range\n\t */\n\tconstructor( start, end ) {\n\t\tsuper( start, end );\n\n\t\tbindWithDocument.call( this );\n\t}\n\n\t/**\n\t * Unbinds all events previously bound by `LiveRange`. Use it whenever you don't need `LiveRange` instance\n\t * anymore (i.e. when leaving scope in which it was declared or before re-assigning variable that was\n\t * referring to it).\n\t */\n\tdetach() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tliveRange.is( 'range' ); // -> true\n\t *\t\tliveRange.is( 'model:range' ); // -> true\n\t *\t\tliveRange.is( 'liveRange' ); // -> true\n\t *\t\tliveRange.is( 'model:liveRange' ); // -> true\n\t *\n\t *\t\tliveRange.is( 'view:range' ); // -> false\n\t *\t\tliveRange.is( 'documentSelection' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'liveRange' || type === 'model:liveRange' ||\n\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\ttype == 'range' || type === 'model:range';\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/model/range~Range range instance} that is equal to this live range.\n\t *\n\t * @returns {module:engine/model/range~Range}\n\t */\n\ttoRange() {\n\t\treturn new Range( this.start, this.end );\n\t}\n\n\t/**\n\t * Creates a `LiveRange` instance that is equal to the given range.\n\t *\n\t * @param {module:engine/model/range~Range} range\n\t * @returns {module:engine/model/liverange~LiveRange}\n\t */\n\tstatic fromRange( range ) {\n\t\treturn new LiveRange( range.start, range.end );\n\t}\n\n\t/**\n\t * @see module:engine/model/range~Range._createIn\n\t * @static\n\t * @protected\n\t * @method module:engine/model/liverange~LiveRange._createIn\n\t * @param {module:engine/model/element~Element} element\n\t * @returns {module:engine/model/liverange~LiveRange}\n\t */\n\n\t/**\n\t * @see module:engine/model/range~Range._createOn\n\t * @static\n\t * @protected\n\t * @method module:engine/model/liverange~LiveRange._createOn\n\t * @param {module:engine/model/element~Element} element\n\t * @returns {module:engine/model/liverange~LiveRange}\n\t */\n\n\t/**\n\t * @see module:engine/model/range~Range._createFromPositionAndShift\n\t * @static\n\t * @protected\n\t * @method module:engine/model/liverange~LiveRange._createFromPositionAndShift\n\t * @param {module:engine/model/position~Position} position\n\t * @param {Number} shift\n\t * @returns {module:engine/model/liverange~LiveRange}\n\t */\n\n\t/**\n\t * Fired when `LiveRange` instance boundaries have changed due to changes in the\n\t * {@link module:engine/model/document~Document document}.\n\t *\n\t * @event change:range\n\t * @param {module:engine/model/range~Range} oldRange Range with start and end position equal to start and end position of this live\n\t * range before it got changed.\n\t * @param {Object} data Object with additional information about the change.\n\t * @param {module:engine/model/position~Position|null} data.deletionPosition Source position for remove and merge changes.\n\t * Available if the range was moved to the graveyard root, `null` otherwise.\n\t */\n\n\t/**\n\t * Fired when `LiveRange` instance boundaries have not changed after a change in {@link module:engine/model/document~Document document}\n\t * but the change took place inside the range, effectively changing its content.\n\t *\n\t * @event change:content\n\t * @param {module:engine/model/range~Range} range Range with start and end position equal to start and end position of\n\t * change range.\n\t * @param {Object} data Object with additional information about the change.\n\t * @param {null} data.deletionPosition Due to the nature of this event, this property is always set to `null`. It is passed\n\t * for compatibility with the {@link module:engine/model/liverange~LiveRange#event:change:range} event.\n\t */\n}\n\n// Binds this `LiveRange` to the {@link module:engine/model/document~Document document}\n// that owns this range's {@link module:engine/model/range~Range#root root}.\n//\n// @private\nfunction bindWithDocument() {\n\tthis.listenTo(\n\t\tthis.root.document.model,\n\t\t'applyOperation',\n\t\t( event, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\tif ( !operation.isDocumentOperation ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttransform.call( this, operation );\n\t\t},\n\t\t{ priority: 'low' }\n\t);\n}\n\n// Updates this range accordingly to the updates applied to the model. Bases on change events.\n//\n// @private\n// @param {module:engine/model/operation/operation~Operation} operation Executed operation.\nfunction transform( operation ) {\n\t// Transform the range by the operation. Join the result ranges if needed.\n\tconst ranges = this.getTransformedByOperation( operation );\n\tconst result = Range._createFromRanges( ranges );\n\n\tconst boundariesChanged = !result.isEqual( this );\n\tconst contentChanged = doesOperationChangeRangeContent( this, operation );\n\n\tlet deletionPosition = null;\n\n\tif ( boundariesChanged ) {\n\t\t// If range boundaries have changed, fire `change:range` event.\n\t\t//\n\t\tif ( result.root.rootName == '$graveyard' ) {\n\t\t\t// If the range was moved to the graveyard root, set `deletionPosition`.\n\t\t\tif ( operation.type == 'remove' ) {\n\t\t\t\tdeletionPosition = operation.sourcePosition;\n\t\t\t} else {\n\t\t\t\t// Merge operation.\n\t\t\t\tdeletionPosition = operation.deletionPosition;\n\t\t\t}\n\t\t}\n\n\t\tconst oldRange = this.toRange();\n\n\t\tthis.start = result.start;\n\t\tthis.end = result.end;\n\n\t\tthis.fire( 'change:range', oldRange, { deletionPosition } );\n\t} else if ( contentChanged ) {\n\t\t// If range boundaries have not changed, but there was change inside the range, fire `change:content` event.\n\t\tthis.fire( 'change:content', this.toRange(), { deletionPosition } );\n\t}\n}\n\n// Checks whether given operation changes something inside the range (even if it does not change boundaries).\n//\n// @private\n// @param {module:engine/model/range~Range} range Range to check.\n// @param {module:engine/model/operation/operation~Operation} operation Executed operation.\n// @returns {Boolean}\nfunction doesOperationChangeRangeContent( range, operation ) {\n\tswitch ( operation.type ) {\n\t\tcase 'insert':\n\t\t\treturn range.containsPosition( operation.position );\n\t\tcase 'move':\n\t\tcase 'remove':\n\t\tcase 'reinsert':\n\t\tcase 'merge':\n\t\t\treturn range.containsPosition( operation.sourcePosition ) ||\n\t\t\t\trange.start.isEqual( operation.sourcePosition ) ||\n\t\t\t\trange.containsPosition( operation.targetPosition );\n\t\tcase 'split':\n\t\t\treturn range.containsPosition( operation.splitPosition ) || range.containsPosition( operation.insertionPosition );\n\t}\n\n\treturn false;\n}\n\nmix( LiveRange, EmitterMixin );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/documentselection\n */\n\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\n\nimport Selection from './selection';\nimport LiveRange from './liverange';\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport toMap from '@ckeditor/ckeditor5-utils/src/tomap';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport uid from '@ckeditor/ckeditor5-utils/src/uid';\n\nconst storePrefix = 'selection:';\n\n/**\n * `DocumentSelection` is a special selection which is used as the\n * {@link module:engine/model/document~Document#selection document's selection}.\n * There can be only one instance of `DocumentSelection` per document.\n *\n * Document selection can only be changed by using the {@link module:engine/model/writer~Writer} instance\n * inside the {@link module:engine/model/model~Model#change `change()`} block, as it provides a secure way to modify model.\n *\n * `DocumentSelection` is automatically updated upon changes in the {@link module:engine/model/document~Document document}\n * to always contain valid ranges. Its attributes are inherited from the text unless set explicitly.\n *\n * Differences between {@link module:engine/model/selection~Selection} and `DocumentSelection` are:\n * * there is always a range in `DocumentSelection` - even if no ranges were added there is a \"default range\"\n * present in the selection,\n * * ranges added to this selection updates automatically when the document changes,\n * * attributes of `DocumentSelection` are updated automatically according to selection ranges.\n *\n * Since `DocumentSelection` uses {@link module:engine/model/liverange~LiveRange live ranges}\n * and is updated when {@link module:engine/model/document~Document document}\n * changes, it cannot be set on {@link module:engine/model/node~Node nodes}\n * that are inside {@link module:engine/model/documentfragment~DocumentFragment document fragment}.\n * If you need to represent a selection in document fragment,\n * use {@link module:engine/model/selection~Selection Selection class} instead.\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class DocumentSelection {\n\t/**\n\t * Creates an empty live selection for given {@link module:engine/model/document~Document}.\n\t *\n\t * @param {module:engine/model/document~Document} doc Document which owns this selection.\n\t */\n\tconstructor( doc ) {\n\t\t/**\n\t\t * Selection used internally by that class (`DocumentSelection` is a proxy to that selection).\n\t\t *\n\t\t * @protected\n\t\t */\n\t\tthis._selection = new LiveSelection( doc );\n\n\t\tthis._selection.delegate( 'change:range' ).to( this );\n\t\tthis._selection.delegate( 'change:attribute' ).to( this );\n\t\tthis._selection.delegate( 'change:marker' ).to( this );\n\t}\n\n\t/**\n\t * Returns whether the selection is collapsed. Selection is collapsed when there is exactly one range which is\n\t * collapsed.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\treturn this._selection.isCollapsed;\n\t}\n\n\t/**\n\t * Selection anchor. Anchor may be described as a position where the most recent part of the selection starts.\n\t * Together with {@link #focus} they define the direction of selection, which is important\n\t * when expanding/shrinking selection. Anchor is always {@link module:engine/model/range~Range#start start} or\n\t * {@link module:engine/model/range~Range#end end} position of the most recently added range.\n\t *\n\t * Is set to `null` if there are no ranges in selection.\n\t *\n\t * @see #focus\n\t * @readonly\n\t * @type {module:engine/model/position~Position|null}\n\t */\n\tget anchor() {\n\t\treturn this._selection.anchor;\n\t}\n\n\t/**\n\t * Selection focus. Focus is a position where the selection ends.\n\t *\n\t * Is set to `null` if there are no ranges in selection.\n\t *\n\t * @see #anchor\n\t * @readonly\n\t * @type {module:engine/model/position~Position|null}\n\t */\n\tget focus() {\n\t\treturn this._selection.focus;\n\t}\n\n\t/**\n\t * Returns number of ranges in selection.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget rangeCount() {\n\t\treturn this._selection.rangeCount;\n\t}\n\n\t/**\n\t * Describes whether `Documentselection` has own range(s) set, or if it is defaulted to\n\t * {@link module:engine/model/document~Document#_getDefaultRange document's default range}.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget hasOwnRange() {\n\t\treturn this._selection.hasOwnRange;\n\t}\n\n\t/**\n\t * Specifies whether the {@link #focus}\n\t * precedes {@link #anchor}.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isBackward() {\n\t\treturn this._selection.isBackward;\n\t}\n\n\t/**\n\t * Describes whether the gravity is overridden (using {@link module:engine/model/writer~Writer#overrideSelectionGravity}) or not.\n\t *\n\t * Note that the gravity remains overridden as long as will not be restored the same number of times as it was overridden.\n\t *\n\t * @readonly\n\t * @returns {Boolean}\n\t */\n\tget isGravityOverridden() {\n\t\treturn this._selection.isGravityOverridden;\n\t}\n\n\t/**\n\t * A collection of selection {@link module:engine/model/markercollection~Marker markers}.\n\t * Marker is a selection marker when selection range is inside the marker range.\n\t *\n\t * **Note**: Only markers from {@link ~DocumentSelection#observeMarkers observed markers groups} are collected.\n\t *\n\t * @readonly\n\t * @type {module:utils/collection~Collection}\n\t */\n\tget markers() {\n\t\treturn this._selection.markers;\n\t}\n\n\t/**\n\t * Used for the compatibility with the {@link module:engine/model/selection~Selection#isEqual} method.\n\t *\n\t * @protected\n\t */\n\tget _ranges() {\n\t\treturn this._selection._ranges;\n\t}\n\n\t/**\n\t * Returns an iterable that iterates over copies of selection ranges.\n\t *\n\t * @returns {Iterable.<module:engine/model/range~Range>}\n\t */\n\tgetRanges() {\n\t\treturn this._selection.getRanges();\n\t}\n\n\t/**\n\t * Returns the first position in the selection.\n\t * First position is the position that {@link module:engine/model/position~Position#isBefore is before}\n\t * any other position in the selection.\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/position~Position|null}\n\t */\n\tgetFirstPosition() {\n\t\treturn this._selection.getFirstPosition();\n\t}\n\n\t/**\n\t * Returns the last position in the selection.\n\t * Last position is the position that {@link module:engine/model/position~Position#isAfter is after}\n\t * any other position in the selection.\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/position~Position|null}\n\t */\n\tgetLastPosition() {\n\t\treturn this._selection.getLastPosition();\n\t}\n\n\t/**\n\t * Returns a copy of the first range in the selection.\n\t * First range is the one which {@link module:engine/model/range~Range#start start} position\n\t * {@link module:engine/model/position~Position#isBefore is before} start position of all other ranges\n\t * (not to confuse with the first range added to the selection).\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/range~Range|null}\n\t */\n\tgetFirstRange() {\n\t\treturn this._selection.getFirstRange();\n\t}\n\n\t/**\n\t * Returns a copy of the last range in the selection.\n\t * Last range is the one which {@link module:engine/model/range~Range#end end} position\n\t * {@link module:engine/model/position~Position#isAfter is after} end position of all other ranges (not to confuse with the range most\n\t * recently added to the selection).\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/range~Range|null}\n\t */\n\tgetLastRange() {\n\t\treturn this._selection.getLastRange();\n\t}\n\n\t/**\n\t * Gets elements of type {@link module:engine/model/schema~Schema#isBlock \"block\"} touched by the selection.\n\t *\n\t * This method's result can be used for example to apply block styling to all blocks covered by this selection.\n\t *\n\t * **Note:** `getSelectedBlocks()` returns blocks that are nested in other non-block elements\n\t * but will not return blocks nested in other blocks.\n\t *\n\t * In this case the function will return exactly all 3 paragraphs (note: `<blockQuote>` is not a block itself):\n\t *\n\t *\t\t<paragraph>[a</paragraph>\n\t *\t\t<blockQuote>\n\t *\t\t\t<paragraph>b</paragraph>\n\t *\t\t</blockQuote>\n\t *\t\t<paragraph>c]d</paragraph>\n\t *\n\t * In this case the paragraph will also be returned, despite the collapsed selection:\n\t *\n\t *\t\t<paragraph>[]a</paragraph>\n\t *\n\t * In such a scenario, however, only blocks A, B & E will be returned as blocks C & D are nested in block B:\n\t *\n\t *\t\t[<blockA></blockA>\n\t *\t\t<blockB>\n\t *\t\t\t<blockC></blockC>\n\t *\t\t\t<blockD></blockD>\n\t *\t\t</blockB>\n\t *\t\t<blockE></blockE>]\n\t *\n\t * If the selection is inside a block all the inner blocks (A & B) are returned:\n\t *\n\t * \t\t<block>\n\t *\t\t\t<blockA>[a</blockA>\n\t * \t\t\t<blockB>b]</blockB>\n\t * \t\t</block>\n\t *\n\t * **Special case**: If a selection ends at the beginning of a block, that block is not returned as from user perspective\n\t * this block wasn't selected. See [#984](https://github.com/ckeditor/ckeditor5-engine/issues/984) for more details.\n\t *\n\t *\t\t<paragraph>[a</paragraph>\n\t *\t\t<paragraph>b</paragraph>\n\t *\t\t<paragraph>]c</paragraph> // this block will not be returned\n\t *\n\t * @returns {Iterable.<module:engine/model/element~Element>}\n\t */\n\tgetSelectedBlocks() {\n\t\treturn this._selection.getSelectedBlocks();\n\t}\n\n\t/**\n\t * Returns the selected element. {@link module:engine/model/element~Element Element} is considered as selected if there is only\n\t * one range in the selection, and that range contains exactly one element.\n\t * Returns `null` if there is no selected element.\n\t *\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\tgetSelectedElement() {\n\t\treturn this._selection.getSelectedElement();\n\t}\n\n\t/**\n\t * Checks whether the selection contains the entire content of the given element. This means that selection must start\n\t * at a position {@link module:engine/model/position~Position#isTouching touching} the element's start and ends at position\n\t * touching the element's end.\n\t *\n\t * By default, this method will check whether the entire content of the selection's current root is selected.\n\t * Useful to check if e.g. the user has just pressed <kbd>Ctrl</kbd> + <kbd>A</kbd>.\n\t *\n\t * @param {module:engine/model/element~Element} [element=this.anchor.root]\n\t * @returns {Boolean}\n\t */\n\tcontainsEntireContent( element ) {\n\t\treturn this._selection.containsEntireContent( element );\n\t}\n\n\t/**\n\t * Unbinds all events previously bound by document selection.\n\t */\n\tdestroy() {\n\t\tthis._selection.destroy();\n\t}\n\n\t/**\n\t * Returns iterable that iterates over this selection's attribute keys.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetAttributeKeys() {\n\t\treturn this._selection.getAttributeKeys();\n\t}\n\n\t/**\n\t * Returns iterable that iterates over this selection's attributes.\n\t *\n\t * Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.\n\t * This format is accepted by native `Map` object and also can be passed in `Node` constructor.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\tgetAttributes() {\n\t\treturn this._selection.getAttributes();\n\t}\n\n\t/**\n\t * Gets an attribute value for given key or `undefined` if that attribute is not set on the selection.\n\t *\n\t * @param {String} key Key of attribute to look for.\n\t * @returns {*} Attribute value or `undefined`.\n\t */\n\tgetAttribute( key ) {\n\t\treturn this._selection.getAttribute( key );\n\t}\n\n\t/**\n\t * Checks if the selection has an attribute for given key.\n\t *\n\t * @param {String} key Key of attribute to check.\n\t * @returns {Boolean} `true` if attribute with given key is set on selection, `false` otherwise.\n\t */\n\thasAttribute( key ) {\n\t\treturn this._selection.hasAttribute( key );\n\t}\n\n\t/**\n\t * Refreshes selection attributes and markers according to the current position in the model.\n\t */\n\trefresh() {\n\t\tthis._selection._updateMarkers();\n\t\tthis._selection._updateAttributes( false );\n\t}\n\n\t/**\n\t * Registers marker group prefix or marker name to be collected in {@link ~DocumentSelection#markers selection markers collection}.\n\t *\n\t * See also {@link module:engine/model/markercollection~MarkerCollection#getMarkersGroup `MarkerCollection#getMarkersGroup()`}.\n\t *\n\t * @param {String} prefixOrName Marker group prefix or marker name.\n\t */\n\tobserveMarkers( prefixOrName ) {\n\t\tthis._selection.observeMarkers( prefixOrName );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tselection.is( 'selection' ); // -> true\n\t *\t\tselection.is( 'documentSelection' ); // -> true\n\t *\t\tselection.is( 'model:selection' ); // -> true\n\t *\t\tselection.is( 'model:documentSelection' ); // -> true\n\t *\n\t *\t\tselection.is( 'view:selection' ); // -> false\n\t *\t\tselection.is( 'element' ); // -> false\n\t *\t\tselection.is( 'node' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'selection' ||\n\t\t\ttype == 'model:selection' ||\n\t\t\ttype == 'documentSelection' ||\n\t\t\ttype == 'model:documentSelection';\n\t}\n\n\t/**\n\t * Moves {@link module:engine/model/documentselection~DocumentSelection#focus} to the specified location.\n\t * Should be used only within the {@link module:engine/model/writer~Writer#setSelectionFocus} method.\n\t *\n\t * The location can be specified in the same form as\n\t * {@link module:engine/model/writer~Writer#createPositionAt writer.createPositionAt()} parameters.\n\t *\n\t * @see module:engine/model/writer~Writer#setSelectionFocus\n\t * @protected\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\t_setFocus( itemOrPosition, offset ) {\n\t\tthis._selection.setFocus( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Sets this selection's ranges and direction to the specified location based on the given\n\t * {@link module:engine/model/selection~Selectable selectable}.\n\t * Should be used only within the {@link module:engine/model/writer~Writer#setSelection} method.\n\t *\n\t * @see module:engine/model/writer~Writer#setSelection\n\t * @protected\n\t * @param {module:engine/model/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t */\n\t_setTo( selectable, placeOrOffset, options ) {\n\t\tthis._selection.setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Sets attribute on the selection. If attribute with the same key already is set, it's value is overwritten.\n\t * Should be used only within the {@link module:engine/model/writer~Writer#setSelectionAttribute} method.\n\t *\n\t * @see module:engine/model/writer~Writer#setSelectionAttribute\n\t * @protected\n\t * @param {String} key Key of the attribute to set.\n\t * @param {*} value Attribute value.\n\t */\n\t_setAttribute( key, value ) {\n\t\tthis._selection.setAttribute( key, value );\n\t}\n\n\t/**\n\t * Removes an attribute with given key from the selection.\n\t * If the given attribute was set on the selection, fires the {@link module:engine/model/selection~Selection#event:change:range}\n\t * event with removed attribute key.\n\t * Should be used only within the {@link module:engine/model/writer~Writer#removeSelectionAttribute} method.\n\t *\n\t * @see module:engine/model/writer~Writer#removeSelectionAttribute\n\t * @protected\n\t * @param {String} key Key of the attribute to remove.\n\t */\n\t_removeAttribute( key ) {\n\t\tthis._selection.removeAttribute( key );\n\t}\n\n\t/**\n\t * Returns an iterable that iterates through all selection attributes stored in current selection's parent.\n\t *\n\t * @protected\n\t * @returns {Iterable.<*>}\n\t */\n\t_getStoredAttributes() {\n\t\treturn this._selection._getStoredAttributes();\n\t}\n\n\t/**\n\t * Temporarily changes the gravity of the selection from the left to the right.\n\t *\n\t * The gravity defines from which direction the selection inherits its attributes. If it's the default left\n\t * gravity, the selection (after being moved by the the user) inherits attributes from its left hand side.\n\t * This method allows to temporarily override this behavior by forcing the gravity to the right.\n\t *\n\t * It returns an unique identifier which is required to restore the gravity. It guarantees the symmetry\n\t * of the process.\n\t *\n\t * @see module:engine/model/writer~Writer#overrideSelectionGravity\n\t * @protected\n\t * @returns {String} The unique id which allows restoring the gravity.\n\t */\n\t_overrideGravity() {\n\t\treturn this._selection.overrideGravity();\n\t}\n\n\t/**\n\t * Restores the {@link ~DocumentSelection#_overrideGravity overridden gravity}.\n\t *\n\t * Restoring the gravity is only possible using the unique identifier returned by\n\t * {@link ~DocumentSelection#_overrideGravity}. Note that the gravity remains overridden as long as won't be restored\n\t * the same number of times it was overridden.\n\t *\n\t * @see module:engine/model/writer~Writer#restoreSelectionGravity\n\t * @protected\n\t * @param {String} uid The unique id returned by {@link #_overrideGravity}.\n\t */\n\t_restoreGravity( uid ) {\n\t\tthis._selection.restoreGravity( uid );\n\t}\n\n\t/**\n\t * Generates and returns an attribute key for selection attributes store, basing on original attribute key.\n\t *\n\t * @protected\n\t * @param {String} key Attribute key to convert.\n\t * @returns {String} Converted attribute key, applicable for selection store.\n\t */\n\tstatic _getStoreAttributeKey( key ) {\n\t\treturn storePrefix + key;\n\t}\n\n\t/**\n\t * Checks whether the given attribute key is an attribute stored on an element.\n\t *\n\t * @protected\n\t * @param {String} key\n\t * @returns {Boolean}\n\t */\n\tstatic _isStoreAttributeKey( key ) {\n\t\treturn key.startsWith( storePrefix );\n\t}\n}\n\nmix( DocumentSelection, EmitterMixin );\n\n/**\n * Fired when selection range(s) changed.\n *\n * @event change:range\n * @param {Boolean} directChange In case of {@link module:engine/model/selection~Selection} class it is always set\n * to `true` which indicates that the selection change was caused by a direct use of selection's API.\n * The {@link module:engine/model/documentselection~DocumentSelection}, however, may change because its position\n * was directly changed through the {@link module:engine/model/writer~Writer writer} or because its position was\n * changed because the structure of the model has been changed (which means an indirect change).\n * The indirect change does not occur in case of normal (detached) selections because they are \"static\" (as \"not live\")\n * which mean that they are not updated once the document changes.\n */\n\n/**\n * Fired when selection attribute changed.\n *\n * @event change:attribute\n * @param {Boolean} directChange In case of {@link module:engine/model/selection~Selection} class it is always set\n * to `true` which indicates that the selection change was caused by a direct use of selection's API.\n * The {@link module:engine/model/documentselection~DocumentSelection}, however, may change because its attributes\n * were directly changed through the {@link module:engine/model/writer~Writer writer} or because its position was\n * changed in the model and its attributes were refreshed (which means an indirect change).\n * The indirect change does not occur in case of normal (detached) selections because they are \"static\" (as \"not live\")\n * which mean that they are not updated once the document changes.\n * @param {Array.<String>} attributeKeys Array containing keys of attributes that changed.\n */\n\n/**\n * Fired when selection marker(s) changed.\n *\n * @event change:marker\n * @param {Boolean} directChange This is always set to `false` in case of `change:marker` event as there is no possibility\n * to change markers directly through {@link module:engine/model/documentselection~DocumentSelection} API.\n * See also {@link module:engine/model/documentselection~DocumentSelection#event:change:range} and\n * {@link module:engine/model/documentselection~DocumentSelection#event:change:attribute}.\n * @param {Array.<module:engine/model/markercollection~Marker>} oldMarkers Markers in which the selection was before the change.\n */\n\n// `LiveSelection` is used internally by {@link module:engine/model/documentselection~DocumentSelection} and shouldn't be used directly.\n//\n// LiveSelection` is automatically updated upon changes in the {@link module:engine/model/document~Document document}\n// to always contain valid ranges. Its attributes are inherited from the text unless set explicitly.\n//\n// Differences between {@link module:engine/model/selection~Selection} and `LiveSelection` are:\n// * there is always a range in `LiveSelection` - even if no ranges were added there is a \"default range\"\n// present in the selection,\n// * ranges added to this selection updates automatically when the document changes,\n// * attributes of `LiveSelection` are updated automatically according to selection ranges.\n//\n// @extends module:engine/model/selection~Selection\n//\nclass LiveSelection extends Selection {\n\t// Creates an empty live selection for given {@link module:engine/model/document~Document}.\n\t// @param {module:engine/model/document~Document} doc Document which owns this selection.\n\tconstructor( doc ) {\n\t\tsuper();\n\n\t\t// List of selection markers.\n\t\t// Marker is a selection marker when selection range is inside the marker range.\n\t\t//\n\t\t// @type {module:utils/collection~Collection}\n\t\tthis.markers = new Collection( { idProperty: 'name' } );\n\n\t\t// Document which owns this selection.\n\t\t//\n\t\t// @protected\n\t\t// @member {module:engine/model/model~Model}\n\t\tthis._model = doc.model;\n\n\t\t// Document which owns this selection.\n\t\t//\n\t\t// @protected\n\t\t// @member {module:engine/model/document~Document}\n\t\tthis._document = doc;\n\n\t\t// Keeps mapping of attribute name to priority with which the attribute got modified (added/changed/removed)\n\t\t// last time. Possible values of priority are: `'low'` and `'normal'`.\n\t\t//\n\t\t// Priorities are used by internal `LiveSelection` mechanisms. All attributes set using `LiveSelection`\n\t\t// attributes API are set with `'normal'` priority.\n\t\t//\n\t\t// @private\n\t\t// @member {Map} module:engine/model/liveselection~LiveSelection#_attributePriority\n\t\tthis._attributePriority = new Map();\n\n\t\t// Position to which the selection should be set if the last selection range was moved to the graveyard.\n\t\t// @private\n\t\t// @member {module:engine/model/position~Position} module:engine/model/liveselection~LiveSelection#_selectionRestorePosition\n\t\tthis._selectionRestorePosition = null;\n\n\t\t// Flag that informs whether the selection ranges have changed. It is changed on true when `LiveRange#change:range` event is fired.\n\t\t// @private\n\t\t// @member {Array} module:engine/model/liveselection~LiveSelection#_hasChangedRange\n\t\tthis._hasChangedRange = false;\n\n\t\t// Each overriding gravity adds an UID to the set and each removal removes it.\n\t\t// Gravity is overridden when there's at least one UID in the set.\n\t\t// Gravity is restored when the set is empty.\n\t\t// This is to prevent conflicts when gravity is overridden by more than one feature at the same time.\n\t\t// @private\n\t\t// @type {Set}\n\t\tthis._overriddenGravityRegister = new Set();\n\n\t\t// Prefixes of marker names that should affect `LiveSelection#markers` collection.\n\t\t// @private\n\t\t// @type {Set}\n\t\tthis._observedMarkers = new Set();\n\n\t\t// Ensure selection is correct after each operation.\n\t\tthis.listenTo( this._model, 'applyOperation', ( evt, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\tif ( !operation.isDocumentOperation || operation.type == 'marker' || operation.type == 'rename' || operation.type == 'noop' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Fix selection if the last range was removed from it and we have a position to which we can restore the selection.\n\t\t\tif ( this._ranges.length == 0 && this._selectionRestorePosition ) {\n\t\t\t\tthis._fixGraveyardSelection( this._selectionRestorePosition );\n\t\t\t}\n\n\t\t\t// \"Forget\" the restore position even if it was not \"used\".\n\t\t\tthis._selectionRestorePosition = null;\n\n\t\t\tif ( this._hasChangedRange ) {\n\t\t\t\tthis._hasChangedRange = false;\n\t\t\t\tthis.fire( 'change:range', { directChange: false } );\n\t\t\t}\n\t\t}, { priority: 'lowest' } );\n\n\t\t// Ensure selection is correct and up to date after each range change.\n\t\tthis.on( 'change:range', () => {\n\t\t\tfor ( const range of this.getRanges() ) {\n\t\t\t\tif ( !this._document._validateSelectionRange( range ) ) {\n\t\t\t\t\t/**\n\t\t\t\t\t * Range from {@link module:engine/model/documentselection~DocumentSelection document selection}\n\t\t\t\t\t * starts or ends at incorrect position.\n\t\t\t\t\t *\n\t\t\t\t\t * @error document-selection-wrong-position\n\t\t\t\t\t * @param {module:engine/model/range~Range} range\n\t\t\t\t\t */\n\t\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t\t'document-selection-wrong-position',\n\t\t\t\t\t\tthis,\n\t\t\t\t\t\t{ range }\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\t// Update markers data stored by the selection after each marker change.\n\t\t// This handles only marker changes done through marker operations (not model tree changes).\n\t\tthis.listenTo( this._model.markers, 'update', ( evt, marker, oldRange, newRange ) => {\n\t\t\tthis._updateMarker( marker, newRange );\n\t\t} );\n\n\t\t// Ensure selection is up to date after each change block.\n\t\tthis.listenTo( this._document, 'change', ( evt, batch ) => {\n\t\t\tclearAttributesStoredInElement( this._model, batch );\n\t\t} );\n\t}\n\n\tget isCollapsed() {\n\t\tconst length = this._ranges.length;\n\n\t\treturn length === 0 ? this._document._getDefaultRange().isCollapsed : super.isCollapsed;\n\t}\n\n\tget anchor() {\n\t\treturn super.anchor || this._document._getDefaultRange().start;\n\t}\n\n\tget focus() {\n\t\treturn super.focus || this._document._getDefaultRange().end;\n\t}\n\n\tget rangeCount() {\n\t\treturn this._ranges.length ? this._ranges.length : 1;\n\t}\n\n\t// Describes whether `LiveSelection` has own range(s) set, or if it is defaulted to\n\t// {@link module:engine/model/document~Document#_getDefaultRange document's default range}.\n\t//\n\t// @readonly\n\t// @type {Boolean}\n\tget hasOwnRange() {\n\t\treturn this._ranges.length > 0;\n\t}\n\n\t// When set to `true` then selection attributes on node before the caret won't be taken\n\t// into consideration while updating selection attributes.\n\t//\n\t// @protected\n\t// @type {Boolean}\n\tget isGravityOverridden() {\n\t\treturn !!this._overriddenGravityRegister.size;\n\t}\n\n\t// Unbinds all events previously bound by live selection.\n\tdestroy() {\n\t\tfor ( let i = 0; i < this._ranges.length; i++ ) {\n\t\t\tthis._ranges[ i ].detach();\n\t\t}\n\n\t\tthis.stopListening();\n\t}\n\n\t* getRanges() {\n\t\tif ( this._ranges.length ) {\n\t\t\tyield* super.getRanges();\n\t\t} else {\n\t\t\tyield this._document._getDefaultRange();\n\t\t}\n\t}\n\n\tgetFirstRange() {\n\t\treturn super.getFirstRange() || this._document._getDefaultRange();\n\t}\n\n\tgetLastRange() {\n\t\treturn super.getLastRange() || this._document._getDefaultRange();\n\t}\n\n\tsetTo( selectable, optionsOrPlaceOrOffset, options ) {\n\t\tsuper.setTo( selectable, optionsOrPlaceOrOffset, options );\n\t\tthis._updateAttributes( true );\n\t\tthis._updateMarkers();\n\t}\n\n\tsetFocus( itemOrPosition, offset ) {\n\t\tsuper.setFocus( itemOrPosition, offset );\n\t\tthis._updateAttributes( true );\n\t\tthis._updateMarkers();\n\t}\n\n\tsetAttribute( key, value ) {\n\t\tif ( this._setAttribute( key, value ) ) {\n\t\t\t// Fire event with exact data.\n\t\t\tconst attributeKeys = [ key ];\n\t\t\tthis.fire( 'change:attribute', { attributeKeys, directChange: true } );\n\t\t}\n\t}\n\n\tremoveAttribute( key ) {\n\t\tif ( this._removeAttribute( key ) ) {\n\t\t\t// Fire event with exact data.\n\t\t\tconst attributeKeys = [ key ];\n\t\t\tthis.fire( 'change:attribute', { attributeKeys, directChange: true } );\n\t\t}\n\t}\n\n\toverrideGravity() {\n\t\tconst overrideUid = uid();\n\n\t\t// Remember that another overriding has been requested. It will need to be removed\n\t\t// before the gravity is to be restored.\n\t\tthis._overriddenGravityRegister.add( overrideUid );\n\n\t\tif ( this._overriddenGravityRegister.size === 1 ) {\n\t\t\tthis._updateAttributes( true );\n\t\t}\n\n\t\treturn overrideUid;\n\t}\n\n\trestoreGravity( uid ) {\n\t\tif ( !this._overriddenGravityRegister.has( uid ) ) {\n\t\t\t/**\n\t\t\t * Restoring gravity for an unknown UID is not possible. Make sure you are using a correct\n\t\t\t * UID obtained from the {@link module:engine/model/writer~Writer#overrideSelectionGravity} to restore.\n\t\t\t *\n\t\t\t * @error document-selection-gravity-wrong-restore\n\t\t\t * @param {String} uid The unique identifier returned by\n\t\t\t * {@link module:engine/model/documentselection~DocumentSelection#_overrideGravity}.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'document-selection-gravity-wrong-restore',\n\t\t\t\tthis,\n\t\t\t\t{ uid }\n\t\t\t);\n\t\t}\n\n\t\tthis._overriddenGravityRegister.delete( uid );\n\n\t\t// Restore gravity only when all overriding have been restored.\n\t\tif ( !this.isGravityOverridden ) {\n\t\t\tthis._updateAttributes( true );\n\t\t}\n\t}\n\n\tobserveMarkers( prefixOrName ) {\n\t\tthis._observedMarkers.add( prefixOrName );\n\t\tthis._updateMarkers();\n\t}\n\n\t_popRange() {\n\t\tthis._ranges.pop().detach();\n\t}\n\n\t_pushRange( range ) {\n\t\tconst liveRange = this._prepareRange( range );\n\n\t\t// `undefined` is returned when given `range` is in graveyard root.\n\t\tif ( liveRange ) {\n\t\t\tthis._ranges.push( liveRange );\n\t\t}\n\t}\n\n\t// Prepares given range to be added to selection. Checks if it is correct,\n\t// converts it to {@link module:engine/model/liverange~LiveRange LiveRange}\n\t// and sets listeners listening to the range's change event.\n\t//\n\t// @private\n\t// @param {module:engine/model/range~Range} range\n\t_prepareRange( range ) {\n\t\tthis._checkRange( range );\n\n\t\tif ( range.root == this._document.graveyard ) {\n\t\t\t// @if CK_DEBUG // console.warn( 'Trying to add a Range that is in the graveyard root. Range rejected.' );\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst liveRange = LiveRange.fromRange( range );\n\n\t\t// If selection range is moved to the graveyard remove it from the selection object.\n\t\t// Also, save some data that can be used to restore selection later, on `Model#applyOperation` event.\n\t\tliveRange.on( 'change:range', ( evt, oldRange, data ) => {\n\t\t\tthis._hasChangedRange = true;\n\n\t\t\tif ( liveRange.root == this._document.graveyard ) {\n\t\t\t\tthis._selectionRestorePosition = data.deletionPosition;\n\n\t\t\t\tconst index = this._ranges.indexOf( liveRange );\n\t\t\t\tthis._ranges.splice( index, 1 );\n\t\t\t\tliveRange.detach();\n\t\t\t}\n\t\t} );\n\n\t\treturn liveRange;\n\t}\n\n\t_updateMarkers() {\n\t\tif ( !this._observedMarkers.size ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst markers = [];\n\t\tlet changed = false;\n\n\t\tfor ( const marker of this._model.markers ) {\n\t\t\tconst markerGroup = marker.name.split( ':', 1 )[ 0 ];\n\n\t\t\tif ( !this._observedMarkers.has( markerGroup ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst markerRange = marker.getRange();\n\n\t\t\tfor ( const selectionRange of this.getRanges() ) {\n\t\t\t\tif ( markerRange.containsRange( selectionRange, !selectionRange.isCollapsed ) ) {\n\t\t\t\t\tmarkers.push( marker );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst oldMarkers = Array.from( this.markers );\n\n\t\tfor ( const marker of markers ) {\n\t\t\tif ( !this.markers.has( marker ) ) {\n\t\t\t\tthis.markers.add( marker );\n\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\n\t\tfor ( const marker of Array.from( this.markers ) ) {\n\t\t\tif ( !markers.includes( marker ) ) {\n\t\t\t\tthis.markers.remove( marker );\n\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\n\t\tif ( changed ) {\n\t\t\tthis.fire( 'change:marker', { oldMarkers, directChange: false } );\n\t\t}\n\t}\n\n\t_updateMarker( marker, markerRange ) {\n\t\tconst markerGroup = marker.name.split( ':', 1 )[ 0 ];\n\n\t\tif ( !this._observedMarkers.has( markerGroup ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet changed = false;\n\n\t\tconst oldMarkers = Array.from( this.markers );\n\t\tconst hasMarker = this.markers.has( marker );\n\n\t\tif ( !markerRange ) {\n\t\t\tif ( hasMarker ) {\n\t\t\t\tthis.markers.remove( marker );\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t} else {\n\t\t\tlet contained = false;\n\n\t\t\tfor ( const selectionRange of this.getRanges() ) {\n\t\t\t\tif ( markerRange.containsRange( selectionRange, !selectionRange.isCollapsed ) ) {\n\t\t\t\t\tcontained = true;\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( contained && !hasMarker ) {\n\t\t\t\tthis.markers.add( marker );\n\n\t\t\t\tchanged = true;\n\t\t\t} else if ( !contained && hasMarker ) {\n\t\t\t\tthis.markers.remove( marker );\n\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\n\t\tif ( changed ) {\n\t\t\tthis.fire( 'change:marker', { oldMarkers, directChange: false } );\n\t\t}\n\t}\n\n\t// Updates this selection attributes according to its ranges and the {@link module:engine/model/document~Document model document}.\n\t//\n\t// @protected\n\t// @param {Boolean} clearAll\n\t// @fires change:attribute\n\t_updateAttributes( clearAll ) {\n\t\tconst newAttributes = toMap( this._getSurroundingAttributes() );\n\t\tconst oldAttributes = toMap( this.getAttributes() );\n\n\t\tif ( clearAll ) {\n\t\t\t// If `clearAll` remove all attributes and reset priorities.\n\t\t\tthis._attributePriority = new Map();\n\t\t\tthis._attrs = new Map();\n\t\t} else {\n\t\t\t// If not, remove only attributes added with `low` priority.\n\t\t\tfor ( const [ key, priority ] of this._attributePriority ) {\n\t\t\t\tif ( priority == 'low' ) {\n\t\t\t\t\tthis._attrs.delete( key );\n\t\t\t\t\tthis._attributePriority.delete( key );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis._setAttributesTo( newAttributes );\n\n\t\t// Let's evaluate which attributes really changed.\n\t\tconst changed = [];\n\n\t\t// First, loop through all attributes that are set on selection right now.\n\t\t// Check which of them are different than old attributes.\n\t\tfor ( const [ newKey, newValue ] of this.getAttributes() ) {\n\t\t\tif ( !oldAttributes.has( newKey ) || oldAttributes.get( newKey ) !== newValue ) {\n\t\t\t\tchanged.push( newKey );\n\t\t\t}\n\t\t}\n\n\t\t// Then, check which of old attributes got removed.\n\t\tfor ( const [ oldKey ] of oldAttributes ) {\n\t\t\tif ( !this.hasAttribute( oldKey ) ) {\n\t\t\t\tchanged.push( oldKey );\n\t\t\t}\n\t\t}\n\n\t\t// Fire event with exact data (fire only if anything changed).\n\t\tif ( changed.length > 0 ) {\n\t\t\tthis.fire( 'change:attribute', { attributeKeys: changed, directChange: false } );\n\t\t}\n\t}\n\n\t// Internal method for setting `LiveSelection` attribute. Supports attribute priorities (through `directChange`\n\t// parameter).\n\t//\n\t// @private\n\t// @param {String} key Attribute key.\n\t// @param {*} value Attribute value.\n\t// @param {Boolean} [directChange=true] `true` if the change is caused by `Selection` API, `false` if change\n\t// is caused by `Batch` API.\n\t// @returns {Boolean} Whether value has changed.\n\t_setAttribute( key, value, directChange = true ) {\n\t\tconst priority = directChange ? 'normal' : 'low';\n\n\t\tif ( priority == 'low' && this._attributePriority.get( key ) == 'normal' ) {\n\t\t\t// Priority too low.\n\t\t\treturn false;\n\t\t}\n\n\t\tconst oldValue = super.getAttribute( key );\n\n\t\t// Don't do anything if value has not changed.\n\t\tif ( oldValue === value ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis._attrs.set( key, value );\n\n\t\t// Update priorities map.\n\t\tthis._attributePriority.set( key, priority );\n\n\t\treturn true;\n\t}\n\n\t// Internal method for removing `LiveSelection` attribute. Supports attribute priorities (through `directChange`\n\t// parameter).\n\t//\n\t// NOTE: Even if attribute is not present in the selection but is provided to this method, it's priority will\n\t// be changed according to `directChange` parameter.\n\t//\n\t// @private\n\t// @param {String} key Attribute key.\n\t// @param {Boolean} [directChange=true] `true` if the change is caused by `Selection` API, `false` if change\n\t// is caused by `Batch` API.\n\t// @returns {Boolean} Whether attribute was removed. May not be true if such attributes didn't exist or the\n\t// existing attribute had higher priority.\n\t_removeAttribute( key, directChange = true ) {\n\t\tconst priority = directChange ? 'normal' : 'low';\n\n\t\tif ( priority == 'low' && this._attributePriority.get( key ) == 'normal' ) {\n\t\t\t// Priority too low.\n\t\t\treturn false;\n\t\t}\n\n\t\t// Update priorities map.\n\t\tthis._attributePriority.set( key, priority );\n\n\t\t// Don't do anything if value has not changed.\n\t\tif ( !super.hasAttribute( key ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis._attrs.delete( key );\n\n\t\treturn true;\n\t}\n\n\t// Internal method for setting multiple `LiveSelection` attributes. Supports attribute priorities (through\n\t// `directChange` parameter).\n\t//\n\t// @private\n\t// @param {Map.<String,*>} attrs Iterable object containing attributes to be set.\n\t// @returns {Set.<String>} Changed attribute keys.\n\t_setAttributesTo( attrs ) {\n\t\tconst changed = new Set();\n\n\t\tfor ( const [ oldKey, oldValue ] of this.getAttributes() ) {\n\t\t\t// Do not remove attribute if attribute with same key and value is about to be set.\n\t\t\tif ( attrs.get( oldKey ) === oldValue ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// All rest attributes will be removed so changed attributes won't change .\n\t\t\tthis._removeAttribute( oldKey, false );\n\t\t}\n\n\t\tfor ( const [ key, value ] of attrs ) {\n\t\t\t// Attribute may not be set because of attributes or because same key/value is already added.\n\t\t\tconst gotAdded = this._setAttribute( key, value, false );\n\n\t\t\tif ( gotAdded ) {\n\t\t\t\tchanged.add( key );\n\t\t\t}\n\t\t}\n\n\t\treturn changed;\n\t}\n\n\t// Returns an iterable that iterates through all selection attributes stored in current selection's parent.\n\t//\n\t// @protected\n\t// @returns {Iterable.<*>}\n\t* _getStoredAttributes() {\n\t\tconst selectionParent = this.getFirstPosition().parent;\n\n\t\tif ( this.isCollapsed && selectionParent.isEmpty ) {\n\t\t\tfor ( const key of selectionParent.getAttributeKeys() ) {\n\t\t\t\tif ( key.startsWith( storePrefix ) ) {\n\t\t\t\t\tconst realKey = key.substr( storePrefix.length );\n\n\t\t\t\t\tyield [ realKey, selectionParent.getAttribute( key ) ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Checks model text nodes that are closest to the selection's first position and returns attributes of first\n\t// found element. If there are no text nodes in selection's first position parent, it returns selection\n\t// attributes stored in that parent.\n\t//\n\t// @private\n\t// @returns {Iterable.<*>} Collection of attributes.\n\t_getSurroundingAttributes() {\n\t\tconst position = this.getFirstPosition();\n\t\tconst schema = this._model.schema;\n\n\t\tlet attrs = null;\n\n\t\tif ( !this.isCollapsed ) {\n\t\t\t// 1. If selection is a range...\n\t\t\tconst range = this.getFirstRange();\n\n\t\t\t// ...look for a first character node in that range and take attributes from it.\n\t\t\tfor ( const value of range ) {\n\t\t\t\t// If the item is an object, we don't want to get attributes from its children.\n\t\t\t\tif ( value.item.is( 'element' ) && schema.isObject( value.item ) ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ( value.type == 'text' ) {\n\t\t\t\t\tattrs = value.item.getAttributes();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// 2. If the selection is a caret or the range does not contain a character node...\n\n\t\t\tconst nodeBefore = position.textNode ? position.textNode : position.nodeBefore;\n\t\t\tconst nodeAfter = position.textNode ? position.textNode : position.nodeAfter;\n\n\t\t\t// When gravity is overridden then don't take node before into consideration.\n\t\t\tif ( !this.isGravityOverridden ) {\n\t\t\t\t// ...look at the node before caret and take attributes from it if it is a character node.\n\t\t\t\tattrs = getAttrsIfCharacter( nodeBefore );\n\t\t\t}\n\n\t\t\t// 3. If not, look at the node after caret...\n\t\t\tif ( !attrs ) {\n\t\t\t\tattrs = getAttrsIfCharacter( nodeAfter );\n\t\t\t}\n\n\t\t\t// 4. If not, try to find the first character on the left, that is in the same node.\n\t\t\t// When gravity is overridden then don't take node before into consideration.\n\t\t\tif ( !this.isGravityOverridden && !attrs ) {\n\t\t\t\tlet node = nodeBefore;\n\n\t\t\t\twhile ( node && !schema.isInline( node ) && !attrs ) {\n\t\t\t\t\tnode = node.previousSibling;\n\t\t\t\t\tattrs = getAttrsIfCharacter( node );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 5. If not found, try to find the first character on the right, that is in the same node.\n\t\t\tif ( !attrs ) {\n\t\t\t\tlet node = nodeAfter;\n\n\t\t\t\twhile ( node && !schema.isInline( node ) && !attrs ) {\n\t\t\t\t\tnode = node.nextSibling;\n\t\t\t\t\tattrs = getAttrsIfCharacter( node );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 6. If not found, selection should retrieve attributes from parent.\n\t\t\tif ( !attrs ) {\n\t\t\t\tattrs = this._getStoredAttributes();\n\t\t\t}\n\t\t}\n\n\t\treturn attrs;\n\t}\n\n\t// Fixes the selection after all its ranges got removed.\n\t//\n\t// @private\n\t// @param {module:engine/model/position~Position} deletionPosition Position where the deletion happened.\n\t_fixGraveyardSelection( deletionPosition ) {\n\t\t// Find a range that is a correct selection range and is closest to the position where the deletion happened.\n\t\tconst selectionRange = this._model.schema.getNearestSelectionRange( deletionPosition );\n\n\t\t// If nearest valid selection range has been found - add it in the place of old range.\n\t\tif ( selectionRange ) {\n\t\t\t// Check the range, convert it to live range, bind events, etc.\n\t\t\tthis._pushRange( selectionRange );\n\t\t}\n\t\t// If nearest valid selection range cannot be found don't add any range. Selection will be set to the default range.\n\t}\n}\n\n// Helper function for {@link module:engine/model/liveselection~LiveSelection#_updateAttributes}.\n//\n// It takes model item, checks whether it is a text node (or text proxy) and, if so, returns it's attributes. If not, returns `null`.\n//\n// @param {module:engine/model/item~Item|null}  node\n// @returns {Boolean}\nfunction getAttrsIfCharacter( node ) {\n\tif ( node instanceof TextProxy || node instanceof Text ) {\n\t\treturn node.getAttributes();\n\t}\n\n\treturn null;\n}\n\n// Removes selection attributes from element which is not empty anymore.\n//\n// @param {module:engine/model/model~Model} model\n// @param {module:engine/model/batch~Batch} batch\nfunction clearAttributesStoredInElement( model, batch ) {\n\tconst differ = model.document.differ;\n\n\tfor ( const entry of differ.getChanges() ) {\n\t\tif ( entry.type != 'insert' ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst changeParent = entry.position.parent;\n\t\tconst isNoLongerEmpty = entry.length === changeParent.maxOffset;\n\n\t\tif ( isNoLongerEmpty ) {\n\t\t\tmodel.enqueueChange( batch, writer => {\n\t\t\t\tconst storedAttributes = Array.from( changeParent.getAttributeKeys() )\n\t\t\t\t\t.filter( key => key.startsWith( storePrefix ) );\n\n\t\t\t\tfor ( const key of storedAttributes ) {\n\t\t\t\t\twriter.removeAttribute( key, changeParent );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/conversion/conversionhelpers\n */\n\n/**\n * Base class for conversion helpers.\n */\nexport default class ConversionHelpers {\n\t/**\n\t * Creates a conversion helpers instance.\n\t *\n\t * @param {Array.<module:engine/conversion/downcastdispatcher~DowncastDispatcher|\n\t * module:engine/conversion/upcastdispatcher~UpcastDispatcher>} dispatchers\n\t */\n\tconstructor( dispatchers ) {\n\t\tthis._dispatchers = dispatchers;\n\t}\n\n\t/**\n\t * Registers a conversion helper.\n\t *\n\t * **Note**: See full usage example in the `{@link module:engine/conversion/conversion~Conversion#for conversion.for()}`\n\t * method description.\n\t *\n\t * @param {Function} conversionHelper The function to be called on event.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers|module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\tadd( conversionHelper ) {\n\t\tfor ( const dispatcher of this._dispatchers ) {\n\t\t\tconversionHelper( dispatcher );\n\t\t}\n\n\t\treturn this;\n\t}\n}\n","import baseClone from './_baseClone.js';\n\n/** Used to compose bitmasks for cloning. */\nvar CLONE_DEEP_FLAG = 1,\n    CLONE_SYMBOLS_FLAG = 4;\n\n/**\n * This method is like `_.clone` except that it recursively clones `value`.\n *\n * @static\n * @memberOf _\n * @since 1.0.0\n * @category Lang\n * @param {*} value The value to recursively clone.\n * @returns {*} Returns the deep cloned value.\n * @see _.clone\n * @example\n *\n * var objects = [{ 'a': 1 }, { 'b': 2 }];\n *\n * var deep = _.cloneDeep(objects);\n * console.log(deep[0] === objects[0]);\n * // => false\n */\nfunction cloneDeep(value) {\n  return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);\n}\n\nexport default cloneDeep;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * Contains downcast (model-to-view) converters for {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}.\n *\n * @module engine/conversion/downcasthelpers\n */\n\nimport ModelRange from '../model/range';\nimport ModelSelection from '../model/selection';\nimport ModelElement from '../model/element';\n\nimport ViewAttributeElement from '../view/attributeelement';\nimport DocumentSelection from '../model/documentselection';\nimport ConversionHelpers from './conversionhelpers';\n\nimport { cloneDeep } from 'lodash-es';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport toArray from '@ckeditor/ckeditor5-utils/src/toarray';\n\n/**\n * Downcast conversion helper functions.\n *\n * @extends module:engine/conversion/conversionhelpers~ConversionHelpers\n */\nexport default class DowncastHelpers extends ConversionHelpers {\n\t/**\n\t * Model element to view element conversion helper.\n\t *\n\t * This conversion results in creating a view element. For example, model `<paragraph>Foo</paragraph>` becomes `<p>Foo</p>` in the view.\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).elementToElement( {\n\t *\t\t\tmodel: 'paragraph',\n\t *\t\t\tview: 'p'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).elementToElement( {\n\t *\t\t\tmodel: 'paragraph',\n\t *\t\t\tview: 'div',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).elementToElement( {\n\t *\t\t\tmodel: 'fancyParagraph',\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'p',\n\t *\t\t\t\tclasses: 'fancy'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).elementToElement( {\n\t *\t\t\tmodel: 'heading',\n\t *\t\t\tview: ( modelElement, conversionApi ) => {\n\t *\t\t\t\tconst { writer } = conversionApi;\n\t *\n\t *\t\t\t\treturn writer.createContainerElement( 'h' + modelElement.getAttribute( 'level' ) );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * The element-to-element conversion supports the reconversion mechanism. This is helpful in the conversion to complex view structures\n\t * where multiple atomic element-to-element and attribute-to-attribute or attribute-to-element could be used. By specifying\n\t * `triggerBy()` events you can trigger reconverting the model to full view tree structures at once.\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).elementToElement( {\n\t *\t\t\tmodel: 'complex',\n\t *\t\t\tview: ( modelElement, conversionApi ) => createComplexViewFromModel( modelElement, conversionApi ),\n\t *\t\t\ttriggerBy: {\n\t *\t\t\t\tattributes: [ 'foo', 'bar' ],\n\t *\t\t\t\tchildren: [ 'slot' ]\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * You can read more about element-to-element conversion in the\n\t * {@glink framework/guides/deep-dive/conversion/custom-element-conversion Custom element conversion} guide.\n\t *\n\t * @method #elementToElement\n\t * @param {Object} config Conversion configuration.\n\t * @param {String} config.model The name of the model element to convert.\n\t * @param {module:engine/view/elementdefinition~ElementDefinition|Function} config.view A view element definition or a function\n\t * that takes the model element and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}\n\t * as parameters and returns a view container element.\n\t * @param {Object} [config.triggerBy] Reconversion triggers. At least one trigger must be defined.\n\t * @param {Array.<String>} config.triggerBy.attributes The name of the element's attributes whose change will trigger element\n\t * reconversion.\n\t * @param {Array.<String>} config.triggerBy.children The name of direct children whose adding or removing will trigger element\n\t * reconversion.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\telementToElement( config ) {\n\t\treturn this.add( downcastElementToElement( config ) );\n\t}\n\n\t/**\n\t * Model attribute to view element conversion helper.\n\t *\n\t * This conversion results in wrapping view nodes with a view attribute element. For example, a model text node with\n\t * `\"Foo\"` as data and the `bold` attribute becomes `<strong>Foo</strong>` in the view.\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tview: 'strong'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tview: 'b',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: 'invert',\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tclasses: [ 'font-light', 'bg-dark' ]\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'fontSize',\n\t *\t\t\t\tvalues: [ 'big', 'small' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\tbig: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'font-size': '1.2em'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t},\n\t *\t\t\t\tsmall: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'font-size': '0.8em'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tview: ( modelAttributeValue, conversionApi ) => {\n\t *\t\t\t\tconst { writer } = conversionApi;\n\t *\n\t *\t\t\t\treturn writer.createAttributeElement( 'span', {\n\t *\t\t\t\t\tstyle: 'font-weight:' + modelAttributeValue\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'color',\n\t *\t\t\t\tname: '$text'\n\t *\t\t\t},\n\t *\t\t\tview: ( modelAttributeValue, conversionApi ) => {\n\t *\t\t\t\tconst { writer } = conversionApi;\n\t *\n\t *\t\t\t\treturn writer.createAttributeElement( 'span', {\n\t *\t\t\t\t\tstyle: 'color:' + modelAttributeValue\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #attributeToElement\n\t * @param {Object} config Conversion configuration.\n\t * @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values }` object. `values` is an array\n\t * of `String`s with possible values if the model attribute is an enumerable.\n\t * @param {module:engine/view/elementdefinition~ElementDefinition|Function|Object} config.view A view element definition or a function\n\t * that takes the model attribute value and\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API} as parameters and returns a view\n\t * attribute element. If `config.model.values` is given, `config.view` should be an object assigning values from `config.model.values`\n\t * to view element definitions or functions.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\tattributeToElement( config ) {\n\t\treturn this.add( downcastAttributeToElement( config ) );\n\t}\n\n\t/**\n\t * Model attribute to view attribute conversion helper.\n\t *\n\t * This conversion results in adding an attribute to a view node, basing on an attribute from a model node. For example,\n\t * `<image src='foo.jpg'></image>` is converted to `<img src='foo.jpg'></img>`.\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: 'source',\n\t *\t\t\tview: 'src'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: 'source',\n\t *\t\t\tview: 'href',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tname: 'image',\n\t *\t\t\t\tkey: 'source'\n\t *\t\t\t},\n\t *\t\t\tview: 'src'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tname: 'styled',\n\t *\t\t\t\tvalues: [ 'dark', 'light' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\tdark: {\n\t *\t\t\t\t\tkey: 'class',\n\t *\t\t\t\t\tvalue: [ 'styled', 'styled-dark' ]\n\t *\t\t\t\t},\n\t *\t\t\t\tlight: {\n\t *\t\t\t\t\tkey: 'class',\n\t *\t\t\t\t\tvalue: [ 'styled', 'styled-light' ]\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: 'styled',\n\t *\t\t\tview: modelAttributeValue => ( {\n\t *\t\t\t\tkey: 'class',\n\t *\t\t\t\tvalue: 'styled-' + modelAttributeValue\n\t *\t\t\t} )\n\t *\t\t} );\n\t *\n\t * **Note**: Downcasting to a style property requires providing `value` as an object:\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: 'lineHeight',\n\t *\t\t\tview: modelAttributeValue => ( {\n\t *\t\t\t\tkey: 'style',\n\t *\t\t\t\tvalue: {\n\t *\t\t\t\t\t'line-height': modelAttributeValue,\n\t *\t\t\t\t\t'border-bottom': '1px dotted #ba2'\n\t *\t\t\t\t}\n\t *\t\t\t} )\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #attributeToAttribute\n\t * @param {Object} config Conversion configuration.\n\t * @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values, [ name ] }` object describing\n\t * the attribute key, possible values and, optionally, an element name to convert from.\n\t * @param {String|Object|Function} config.view A view attribute key, or a `{ key, value }` object or a function that takes\n\t * the model attribute value and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}\n\t * as parameters and returns a `{ key, value }` object. If `key` is `'class'`, `value` can be a `String` or an\n\t * array of `String`s. If `key` is `'style'`, `value` is an object with key-value pairs. In other cases, `value` is a `String`.\n\t * If `config.model.values` is set, `config.view` should be an object assigning values from `config.model.values` to\n\t * `{ key, value }` objects or a functions.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\tattributeToAttribute( config ) {\n\t\treturn this.add( downcastAttributeToAttribute( config ) );\n\t}\n\n\t/**\n\t * Model marker to view element conversion helper.\n\t *\n\t * **Note**: This method should be used only for editing downcast. For data downcast, use\n\t * {@link #markerToData `#markerToData()`} that produces valid HTML data.\n\t *\n\t * This conversion results in creating a view element on the boundaries of the converted marker. If the converted marker\n\t * is collapsed, only one element is created. For example, model marker set like this: `<paragraph>F[oo b]ar</paragraph>`\n\t * becomes `<p>F<span data-marker=\"search\"></span>oo b<span data-marker=\"search\"></span>ar</p>` in the view.\n\t *\n\t *\t\teditor.conversion.for( 'editingDowncast' ).markerToElement( {\n\t *\t\t\tmodel: 'search',\n\t *\t\t\tview: 'marker-search'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'editingDowncast' ).markerToElement( {\n\t *\t\t\tmodel: 'search',\n\t *\t\t\tview: 'search-result',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'editingDowncast' ).markerToElement( {\n\t *\t\t\tmodel: 'search',\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tattributes: {\n\t *\t\t\t\t\t'data-marker': 'search'\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'editingDowncast' ).markerToElement( {\n\t *\t\t\tmodel: 'search',\n\t *\t\t\tview: ( markerData, conversionApi ) => {\n\t *\t\t\t\tconst { writer } = conversionApi;\n\t *\n\t *\t\t\t\treturn writer.createUIElement( 'span', {\n\t *\t\t\t\t\t'data-marker': 'search',\n\t *\t\t\t\t\t'data-start': markerData.isOpening\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * If a function is passed as the `config.view` parameter, it will be used to generate both boundary elements. The function\n\t * receives the `data` object and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}\n\t * as a parameters and should return an instance of the\n\t * {@link module:engine/view/uielement~UIElement view UI element}. The `data` object and\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi `conversionApi`} are passed from\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}. Additionally,\n\t * the `data.isOpening` parameter is passed, which is set to `true` for the marker start boundary element, and `false` to\n\t * the marker end boundary element.\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #markerToElement\n\t * @param {Object} config Conversion configuration.\n\t * @param {String} config.model The name of the model marker (or model marker group) to convert.\n\t * @param {module:engine/view/elementdefinition~ElementDefinition|Function} config.view A view element definition or a function that\n\t * takes the model marker data and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}\n\t * as a parameters and returns a view UI element.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\tmarkerToElement( config ) {\n\t\treturn this.add( downcastMarkerToElement( config ) );\n\t}\n\n\t/**\n\t * Model marker to highlight conversion helper.\n\t *\n\t * This conversion results in creating a highlight on view nodes. For this kind of conversion,\n\t * {@link module:engine/conversion/downcasthelpers~HighlightDescriptor} should be provided.\n\t *\n\t * For text nodes, a `<span>` {@link module:engine/view/attributeelement~AttributeElement} is created and it wraps all text nodes\n\t * in the converted marker range. For example, a model marker set like this: `<paragraph>F[oo b]ar</paragraph>` becomes\n\t * `<p>F<span class=\"comment\">oo b</span>ar</p>` in the view.\n\t *\n\t * {@link module:engine/view/containerelement~ContainerElement} may provide a custom way of handling highlight. Most often,\n\t * the element itself is given classes and attributes described in the highlight descriptor (instead of being wrapped in `<span>`).\n\t * For example, a model marker set like this: `[<image src=\"foo.jpg\"></image>]` becomes `<img src=\"foo.jpg\" class=\"comment\"></img>`\n\t * in the view.\n\t *\n\t * For container elements, the conversion is two-step. While the converter processes the highlight descriptor and passes it\n\t * to a container element, it is the container element instance itself that applies values from the highlight descriptor.\n\t * So, in a sense, the converter takes care of stating what should be applied on what, while the element decides how to apply that.\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).markerToHighlight( { model: 'comment', view: { classes: 'comment' } } );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).markerToHighlight( {\n\t *\t\t\tmodel: 'comment',\n\t *\t\t\tview: { classes: 'new-comment' },\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).markerToHighlight( {\n\t *\t\t\tmodel: 'comment',\n\t *\t\t\tview: ( data, converstionApi ) => {\n\t *\t\t\t\t// Assuming that the marker name is in a form of comment:commentType.\n\t *\t\t\t\tconst commentType = data.markerName.split( ':' )[ 1 ];\n\t *\n\t *\t\t\t\treturn {\n\t *\t\t\t\t\tclasses: [ 'comment', 'comment-' + commentType ]\n\t *\t\t\t\t};\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * If a function is passed as the `config.view` parameter, it will be used to generate the highlight descriptor. The function\n\t * receives the `data` object and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}\n\t * as a parameters and should return a\n\t * {@link module:engine/conversion/downcasthelpers~HighlightDescriptor highlight descriptor}.\n\t * The `data` object properties are passed from {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}.\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #markerToHighlight\n\t * @param {Object} config Conversion configuration.\n\t * @param {String} config.model The name of the model marker (or model marker group) to convert.\n\t * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor|Function} config.view A highlight descriptor\n\t * that will be used for highlighting or a function that takes the model marker data and\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API} as a parameters\n\t * and returns a highlight descriptor.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\tmarkerToHighlight( config ) {\n\t\treturn this.add( downcastMarkerToHighlight( config ) );\n\t}\n\n\t/**\n\t * Model marker converter for data downcast.\n\t *\n\t * This conversion creates a representation for model marker boundaries in the view:\n\t *\n\t * * If the marker boundary is at a position where text nodes are allowed, then a view element with the specified tag name\n\t * and `name` attribute is added at this position.\n\t * * In other cases, a specified attribute is set on a view element that is before or after the marker boundary.\n\t *\n\t * Typically, marker names use the `group:uniqueId:otherData` convention. For example: `comment:e34zfk9k2n459df53sjl34:zx32c`.\n\t * The default configuration for this conversion is that the first part is the `group` part and the rest of\n\t * the marker name becomes the `name` part.\n\t *\n\t * Tag and attribute names and values are generated from the marker name:\n\t *\n\t * * Templates for attributes are `data-[group]-start-before=\"[name]\"`, `data-[group]-start-after=\"[name]\"`,\n\t * `data-[group]-end-before=\"[name]\"` and `data-[group]-end-after=\"[name]\"`.\n\t * * Templates for view elements are `<[group]-start name=\"[name]\">` and `<[group]-end name=\"[name]\">`.\n\t *\n\t * Attributes mark whether the given marker's start or end boundary is before or after the given element.\n\t * Attributes `data-[group]-start-before` and `data-[group]-end-after` are favored.\n\t * The other two are used when the former two cannot be used.\n\t *\n\t * The conversion configuration can take a function that will generate different group and name parts.\n\t * If such function is set as the `config.view` parameter, it is passed a marker name and it is expected to return an object with two\n\t * properties: `group` and `name`. If the function returns a falsy value, the conversion will not take place.\n\t *\n\t * Basic usage:\n\t *\n\t *\t\t// Using the default conversion.\n\t *\t\t// In this case, all markers whose name starts with 'comment:' will be converted.\n\t *\t\t// The `group` parameter will be set to `comment`.\n\t *\t\t// The `name` parameter will be the rest of the marker name (without `:`).\n\t *\t\teditor.conversion.for( 'dataDowncast' ).markerToData( {\n\t *\t\t\tmodel: 'comment'\n\t *\t\t} );\n\t *\n\t * An example of a view that may be generated by this conversion (assuming a marker with the name `comment:commentId:uid` marked\n\t * by `[]`):\n\t *\n\t *\t\t// Model:\n\t *\t\t<paragraph>Foo[bar</paragraph>\n\t *\t\t<image src=\"abc.jpg\"></image>]\n\t *\n\t *\t\t// View:\n\t *\t\t<p>Foo<comment-start name=\"commentId:uid\"></comment-start>bar</p>\n\t *\t\t<figure data-comment-end-after=\"commentId:uid\" class=\"image\"><img src=\"abc.jpg\" /></figure>\n\t *\n\t * In the example above, the comment starts before \"bar\" and ends after the image.\n\t *\n\t * If the `name` part is empty, the following view may be generated:\n\t *\n\t *\t\t<p>Foo <myMarker-start></myMarker-start>bar</p>\n\t *\t\t<figure data-myMarker-end-after=\"\" class=\"image\"><img src=\"abc.jpg\" /></figure>\n\t *\n\t * **Note:** A situation where some markers have the `name` part and some do not have it is incorrect and should be avoided.\n\t *\n\t * Examples where `data-group-start-after` and `data-group-end-before` are used:\n\t *\n\t *\t\t// Model:\n\t *\t\t<blockQuote>[]<paragraph>Foo</paragraph></blockQuote>\n\t *\n\t * \t\t// View:\n\t *\t\t<blockquote><p data-group-end-before=\"name\" data-group-start-before=\"name\">Foo</p></blockquote>\n\t *\n\t * Similarly, when a marker is collapsed after the last element:\n\t *\n\t *\t\t// Model:\n\t *\t\t<blockQuote><paragraph>Foo</paragraph>[]</blockQuote>\n\t *\n\t *\t\t// View:\n\t *\t\t<blockquote><p data-group-end-after=\"name\" data-group-start-after=\"name\">Foo</p></blockquote>\n\t *\n\t * When there are multiple markers from the same group stored in the same attribute of the same element, their\n\t * name parts are put together in the attribute value, for example: `data-group-start-before=\"name1,name2,name3\"`.\n\t *\n\t * Other examples of usage:\n\t *\n\t *\t\t// Using a custom function which is the same as the default conversion:\n\t *\t\teditor.conversion.for( 'dataDowncast' ).markerToData( {\n\t *\t\t\tmodel: 'comment'\n\t *\t\t\tview: markerName => ( {\n\t *\t\t\t\tgroup: 'comment',\n\t *\t\t\t\tname: markerName.substr( 8 ) // Removes 'comment:' part.\n\t *\t\t\t} )\n\t *\t\t} );\n\t *\n\t *\t\t// Using the converter priority:\n\t *\t\teditor.conversion.for( 'dataDowncast' ).markerToData( {\n\t *\t\t\tmodel: 'comment'\n\t *\t\t\tview: markerName => ( {\n\t *\t\t\t\tgroup: 'comment',\n\t *\t\t\t\tname: markerName.substr( 8 ) // Removes 'comment:' part.\n\t *\t\t\t} ),\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t * This kind of conversion is useful for saving data into the database, so it should be used in the data conversion pipeline.\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #markerToData\n\t * @param {Object} config Conversion configuration.\n\t * @param {String} config.model The name of the model marker (or model marker group) to convert.\n\t * @param {Function} [config.view] A function that takes the model marker name and\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API} as a parameters\n\t * and returns an object with the `group` and `name` properties.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\tmarkerToData( config ) {\n\t\treturn this.add( downcastMarkerToData( config ) );\n\t}\n}\n\n/**\n * Function factory that creates a default downcast converter for text insertion changes.\n *\n * The converter automatically consumes the corresponding value from the consumables list and stops the event (see\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}).\n *\n *\t\tmodelDispatcher.on( 'insert:$text', insertText() );\n *\n * @returns {Function} Insert text event converter.\n */\nexport function insertText() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !conversionApi.consumable.consume( data.item, 'insert' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst viewPosition = conversionApi.mapper.toViewPosition( data.range.start );\n\t\tconst viewText = viewWriter.createText( data.item.data );\n\n\t\tviewWriter.insert( viewPosition, viewText );\n\t};\n}\n\n/**\n * Function factory that creates a default downcast converter for node remove changes.\n *\n *\t\tmodelDispatcher.on( 'remove', remove() );\n *\n * @returns {Function} Remove event converter.\n */\nexport function remove() {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// Find view range start position by mapping model position at which the remove happened.\n\t\tconst viewStart = conversionApi.mapper.toViewPosition( data.position );\n\n\t\tconst modelEnd = data.position.getShiftedBy( data.length );\n\t\tconst viewEnd = conversionApi.mapper.toViewPosition( modelEnd, { isPhantom: true } );\n\n\t\tconst viewRange = conversionApi.writer.createRange( viewStart, viewEnd );\n\n\t\t// Trim the range to remove in case some UI elements are on the view range boundaries.\n\t\tconst removed = conversionApi.writer.remove( viewRange.getTrimmed() );\n\n\t\t// After the range is removed, unbind all view elements from the model.\n\t\t// Range inside view document fragment is used to unbind deeply.\n\t\tfor ( const child of conversionApi.writer.createRangeIn( removed ).getItems() ) {\n\t\t\tconversionApi.mapper.unbindViewElement( child );\n\t\t}\n\t};\n}\n\n/**\n * Creates a `<span>` {@link module:engine/view/attributeelement~AttributeElement view attribute element} from the information\n * provided by the {@link module:engine/conversion/downcasthelpers~HighlightDescriptor highlight descriptor} object. If a priority\n * is not provided in the descriptor, the default priority will be used.\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} descriptor\n * @returns {module:engine/view/attributeelement~AttributeElement}\n */\nexport function createViewElementFromHighlightDescriptor( writer, descriptor ) {\n\tconst viewElement = writer.createAttributeElement( 'span', descriptor.attributes );\n\n\tif ( descriptor.classes ) {\n\t\tviewElement._addClass( descriptor.classes );\n\t}\n\n\tif ( descriptor.priority ) {\n\t\tviewElement._priority = descriptor.priority;\n\t}\n\n\tviewElement._id = descriptor.id;\n\n\treturn viewElement;\n}\n\n/**\n * Function factory that creates a converter which converts a non-collapsed {@link module:engine/model/selection~Selection model selection}\n * to a {@link module:engine/view/documentselection~DocumentSelection view selection}. The converter consumes appropriate\n * value from the `consumable` object and maps model positions from the selection to view positions.\n *\n *\t\tmodelDispatcher.on( 'selection', convertRangeSelection() );\n *\n * @returns {Function} Selection converter.\n */\nexport function convertRangeSelection() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst selection = data.selection;\n\n\t\tif ( selection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( selection, 'selection' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewRanges = [];\n\n\t\tfor ( const range of selection.getRanges() ) {\n\t\t\tconst viewRange = conversionApi.mapper.toViewRange( range );\n\t\t\tviewRanges.push( viewRange );\n\t\t}\n\n\t\tconversionApi.writer.setSelection( viewRanges, { backward: selection.isBackward } );\n\t};\n}\n\n/**\n * Function factory that creates a converter which converts a collapsed {@link module:engine/model/selection~Selection model selection} to\n * a {@link module:engine/view/documentselection~DocumentSelection view selection}. The converter consumes appropriate\n * value from the `consumable` object, maps the model selection position to the view position and breaks\n * {@link module:engine/view/attributeelement~AttributeElement attribute elements} at the selection position.\n *\n *\t\tmodelDispatcher.on( 'selection', convertCollapsedSelection() );\n *\n * An example of the view state before and after converting the collapsed selection:\n *\n *\t\t   <p><strong>f^oo<strong>bar</p>\n *\t\t-> <p><strong>f</strong>^<strong>oo</strong>bar</p>\n *\n * By breaking attribute elements like `<strong>`, the selection is in a correct element. Then, when the selection attribute is\n * converted, broken attributes might be merged again, or the position where the selection is may be wrapped\n * with different, appropriate attribute elements.\n *\n * See also {@link module:engine/conversion/downcasthelpers~clearAttributes} which does a clean-up\n * by merging attributes.\n *\n * @returns {Function} Selection converter.\n */\nexport function convertCollapsedSelection() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst selection = data.selection;\n\n\t\tif ( !selection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( selection, 'selection' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst modelPosition = selection.getFirstPosition();\n\t\tconst viewPosition = conversionApi.mapper.toViewPosition( modelPosition );\n\t\tconst brokenPosition = viewWriter.breakAttributes( viewPosition );\n\n\t\tviewWriter.setSelection( brokenPosition );\n\t};\n}\n\n/**\n * Function factory that creates a converter which clears artifacts after the previous\n * {@link module:engine/model/selection~Selection model selection} conversion. It removes all empty\n * {@link module:engine/view/attributeelement~AttributeElement view attribute elements} and merges sibling attributes at all start and end\n * positions of all ranges.\n *\n *\t\t   <p><strong>^</strong></p>\n *\t\t-> <p>^</p>\n *\n *\t\t   <p><strong>foo</strong>^<strong>bar</strong>bar</p>\n *\t\t-> <p><strong>foo^bar<strong>bar</p>\n *\n *\t\t   <p><strong>foo</strong><em>^</em><strong>bar</strong>bar</p>\n *\t\t-> <p><strong>foo^bar<strong>bar</p>\n *\n * This listener should be assigned before any converter for the new selection:\n *\n *\t\tmodelDispatcher.on( 'selection', clearAttributes() );\n *\n * See {@link module:engine/conversion/downcasthelpers~convertCollapsedSelection}\n * which does the opposite by breaking attributes in the selection position.\n *\n * @returns {Function} Selection converter.\n */\nexport function clearAttributes() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst viewSelection = viewWriter.document.selection;\n\n\t\tfor ( const range of viewSelection.getRanges() ) {\n\t\t\t// Not collapsed selection should not have artifacts.\n\t\t\tif ( range.isCollapsed ) {\n\t\t\t\t// Position might be in the node removed by the view writer.\n\t\t\t\tif ( range.end.parent.isAttached() ) {\n\t\t\t\t\tconversionApi.writer.mergeAttributes( range.start );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tviewWriter.setSelection( null );\n\t};\n}\n\n/**\n * Function factory that creates a converter which converts set/change/remove attribute changes from the model to the view.\n * It can also be used to convert selection attributes. In that case, an empty attribute element will be created and the\n * selection will be put inside it.\n *\n * Attributes from the model are converted to a view element that will be wrapping these view nodes that are bound to\n * model elements having the given attribute. This is useful for attributes like `bold` that may be set on text nodes in the model\n * but are represented as an element in the view:\n *\n *\t\t[paragraph]              MODEL ====> VIEW        <p>\n *\t\t\t|- a {bold: true}                             |- <b>\n *\t\t\t|- b {bold: true}                             |   |- ab\n *\t\t\t|- c                                          |- c\n *\n * Passed `Function` will be provided with the attribute value and then all the parameters of the\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute `attribute` event}.\n * It is expected that the function returns an {@link module:engine/view/element~Element}.\n * The result of the function will be the wrapping element.\n * When the provided `Function` does not return any element, no conversion will take place.\n *\n * The converter automatically consumes the corresponding value from the consumables list and stops the event (see\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}).\n *\n *\t\tmodelDispatcher.on( 'attribute:bold', wrap( ( modelAttributeValue, { writer } ) => {\n *\t\t\treturn writer.createAttributeElement( 'strong' );\n *\t\t} );\n *\n * @protected\n * @param {Function} elementCreator Function returning a view element that will be used for wrapping.\n * @returns {Function} Set/change attribute converter.\n */\nexport function wrap( elementCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// Recreate current wrapping node. It will be used to unwrap view range if the attribute value has changed\n\t\t// or the attribute was removed.\n\t\tconst oldViewElement = elementCreator( data.attributeOldValue, conversionApi );\n\n\t\t// Create node to wrap with.\n\t\tconst newViewElement = elementCreator( data.attributeNewValue, conversionApi );\n\n\t\tif ( !oldViewElement && !newViewElement ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst viewSelection = viewWriter.document.selection;\n\n\t\tif ( data.item instanceof ModelSelection || data.item instanceof DocumentSelection ) {\n\t\t\t// Selection attribute conversion.\n\t\t\tviewWriter.wrap( viewSelection.getFirstRange(), newViewElement );\n\t\t} else {\n\t\t\t// Node attribute conversion.\n\t\t\tlet viewRange = conversionApi.mapper.toViewRange( data.range );\n\n\t\t\t// First, unwrap the range from current wrapper.\n\t\t\tif ( data.attributeOldValue !== null && oldViewElement ) {\n\t\t\t\tviewRange = viewWriter.unwrap( viewRange, oldViewElement );\n\t\t\t}\n\n\t\t\tif ( data.attributeNewValue !== null && newViewElement ) {\n\t\t\t\tviewWriter.wrap( viewRange, newViewElement );\n\t\t\t}\n\t\t}\n\t};\n}\n\n/**\n * Function factory that creates a converter which converts node insertion changes from the model to the view.\n * The function passed will be provided with all the parameters of the dispatcher's\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert `insert` event}.\n * It is expected that the function returns an {@link module:engine/view/element~Element}.\n * The result of the function will be inserted into the view.\n *\n * The converter automatically consumes the corresponding value from the consumables list, stops the event (see\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}) and binds the model and view elements.\n *\n *\t\tdowncastDispatcher.on(\n *\t\t\t'insert:myElem',\n *\t\t\tinsertElement( ( modelItem, { writer } ) => {\n *\t\t\t\tconst text = writer.createText( 'myText' );\n *\t\t\t\tconst myElem = writer.createElement( 'myElem', { myAttr: 'my-' + modelItem.getAttribute( 'myAttr' ) }, text );\n *\n *\t\t\t\t// Do something fancy with `myElem` using `modelItem` or other parameters.\n *\n *\t\t\t\treturn myElem;\n *\t\t\t}\n *\t\t) );\n *\n * @protected\n * @param {Function} elementCreator Function returning a view element, which will be inserted.\n * @returns {Function} Insert element event converter.\n */\nexport function insertElement( elementCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst viewElement = elementCreator( data.item, conversionApi );\n\n\t\tif ( !viewElement ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( data.item, 'insert' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewPosition = conversionApi.mapper.toViewPosition( data.range.start );\n\n\t\tconversionApi.mapper.bindElements( data.item, viewElement );\n\t\tconversionApi.writer.insert( viewPosition, viewElement );\n\t};\n}\n\n/**\n * Function factory that creates a converter which converts marker adding change to the\n * {@link module:engine/view/uielement~UIElement view UI element}.\n *\n * The view UI element that will be added to the view depends on the passed parameter. See {@link ~insertElement}.\n * In case of a non-collapsed range, the UI element will not wrap nodes but separate elements will be placed at the beginning\n * and at the end of the range.\n *\n * This converter binds created UI elements with the marker name using {@link module:engine/conversion/mapper~Mapper#bindElementToMarker}.\n *\n * @protected\n * @param {module:engine/view/uielement~UIElement|Function} elementCreator A view UI element or a function returning the view element\n * that will be inserted.\n * @returns {Function} Insert element event converter.\n */\nexport function insertUIElement( elementCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// Create two view elements. One will be inserted at the beginning of marker, one at the end.\n\t\t// If marker is collapsed, only \"opening\" element will be inserted.\n\t\tdata.isOpening = true;\n\t\tconst viewStartElement = elementCreator( data, conversionApi );\n\n\t\tdata.isOpening = false;\n\t\tconst viewEndElement = elementCreator( data, conversionApi );\n\n\t\tif ( !viewStartElement || !viewEndElement ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst markerRange = data.markerRange;\n\n\t\t// Marker that is collapsed has consumable build differently that non-collapsed one.\n\t\t// For more information see `addMarker` event description.\n\t\t// If marker's range is collapsed - check if it can be consumed.\n\t\tif ( markerRange.isCollapsed && !conversionApi.consumable.consume( markerRange, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If marker's range is not collapsed - consume all items inside.\n\t\tfor ( const value of markerRange ) {\n\t\t\tif ( !conversionApi.consumable.consume( value.item, evt.name ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tconst mapper = conversionApi.mapper;\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\t// Add \"opening\" element.\n\t\tviewWriter.insert( mapper.toViewPosition( markerRange.start ), viewStartElement );\n\t\tconversionApi.mapper.bindElementToMarker( viewStartElement, data.markerName );\n\n\t\t// Add \"closing\" element only if range is not collapsed.\n\t\tif ( !markerRange.isCollapsed ) {\n\t\t\tviewWriter.insert( mapper.toViewPosition( markerRange.end ), viewEndElement );\n\t\t\tconversionApi.mapper.bindElementToMarker( viewEndElement, data.markerName );\n\t\t}\n\n\t\tevt.stop();\n\t};\n}\n\n// Function factory that returns a default downcast converter for removing a {@link module:engine/view/uielement~UIElement UI element}\n// based on marker remove change.\n//\n// This converter unbinds elements from the marker name.\n//\n// @returns {Function} Removed UI element converter.\nfunction removeUIElement() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst elements = conversionApi.mapper.markerNameToElements( data.markerName );\n\n\t\tif ( !elements ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const element of elements ) {\n\t\t\tconversionApi.mapper.unbindElementFromMarkerName( element, data.markerName );\n\t\t\tconversionApi.writer.clear( conversionApi.writer.createRangeOn( element ), element );\n\t\t}\n\n\t\tconversionApi.writer.clearClonedElementsGroup( data.markerName );\n\n\t\tevt.stop();\n\t};\n}\n\n// Function factory that creates a default converter for model markers.\n//\n// See {@link DowncastHelpers#markerToData} for more information what type of view is generated.\n//\n// This converter binds created UI elements and affected view elements with the marker name\n// using {@link module:engine/conversion/mapper~Mapper#bindElementToMarker}.\n//\n// @returns {Function} Add marker converter.\nfunction insertMarkerData( viewCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst viewMarkerData = viewCreator( data.markerName, conversionApi );\n\n\t\tif ( !viewMarkerData ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst markerRange = data.markerRange;\n\n\t\tif ( !conversionApi.consumable.consume( markerRange, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Adding closing data first to keep the proper order in the view.\n\t\thandleMarkerBoundary( markerRange, false, conversionApi, data, viewMarkerData );\n\t\thandleMarkerBoundary( markerRange, true, conversionApi, data, viewMarkerData );\n\n\t\tevt.stop();\n\t};\n}\n\n// Helper function for `insertMarkerData()` that marks a marker boundary at the beginning or end of given `range`.\nfunction handleMarkerBoundary( range, isStart, conversionApi, data, viewMarkerData ) {\n\tconst modelPosition = isStart ? range.start : range.end;\n\tconst canInsertElement = conversionApi.schema.checkChild( modelPosition, '$text' );\n\n\tif ( canInsertElement ) {\n\t\tconst viewPosition = conversionApi.mapper.toViewPosition( modelPosition );\n\n\t\tinsertMarkerAsElement( viewPosition, isStart, conversionApi, data, viewMarkerData );\n\t} else {\n\t\tlet modelElement;\n\t\tlet isBefore;\n\n\t\t// If possible, we want to add `data-group-start-before` and `data-group-end-after` attributes.\n\t\t// Below `if` is constructed in a way that will favor adding these attributes.\n\t\t//\n\t\t// Also, I assume that there will be always an element either after or before the position.\n\t\t// If not, then it is a case when we are not in a position where text is allowed and also there are no elements around...\n\t\tif ( isStart && modelPosition.nodeAfter || !isStart && !modelPosition.nodeBefore ) {\n\t\t\tmodelElement = modelPosition.nodeAfter;\n\t\t\tisBefore = true;\n\t\t} else {\n\t\t\tmodelElement = modelPosition.nodeBefore;\n\t\t\tisBefore = false;\n\t\t}\n\n\t\tconst viewElement = conversionApi.mapper.toViewElement( modelElement );\n\n\t\tinsertMarkerAsAttribute( viewElement, isStart, isBefore, conversionApi, data, viewMarkerData );\n\t}\n}\n\n// Helper function for `insertMarkerData()` that marks a marker boundary in the view as an attribute on a view element.\nfunction insertMarkerAsAttribute( viewElement, isStart, isBefore, conversionApi, data, viewMarkerData ) {\n\tconst attributeName = `data-${ viewMarkerData.group }-${ isStart ? 'start' : 'end' }-${ isBefore ? 'before' : 'after' }`;\n\n\tconst markerNames = viewElement.hasAttribute( attributeName ) ? viewElement.getAttribute( attributeName ).split( ',' ) : [];\n\n\t// Adding marker name at the beginning to have the same order in the attribute as there is with marker elements.\n\tmarkerNames.unshift( viewMarkerData.name );\n\n\tconversionApi.writer.setAttribute( attributeName, markerNames.join( ',' ), viewElement );\n\tconversionApi.mapper.bindElementToMarker( viewElement, data.markerName );\n}\n\n// Helper function for `insertMarkerData()` that marks a marker boundary in the view as a separate view ui element.\nfunction insertMarkerAsElement( position, isStart, conversionApi, data, viewMarkerData ) {\n\tconst viewElementName = `${ viewMarkerData.group }-${ isStart ? 'start' : 'end' }`;\n\n\tconst attrs = viewMarkerData.name ? { 'name': viewMarkerData.name } : null;\n\tconst viewElement = conversionApi.writer.createUIElement( viewElementName, attrs );\n\n\tconversionApi.writer.insert( position, viewElement );\n\tconversionApi.mapper.bindElementToMarker( viewElement, data.markerName );\n}\n\n// Function factory that creates a converter for removing a model marker data added by the {@link #insertMarkerData} converter.\n//\n// @returns {Function} Remove marker converter.\nfunction removeMarkerData( viewCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst viewData = viewCreator( data.markerName, conversionApi );\n\n\t\tif ( !viewData ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst elements = conversionApi.mapper.markerNameToElements( data.markerName );\n\n\t\tif ( !elements ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const element of elements ) {\n\t\t\tconversionApi.mapper.unbindElementFromMarkerName( element, data.markerName );\n\n\t\t\tif ( element.is( 'containerElement' ) ) {\n\t\t\t\tremoveMarkerFromAttribute( `data-${ viewData.group }-start-before`, element );\n\t\t\t\tremoveMarkerFromAttribute( `data-${ viewData.group }-start-after`, element );\n\t\t\t\tremoveMarkerFromAttribute( `data-${ viewData.group }-end-before`, element );\n\t\t\t\tremoveMarkerFromAttribute( `data-${ viewData.group }-end-after`, element );\n\t\t\t} else {\n\t\t\t\tconversionApi.writer.clear( conversionApi.writer.createRangeOn( element ), element );\n\t\t\t}\n\t\t}\n\n\t\tconversionApi.writer.clearClonedElementsGroup( data.markerName );\n\n\t\tevt.stop();\n\n\t\tfunction removeMarkerFromAttribute( attributeName, element ) {\n\t\t\tif ( element.hasAttribute( attributeName ) ) {\n\t\t\t\tconst markerNames = new Set( element.getAttribute( attributeName ).split( ',' ) );\n\t\t\t\tmarkerNames.delete( viewData.name );\n\n\t\t\t\tif ( markerNames.size == 0 ) {\n\t\t\t\t\tconversionApi.writer.removeAttribute( attributeName, element );\n\t\t\t\t} else {\n\t\t\t\t\tconversionApi.writer.setAttribute( attributeName, Array.from( markerNames ).join( ',' ), element );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Function factory that creates a converter which converts set/change/remove attribute changes from the model to the view.\n//\n// Attributes from the model are converted to the view element attributes in the view. You may provide a custom function to generate\n// a key-value attribute pair to add/change/remove. If not provided, model attributes will be converted to view element\n// attributes on a one-to-one basis.\n//\n// *Note:** The provided attribute creator should always return the same `key` for a given attribute from the model.\n//\n// The converter automatically consumes the corresponding value from the consumables list and stops the event (see\n// {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}).\n//\n//\t\tmodelDispatcher.on( 'attribute:customAttr:myElem', changeAttribute( ( value, data ) => {\n//\t\t\t// Change attribute key from `customAttr` to `class` in the view.\n//\t\t\tconst key = 'class';\n//\t\t\tlet value = data.attributeNewValue;\n//\n//\t\t\t// Force attribute value to 'empty' if the model element is empty.\n//\t\t\tif ( data.item.childCount === 0 ) {\n//\t\t\t\tvalue = 'empty';\n//\t\t\t}\n//\n//\t\t\t// Return the key-value pair.\n//\t\t\treturn { key, value };\n//\t\t} ) );\n//\n// @param {Function} [attributeCreator] Function returning an object with two properties: `key` and `value`, which\n// represent the attribute key and attribute value to be set on a {@link module:engine/view/element~Element view element}.\n// The function is passed the model attribute value as the first parameter and additional data about the change as the second parameter.\n// @returns {Function} Set/change attribute converter.\nfunction changeAttribute( attributeCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst oldAttribute = attributeCreator( data.attributeOldValue, conversionApi );\n\t\tconst newAttribute = attributeCreator( data.attributeNewValue, conversionApi );\n\n\t\tif ( !oldAttribute && !newAttribute ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewElement = conversionApi.mapper.toViewElement( data.item );\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\t// If model item cannot be mapped to a view element, it means item is not an `Element` instance but a `TextProxy` node.\n\t\t// Only elements can have attributes in a view so do not proceed for anything else (#1587).\n\t\tif ( !viewElement ) {\n\t\t\t/**\n\t\t\t * This error occurs when a {@link module:engine/model/textproxy~TextProxy text node's} attribute is to be downcasted\n\t\t\t * by {@link module:engine/conversion/conversion~Conversion#attributeToAttribute `Attribute to Attribute converter`}.\n\t\t\t * In most cases it is caused by converters misconfiguration when only \"generic\" converter is defined:\n\t\t\t *\n\t\t\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t\t\t *\t\t\tmodel: 'attribute-name',\n\t\t\t *\t\t\tview: 'attribute-name'\n\t\t\t *\t\t} ) );\n\t\t\t *\n\t\t\t * and given attribute is used on text node, for example:\n\t\t\t *\n\t\t\t *\t\tmodel.change( writer => {\n\t\t\t *\t\t\twriter.insertText( 'Foo', { 'attribute-name': 'bar' }, parent, 0 );\n\t\t\t *\t\t} );\n\t\t\t *\n\t\t\t * In such cases, to convert the same attribute for both {@link module:engine/model/element~Element}\n\t\t\t * and {@link module:engine/model/textproxy~TextProxy `Text`} nodes, text specific\n\t\t\t * {@link module:engine/conversion/conversion~Conversion#attributeToElement `Attribute to Element converter`}\n\t\t\t * with higher {@link module:utils/priorities~PriorityString priority} must also be defined:\n\t\t\t *\n\t\t\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t\t\t *\t\t\tmodel: {\n\t\t\t *\t\t\t\tkey: 'attribute-name',\n\t\t\t *\t\t\t\tname: '$text'\n\t\t\t *\t\t\t},\n\t\t\t *\t\t\tview: ( value, { writer } ) => {\n\t\t\t *\t\t\t\treturn writer.createAttributeElement( 'span', { 'attribute-name': value } );\n\t\t\t *\t\t\t},\n\t\t\t *\t\t\tconverterPriority: 'high'\n\t\t\t *\t\t} ) );\n\t\t\t *\n\t\t\t * @error conversion-attribute-to-attribute-on-text\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'conversion-attribute-to-attribute-on-text',\n\t\t\t\t[ data, conversionApi ]\n\t\t\t);\n\t\t}\n\n\t\t// First remove the old attribute if there was one.\n\t\tif ( data.attributeOldValue !== null && oldAttribute ) {\n\t\t\tif ( oldAttribute.key == 'class' ) {\n\t\t\t\tconst classes = toArray( oldAttribute.value );\n\n\t\t\t\tfor ( const className of classes ) {\n\t\t\t\t\tviewWriter.removeClass( className, viewElement );\n\t\t\t\t}\n\t\t\t} else if ( oldAttribute.key == 'style' ) {\n\t\t\t\tconst keys = Object.keys( oldAttribute.value );\n\n\t\t\t\tfor ( const key of keys ) {\n\t\t\t\t\tviewWriter.removeStyle( key, viewElement );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tviewWriter.removeAttribute( oldAttribute.key, viewElement );\n\t\t\t}\n\t\t}\n\n\t\t// Then set the new attribute.\n\t\tif ( data.attributeNewValue !== null && newAttribute ) {\n\t\t\tif ( newAttribute.key == 'class' ) {\n\t\t\t\tconst classes = toArray( newAttribute.value );\n\n\t\t\t\tfor ( const className of classes ) {\n\t\t\t\t\tviewWriter.addClass( className, viewElement );\n\t\t\t\t}\n\t\t\t} else if ( newAttribute.key == 'style' ) {\n\t\t\t\tconst keys = Object.keys( newAttribute.value );\n\n\t\t\t\tfor ( const key of keys ) {\n\t\t\t\t\tviewWriter.setStyle( key, newAttribute.value[ key ], viewElement );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tviewWriter.setAttribute( newAttribute.key, newAttribute.value, viewElement );\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Function factory that creates a converter which converts the text inside marker's range. The converter wraps the text with\n// {@link module:engine/view/attributeelement~AttributeElement} created from the provided descriptor.\n// See {link module:engine/conversion/downcasthelpers~createViewElementFromHighlightDescriptor}.\n//\n// It can also be used to convert the selection that is inside a marker. In that case, an empty attribute element will be\n// created and the selection will be put inside it.\n//\n// If the highlight descriptor does not provide the `priority` property, `10` will be used.\n//\n// If the highlight descriptor does not provide the `id` property, the name of the marker will be used.\n//\n// This converter binds the created {@link module:engine/view/attributeelement~AttributeElement attribute elemens} with the marker name\n// using the {@link module:engine/conversion/mapper~Mapper#bindElementToMarker} method.\n//\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor|Function} highlightDescriptor\n// @returns {Function}\nfunction highlightText( highlightDescriptor ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !data.item ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !( data.item instanceof ModelSelection || data.item instanceof DocumentSelection ) && !data.item.is( '$textProxy' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst descriptor = prepareDescriptor( highlightDescriptor, data, conversionApi );\n\n\t\tif ( !descriptor ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst viewElement = createViewElementFromHighlightDescriptor( viewWriter, descriptor );\n\t\tconst viewSelection = viewWriter.document.selection;\n\n\t\tif ( data.item instanceof ModelSelection || data.item instanceof DocumentSelection ) {\n\t\t\tviewWriter.wrap( viewSelection.getFirstRange(), viewElement, viewSelection );\n\t\t} else {\n\t\t\tconst viewRange = conversionApi.mapper.toViewRange( data.range );\n\t\t\tconst rangeAfterWrap = viewWriter.wrap( viewRange, viewElement );\n\n\t\t\tfor ( const element of rangeAfterWrap.getItems() ) {\n\t\t\t\tif ( element.is( 'attributeElement' ) && element.isSimilar( viewElement ) ) {\n\t\t\t\t\tconversionApi.mapper.bindElementToMarker( element, data.markerName );\n\n\t\t\t\t\t// One attribute element is enough, because all of them are bound together by the view writer.\n\t\t\t\t\t// Mapper uses this binding to get all the elements no matter how many of them are registered in the mapper.\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Converter function factory. It creates a function which applies the marker's highlight to an element inside the marker's range.\n//\n// The converter checks if an element has the `addHighlight` function stored as a\n// {@link module:engine/view/element~Element#_setCustomProperty custom property} and, if so, uses it to apply the highlight.\n// In such case the converter will consume all element's children, assuming that they were handled by the element itself.\n//\n// When the `addHighlight` custom property is not present, the element is not converted in any special way.\n// This means that converters will proceed to convert the element's child nodes.\n//\n// If the highlight descriptor does not provide the `priority` property, `10` will be used.\n//\n// If the highlight descriptor does not provide the `id` property, the name of the marker will be used.\n//\n// This converter binds altered {@link module:engine/view/containerelement~ContainerElement container elements} with the marker name using\n// the {@link module:engine/conversion/mapper~Mapper#bindElementToMarker} method.\n//\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor|Function} highlightDescriptor\n// @returns {Function}\nfunction highlightElement( highlightDescriptor ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !data.item ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !( data.item instanceof ModelElement ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst descriptor = prepareDescriptor( highlightDescriptor, data, conversionApi );\n\n\t\tif ( !descriptor ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.test( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewElement = conversionApi.mapper.toViewElement( data.item );\n\n\t\tif ( viewElement && viewElement.getCustomProperty( 'addHighlight' ) ) {\n\t\t\t// Consume element itself.\n\t\t\tconversionApi.consumable.consume( data.item, evt.name );\n\n\t\t\t// Consume all children nodes.\n\t\t\tfor ( const value of ModelRange._createIn( data.item ) ) {\n\t\t\t\tconversionApi.consumable.consume( value.item, evt.name );\n\t\t\t}\n\n\t\t\tviewElement.getCustomProperty( 'addHighlight' )( viewElement, descriptor, conversionApi.writer );\n\n\t\t\tconversionApi.mapper.bindElementToMarker( viewElement, data.markerName );\n\t\t}\n\t};\n}\n\n// Function factory that creates a converter which converts the removing model marker to the view.\n//\n// Both text nodes and elements are handled by this converter but they are handled a bit differently.\n//\n// Text nodes are unwrapped using the {@link module:engine/view/attributeelement~AttributeElement attribute element} created from the\n// provided highlight descriptor. See {link module:engine/conversion/downcasthelpers~HighlightDescriptor}.\n//\n// For elements, the converter checks if an element has the `removeHighlight` function stored as a\n// {@link module:engine/view/element~Element#_setCustomProperty custom property}. If so, it uses it to remove the highlight.\n// In such case, the children of that element will not be converted.\n//\n// When `removeHighlight` is not present, the element is not converted in any special way.\n// The converter will proceed to convert the element's child nodes instead.\n//\n// If the highlight descriptor does not provide the `priority` property, `10` will be used.\n//\n// If the highlight descriptor does not provide the `id` property, the name of the marker will be used.\n//\n// This converter unbinds elements from the marker name.\n//\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor|Function} highlightDescriptor\n// @returns {Function}\nfunction removeHighlight( highlightDescriptor ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// This conversion makes sense only for non-collapsed range.\n\t\tif ( data.markerRange.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst descriptor = prepareDescriptor( highlightDescriptor, data, conversionApi );\n\n\t\tif ( !descriptor ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// View element that will be used to unwrap `AttributeElement`s.\n\t\tconst viewHighlightElement = createViewElementFromHighlightDescriptor( conversionApi.writer, descriptor );\n\n\t\t// Get all elements bound with given marker name.\n\t\tconst elements = conversionApi.mapper.markerNameToElements( data.markerName );\n\n\t\tif ( !elements ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const element of elements ) {\n\t\t\tconversionApi.mapper.unbindElementFromMarkerName( element, data.markerName );\n\n\t\t\tif ( element.is( 'attributeElement' ) ) {\n\t\t\t\tconversionApi.writer.unwrap( conversionApi.writer.createRangeOn( element ), viewHighlightElement );\n\t\t\t} else {\n\t\t\t\t// if element.is( 'containerElement' ).\n\t\t\t\telement.getCustomProperty( 'removeHighlight' )( element, descriptor.id, conversionApi.writer );\n\t\t\t}\n\t\t}\n\n\t\tconversionApi.writer.clearClonedElementsGroup( data.markerName );\n\n\t\tevt.stop();\n\t};\n}\n\n// Model element to view element conversion helper.\n//\n// See {@link ~DowncastHelpers#elementToElement `.elementToElement()` downcast helper} for examples and config params description.\n//\n// @param {Object} config Conversion configuration.\n// @param {String} config.model\n// @param {module:engine/view/elementdefinition~ElementDefinition|Function} config.view\n// @param {Object} [config.triggerBy]\n// @param {Array.<String>} [config.triggerBy.attributes]\n// @param {Array.<String>} [config.triggerBy.children]\n// @returns {Function} Conversion helper.\nfunction downcastElementToElement( config ) {\n\tconfig = cloneDeep( config );\n\n\tconfig.view = normalizeToElementConfig( config.view, 'container' );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( 'insert:' + config.model, insertElement( config.view ), { priority: config.converterPriority || 'normal' } );\n\n\t\tif ( config.triggerBy ) {\n\t\t\tif ( config.triggerBy.attributes ) {\n\t\t\t\tfor ( const attributeKey of config.triggerBy.attributes ) {\n\t\t\t\t\tdispatcher._mapReconversionTriggerEvent( config.model, `attribute:${ attributeKey }:${ config.model }` );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( config.triggerBy.children ) {\n\t\t\t\tfor ( const childName of config.triggerBy.children ) {\n\t\t\t\t\tdispatcher._mapReconversionTriggerEvent( config.model, `insert:${ childName }` );\n\t\t\t\t\tdispatcher._mapReconversionTriggerEvent( config.model, `remove:${ childName }` );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Model attribute to view element conversion helper.\n//\n// See {@link ~DowncastHelpers#attributeToElement `.attributeToElement()` downcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values }` object. `values` is an array\n// of `String`s with possible values if the model attribute is an enumerable.\n// @param {module:engine/view/elementdefinition~ElementDefinition|Function|Object} config.view A view element definition or a function\n// that takes the model attribute value and {@link module:engine/view/downcastwriter~DowncastWriter view downcast writer}\n// as parameters and returns a view attribute element. If `config.model.values` is\n// given, `config.view` should be an object assigning values from `config.model.values` to view element definitions or functions.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction downcastAttributeToElement( config ) {\n\tconfig = cloneDeep( config );\n\n\tconst modelKey = config.model.key ? config.model.key : config.model;\n\tlet eventName = 'attribute:' + modelKey;\n\n\tif ( config.model.name ) {\n\t\teventName += ':' + config.model.name;\n\t}\n\n\tif ( config.model.values ) {\n\t\tfor ( const modelValue of config.model.values ) {\n\t\t\tconfig.view[ modelValue ] = normalizeToElementConfig( config.view[ modelValue ], 'attribute' );\n\t\t}\n\t} else {\n\t\tconfig.view = normalizeToElementConfig( config.view, 'attribute' );\n\t}\n\n\tconst elementCreator = getFromAttributeCreator( config );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( eventName, wrap( elementCreator ), { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// Model attribute to view attribute conversion helper.\n//\n// See {@link ~DowncastHelpers#attributeToAttribute `.attributeToAttribute()` downcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values, [ name ] }` object describing\n// the attribute key, possible values and, optionally, an element name to convert from.\n// @param {String|Object|Function} config.view A view attribute key, or a `{ key, value }` object or a function that takes\n// the model attribute value and returns a `{ key, value }` object. If `key` is `'class'`, `value` can be a `String` or an\n// array of `String`s. If `key` is `'style'`, `value` is an object with key-value pairs. In other cases, `value` is a `String`.\n// If `config.model.values` is set, `config.view` should be an object assigning values from `config.model.values` to\n// `{ key, value }` objects or a functions.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction downcastAttributeToAttribute( config ) {\n\tconfig = cloneDeep( config );\n\n\tconst modelKey = config.model.key ? config.model.key : config.model;\n\tlet eventName = 'attribute:' + modelKey;\n\n\tif ( config.model.name ) {\n\t\teventName += ':' + config.model.name;\n\t}\n\n\tif ( config.model.values ) {\n\t\tfor ( const modelValue of config.model.values ) {\n\t\t\tconfig.view[ modelValue ] = normalizeToAttributeConfig( config.view[ modelValue ] );\n\t\t}\n\t} else {\n\t\tconfig.view = normalizeToAttributeConfig( config.view );\n\t}\n\n\tconst elementCreator = getFromAttributeCreator( config );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( eventName, changeAttribute( elementCreator ), { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// Model marker to view element conversion helper.\n//\n// See {@link ~DowncastHelpers#markerToElement `.markerToElement()` downcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String} config.model The name of the model marker (or model marker group) to convert.\n// @param {module:engine/view/elementdefinition~ElementDefinition|Function} config.view A view element definition or a function\n// that takes the model marker data as a parameter and returns a view UI element.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction downcastMarkerToElement( config ) {\n\tconfig = cloneDeep( config );\n\n\tconfig.view = normalizeToElementConfig( config.view, 'ui' );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( 'addMarker:' + config.model, insertUIElement( config.view ), { priority: config.converterPriority || 'normal' } );\n\t\tdispatcher.on( 'removeMarker:' + config.model, removeUIElement( config.view ), { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// Model marker to view data conversion helper.\n//\n// See {@link ~DowncastHelpers#markerToData `markerToData()` downcast helper} to learn more.\n//\n// @param {Object} config\n// @param {String} config.model\n// @param {Function} [config.view]\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal']\n// @returns {Function} Conversion helper.\nfunction downcastMarkerToData( config ) {\n\tconfig = cloneDeep( config );\n\n\tconst group = config.model;\n\n\t// Default conversion.\n\tif ( !config.view ) {\n\t\tconfig.view = markerName => ( {\n\t\t\tgroup,\n\t\t\tname: markerName.substr( config.model.length + 1 )\n\t\t} );\n\t}\n\n\treturn dispatcher => {\n\t\tdispatcher.on( 'addMarker:' + group, insertMarkerData( config.view ), { priority: config.converterPriority || 'normal' } );\n\t\tdispatcher.on( 'removeMarker:' + group, removeMarkerData( config.view ), { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// Model marker to highlight conversion helper.\n//\n// See {@link ~DowncastHelpers#markerToElement `.markerToElement()` downcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String} config.model The name of the model marker (or model marker group) to convert.\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor|Function} config.view A highlight descriptor\n// that will be used for highlighting or a function that takes the model marker data as a parameter and returns a highlight descriptor.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction downcastMarkerToHighlight( config ) {\n\treturn dispatcher => {\n\t\tdispatcher.on( 'addMarker:' + config.model, highlightText( config.view ), { priority: config.converterPriority || 'normal' } );\n\t\tdispatcher.on( 'addMarker:' + config.model, highlightElement( config.view ), { priority: config.converterPriority || 'normal' } );\n\t\tdispatcher.on( 'removeMarker:' + config.model, removeHighlight( config.view ), { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// Takes `config.view`, and if it is an {@link module:engine/view/elementdefinition~ElementDefinition}, converts it\n// to a function (because lower level converters accept only element creator functions).\n//\n// @param {module:engine/view/elementdefinition~ElementDefinition|Function} view View configuration.\n// @param {'container'|'attribute'|'ui'} viewElementType View element type to create.\n// @returns {Function} Element creator function to use in lower level converters.\nfunction normalizeToElementConfig( view, viewElementType ) {\n\tif ( typeof view == 'function' ) {\n\t\t// If `view` is already a function, don't do anything.\n\t\treturn view;\n\t}\n\n\treturn ( modelData, conversionApi ) => createViewElementFromDefinition( view, conversionApi, viewElementType );\n}\n\n// Creates a view element instance from the provided {@link module:engine/view/elementdefinition~ElementDefinition} and class.\n//\n// @param {module:engine/view/elementdefinition~ElementDefinition} viewElementDefinition\n// @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter\n// @param {'container'|'attribute'|'ui'} viewElementType\n// @returns {module:engine/view/element~Element}\nfunction createViewElementFromDefinition( viewElementDefinition, conversionApi, viewElementType ) {\n\tif ( typeof viewElementDefinition == 'string' ) {\n\t\t// If `viewElementDefinition` is given as a `String`, normalize it to an object with `name` property.\n\t\tviewElementDefinition = { name: viewElementDefinition };\n\t}\n\n\tlet element;\n\tconst viewWriter = conversionApi.writer;\n\tconst attributes = Object.assign( {}, viewElementDefinition.attributes );\n\n\tif ( viewElementType == 'container' ) {\n\t\telement = viewWriter.createContainerElement( viewElementDefinition.name, attributes );\n\t} else if ( viewElementType == 'attribute' ) {\n\t\tconst options = {\n\t\t\tpriority: viewElementDefinition.priority || ViewAttributeElement.DEFAULT_PRIORITY\n\t\t};\n\n\t\telement = viewWriter.createAttributeElement( viewElementDefinition.name, attributes, options );\n\t} else {\n\t\t// 'ui'.\n\t\telement = viewWriter.createUIElement( viewElementDefinition.name, attributes );\n\t}\n\n\tif ( viewElementDefinition.styles ) {\n\t\tconst keys = Object.keys( viewElementDefinition.styles );\n\n\t\tfor ( const key of keys ) {\n\t\t\tviewWriter.setStyle( key, viewElementDefinition.styles[ key ], element );\n\t\t}\n\t}\n\n\tif ( viewElementDefinition.classes ) {\n\t\tconst classes = viewElementDefinition.classes;\n\n\t\tif ( typeof classes == 'string' ) {\n\t\t\tviewWriter.addClass( classes, element );\n\t\t} else {\n\t\t\tfor ( const className of classes ) {\n\t\t\t\tviewWriter.addClass( className, element );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn element;\n}\n\nfunction getFromAttributeCreator( config ) {\n\tif ( config.model.values ) {\n\t\treturn ( modelAttributeValue, conversionApi ) => {\n\t\t\tconst view = config.view[ modelAttributeValue ];\n\n\t\t\tif ( view ) {\n\t\t\t\treturn view( modelAttributeValue, conversionApi );\n\t\t\t}\n\n\t\t\treturn null;\n\t\t};\n\t} else {\n\t\treturn config.view;\n\t}\n}\n\n// Takes the configuration, adds default parameters if they do not exist and normalizes other parameters to be used in downcast converters\n// for generating a view attribute.\n//\n// @param {Object} view View configuration.\nfunction normalizeToAttributeConfig( view ) {\n\tif ( typeof view == 'string' ) {\n\t\treturn modelAttributeValue => ( { key: view, value: modelAttributeValue } );\n\t} else if ( typeof view == 'object' ) {\n\t\t// { key, value, ... }\n\t\tif ( view.value ) {\n\t\t\treturn () => view;\n\t\t}\n\t\t// { key, ... }\n\t\telse {\n\t\t\treturn modelAttributeValue => ( { key: view.key, value: modelAttributeValue } );\n\t\t}\n\t} else {\n\t\t// function.\n\t\treturn view;\n\t}\n}\n\n// Helper function for `highlight`. Prepares the actual descriptor object using value passed to the converter.\nfunction prepareDescriptor( highlightDescriptor, data, conversionApi ) {\n\t// If passed descriptor is a creator function, call it. If not, just use passed value.\n\tconst descriptor = typeof highlightDescriptor == 'function' ?\n\t\thighlightDescriptor( data, conversionApi ) :\n\t\thighlightDescriptor;\n\n\tif ( !descriptor ) {\n\t\treturn null;\n\t}\n\n\t// Apply default descriptor priority.\n\tif ( !descriptor.priority ) {\n\t\tdescriptor.priority = 10;\n\t}\n\n\t// Default descriptor id is marker name.\n\tif ( !descriptor.id ) {\n\t\tdescriptor.id = data.markerName;\n\t}\n\n\treturn descriptor;\n}\n\n/**\n * An object describing how the marker highlight should be represented in the view.\n *\n * Each text node contained in a highlighted range will be wrapped in a `<span>`\n * {@link module:engine/view/attributeelement~AttributeElement view attribute element} with CSS class(es), attributes and a priority\n * described by this object.\n *\n * Additionally, each {@link module:engine/view/containerelement~ContainerElement container element} can handle displaying the highlight\n * separately by providing the `addHighlight` and `removeHighlight` custom properties. In this case:\n *\n *  * The `HighlightDescriptor` object is passed to the `addHighlight` function upon conversion and should be used to apply the highlight to\n *  the element.\n *  * The descriptor `id` is passed to the `removeHighlight` function upon conversion and should be used to remove the highlight with the\n *  given ID from the element.\n *\n * @typedef {Object} module:engine/conversion/downcasthelpers~HighlightDescriptor\n *\n * @property {String|Array.<String>} classes A CSS class or an array of classes to set. If the descriptor is used to\n * create an {@link module:engine/view/attributeelement~AttributeElement attribute element} over text nodes, these classes will be set\n * on that attribute element. If the descriptor is applied to an element, usually these classes will be set on that element, however,\n * this depends on how the element converts the descriptor.\n *\n * @property {String} [id] Descriptor identifier. If not provided, it defaults to the converted marker's name.\n *\n * @property {Number} [priority] Descriptor priority. If not provided, it defaults to `10`. If the descriptor is used to create\n * an {@link module:engine/view/attributeelement~AttributeElement attribute element}, it will be that element's\n * {@link module:engine/view/attributeelement~AttributeElement#priority priority}. If the descriptor is applied to an element,\n * the priority will be used to determine which descriptor is more important.\n *\n * @property {Object} [attributes] Attributes to set. If the descriptor is used to create\n * an {@link module:engine/view/attributeelement~AttributeElement attribute element} over text nodes, these attributes will be set on that\n * attribute element. If the descriptor is applied to an element, usually these attributes will be set on that element, however,\n * this depends on how the element converts the descriptor.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/utils/autoparagraphing\n */\n\n/**\n * Fixes all empty roots.\n *\n * @protected\n * @param {module:engine/model/writer~Writer} writer The model writer.\n * @returns {Boolean} `true` if any change has been applied, `false` otherwise.\n */\nexport function autoParagraphEmptyRoots( writer ) {\n\tconst { schema, document } = writer.model;\n\n\tfor ( const rootName of document.getRootNames() ) {\n\t\tconst root = document.getRoot( rootName );\n\n\t\tif ( root.isEmpty && !schema.checkChild( root, '$text' ) ) {\n\t\t\t// If paragraph element is allowed in the root, create paragraph element.\n\t\t\tif ( schema.checkChild( root, 'paragraph' ) ) {\n\t\t\t\twriter.insertElement( 'paragraph', root );\n\n\t\t\t\t// Other roots will get fixed in the next post-fixer round. Those will be triggered\n\t\t\t\t// in the same batch no matter if this method was triggered by the post-fixing or not\n\t\t\t\t// (the above insertElement call will trigger the post-fixers).\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Checks if the given node wrapped with a paragraph would be accepted by the schema in the given position.\n *\n * @protected\n * @param {module:engine/model/position~Position} position The position at which to check.\n * @param {module:engine/model/node~Node|String} nodeOrType The child node or child type to check.\n * @param {module:engine/model/schema~Schema} schema A schema instance used for element validation.\n */\nexport function isParagraphable( position, nodeOrType, schema ) {\n\tconst context = schema.createContext( position );\n\n\t// When paragraph is allowed in this context...\n\tif ( !schema.checkChild( context, 'paragraph' ) ) {\n\t\treturn false;\n\t}\n\n\t// And a node would be allowed in this paragraph...\n\tif ( !schema.checkChild( context.push( 'paragraph' ), nodeOrType ) ) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n/**\n * Inserts a new paragraph at the given position and returns a position inside that paragraph.\n *\n * @protected\n * @param {module:engine/model/position~Position} position The position where a paragraph should be inserted.\n * @param {module:engine/model/writer~Writer} writer The model writer.\n * @returns {module:engine/model/position~Position} Position inside the created paragraph.\n */\nexport function wrapInParagraph( position, writer ) {\n\tconst paragraph = writer.createElement( 'paragraph' );\n\n\twriter.insert( paragraph, position );\n\n\treturn writer.createPositionAt( paragraph, 0 );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport Matcher from '../view/matcher';\nimport ConversionHelpers from './conversionhelpers';\n\nimport { cloneDeep } from 'lodash-es';\nimport { logWarning } from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\nimport priorities from '@ckeditor/ckeditor5-utils/src/priorities';\nimport { isParagraphable, wrapInParagraph } from '../model/utils/autoparagraphing';\n\n/**\n * Contains {@link module:engine/view/view view} to {@link module:engine/model/model model} converters for\n * {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher}.\n *\n * @module engine/conversion/upcasthelpers\n */\n\n/**\n * Upcast conversion helper functions.\n *\n * @extends module:engine/conversion/conversionhelpers~ConversionHelpers\n */\nexport default class UpcastHelpers extends ConversionHelpers {\n\t/**\n\t * View element to model element conversion helper.\n\t *\n\t * This conversion results in creating a model element. For example,\n\t * view `<p>Foo</p>` becomes `<paragraph>Foo</paragraph>` in the model.\n\t *\n\t * Keep in mind that the element will be inserted only if it is allowed\n\t * by {@link module:engine/model/schema~Schema schema} configuration.\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t *\t\t\tview: 'p',\n\t *\t\t\tmodel: 'paragraph'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t *\t\t\tview: 'p',\n\t *\t\t\tmodel: 'paragraph',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'p',\n\t *\t\t\t\tclasses: 'fancy'\n\t *\t\t\t},\n\t *\t\t\tmodel: 'fancyParagraph'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t * \t\t\tview: {\n\t *\t\t\t\tname: 'p',\n\t *\t\t\t\tclasses: 'heading'\n\t * \t\t\t},\n\t * \t\t\tmodel: ( viewElement, conversionApi ) => {\n\t * \t\t\t\tconst modelWriter = conversionApi.writer;\n\t *\n\t * \t\t\t\treturn modelWriter.createElement( 'heading', { level: viewElement.getAttribute( 'data-level' ) } );\n\t * \t\t\t}\n\t * \t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #elementToElement\n\t * @param {Object} config Conversion configuration.\n\t * @param {module:engine/view/matcher~MatcherPattern} [config.view] Pattern matching all view elements which should be converted. If not\n\t * set, the converter will fire for every view element.\n\t * @param {String|module:engine/model/element~Element|Function} config.model Name of the model element, a model element instance or a\n\t * function that takes a view element and {@link module:engine/conversion/upcastdispatcher~UpcastConversionApi upcast conversion API}\n\t * and returns a model element. The model element will be inserted in the model.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\telementToElement( config ) {\n\t\treturn this.add( upcastElementToElement( config ) );\n\t}\n\n\t/**\n\t * View element to model attribute conversion helper.\n\t *\n\t * This conversion results in setting an attribute on a model node. For example, view `<strong>Foo</strong>` becomes\n\t * `Foo` {@link module:engine/model/text~Text model text node} with `bold` attribute set to `true`.\n\t *\n\t * This helper is meant to set a model attribute on all the elements that are inside the converted element:\n\t *\n\t *\t\t<strong>Foo</strong>   -->   <strong><p>Foo</p></strong>   -->   <paragraph><$text bold=\"true\">Foo</$text></paragraph>\n\t *\n\t * Above is a sample of HTML code, that goes through autoparagraphing (first step) and then is converted (second step).\n\t * Even though `<strong>` is over `<p>` element, `bold=\"true\"` was added to the text. See\n\t * {@link module:engine/conversion/upcasthelpers~UpcastHelpers#attributeToAttribute} for comparison.\n\t *\n\t * Keep in mind that the attribute will be set only if it is allowed by {@link module:engine/model/schema~Schema schema} configuration.\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t *\t\t\tview: 'strong',\n\t *\t\t\tmodel: 'bold'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t *\t\t\tview: 'strong',\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tclasses: 'bold'\n\t *\t\t\t},\n\t *\t\t\tmodel: 'bold'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tclasses: [ 'styled', 'styled-dark' ]\n\t *\t\t\t},\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'styled',\n\t *\t\t\t\tvalue: 'dark'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * \t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tstyles: {\n\t *\t\t\t\t\t'font-size': /[\\s\\S]+/\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'fontSize',\n\t *\t\t\t\tvalue: ( viewElement, conversionApi ) => {\n\t *\t\t\t\t\tconst fontSize = viewElement.getStyle( 'font-size' );\n\t *\t\t\t\t\tconst value = fontSize.substr( 0, fontSize.length - 2 );\n\t *\n\t *\t\t\t\t\tif ( value <= 10 ) {\n\t *\t\t\t\t\t\treturn 'small';\n\t *\t\t\t\t\t} else if ( value > 12 ) {\n\t *\t\t\t\t\t\treturn 'big';\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\treturn null;\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #elementToAttribute\n\t * @param {Object} config Conversion configuration.\n\t * @param {module:engine/view/matcher~MatcherPattern} config.view Pattern matching all view elements which should be converted.\n\t * @param {String|Object} config.model Model attribute key or an object with `key` and `value` properties, describing\n\t * the model attribute. `value` property may be set as a function that takes a view element and\n\t * {@link module:engine/conversion/upcastdispatcher~UpcastConversionApi upcast conversion API} and returns the value.\n\t * If `String` is given, the model attribute value will be set to `true`.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='low'] Converter priority.\n\t * @returns {module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\telementToAttribute( config ) {\n\t\treturn this.add( upcastElementToAttribute( config ) );\n\t}\n\n\t/**\n\t * View attribute to model attribute conversion helper.\n\t *\n\t * This conversion results in setting an attribute on a model node. For example, view `<img src=\"foo.jpg\"></img>` becomes\n\t * `<image source=\"foo.jpg\"></image>` in the model.\n\t *\n\t * This helper is meant to convert view attributes from view elements which got converted to the model, so the view attribute\n\t * is set only on the corresponding model node:\n\t *\n\t *\t\t<div class=\"dark\"><div>foo</div></div>    -->    <div dark=\"true\"><div>foo</div></div>\n\t *\n\t * Above, `class=\"dark\"` attribute is added only to the `<div>` elements that has it. This is in contrary to\n\t * {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToAttribute} which sets attributes for\n\t * all the children in the model:\n\t *\n\t *\t\t<strong>Foo</strong>   -->   <strong><p>Foo</p></strong>   -->   <paragraph><$text bold=\"true\">Foo</$text></paragraph>\n\t *\n\t * Above is a sample of HTML code, that goes through autoparagraphing (first step) and then is converted (second step).\n\t * Even though `<strong>` is over `<p>` element, `bold=\"true\"` was added to the text.\n\t *\n\t * Keep in mind that the attribute will be set only if it is allowed by {@link module:engine/model/schema~Schema schema} configuration.\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: 'src',\n\t *\t\t\tmodel: 'source'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: { key: 'src' },\n\t *\t\t\tmodel: 'source'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: { key: 'src' },\n\t *\t\t\tmodel: 'source',\n\t *\t\t\tconverterPriority: 'normal'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tkey: 'data-style',\n\t *\t\t\t\tvalue: /[\\s\\S]+/\n\t *\t\t\t},\n\t *\t\t\tmodel: 'styled'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'img',\n\t *\t\t\t\tkey: 'class',\n\t *\t\t\t\tvalue: 'styled-dark'\n\t *\t\t\t},\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'styled',\n\t *\t\t\t\tvalue: 'dark'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tkey: 'class',\n\t *\t\t\t\tvalue: /styled-[\\S]+/\n\t *\t\t\t},\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'styled'\n\t *\t\t\t\tvalue: ( viewElement, conversionApi ) => {\n\t *\t\t\t\t\tconst regexp = /styled-([\\S]+)/;\n\t *\t\t\t\t\tconst match = viewElement.getAttribute( 'class' ).match( regexp );\n\t *\n\t *\t\t\t\t\treturn match[ 1 ];\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * Converting styles works a bit differently as it requires `view.styles` to be an object and by default\n\t * a model attribute will be set to `true` by such a converter. You can set the model attribute to any value by providing the `value`\n\t * callback that returns the desired value.\n\t *\n\t *\t\t// Default conversion of font-weight style will result in setting bold attribute to true.\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tstyles: {\n\t *\t\t\t\t\t'font-weight': 'bold'\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tmodel: 'bold'\n\t *\t\t} );\n\t *\n\t *\t\t// This converter will pass any style value to the `lineHeight` model attribute.\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tstyles: {\n\t *\t\t\t\t\t'line-height': /[\\s\\S]+/\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'lineHeight',\n\t *\t\t\t\tvalue: ( viewElement, conversionApi ) => viewElement.getStyle( 'line-height' )\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #attributeToAttribute\n\t * @param {Object} config Conversion configuration.\n\t * @param {String|Object} config.view Specifies which view attribute will be converted. If a `String` is passed,\n\t * attributes with given key will be converted. If an `Object` is passed, it must have a required `key` property,\n\t * specifying view attribute key, and may have an optional `value` property, specifying view attribute value and optional `name`\n\t * property specifying a view element name from/on which the attribute should be converted. `value` can be given as a `String`,\n\t * a `RegExp` or a function callback, that takes view attribute value as the only parameter and returns `Boolean`.\n\t * @param {String|Object} config.model Model attribute key or an object with `key` and `value` properties, describing\n\t * the model attribute. `value` property may be set as a function that takes a view element and\n\t * {@link module:engine/conversion/upcastdispatcher~UpcastConversionApi upcast conversion API} and returns the value.\n\t * If `String` is given, the model attribute value will be same as view attribute value.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='low'] Converter priority.\n\t * @returns {module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\tattributeToAttribute( config ) {\n\t\treturn this.add( upcastAttributeToAttribute( config ) );\n\t}\n\n\t/**\n\t * View element to model marker conversion helper.\n\t *\n\t * **Note**: This method was deprecated. Please use {@link #dataToMarker} instead.\n\t *\n\t * This conversion results in creating a model marker. For example, if the marker was stored in a view as an element:\n\t * `<p>Fo<span data-marker=\"comment\" data-comment-id=\"7\"></span>o</p><p>B<span data-marker=\"comment\" data-comment-id=\"7\"></span>ar</p>`,\n\t * after the conversion is done, the marker will be available in\n\t * {@link module:engine/model/model~Model#markers model document markers}.\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToMarker( {\n\t *\t\t\tview: 'marker-search',\n\t *\t\t\tmodel: 'search'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToMarker( {\n\t *\t\t\tview: 'marker-search',\n\t *\t\t\tmodel: 'search',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToMarker( {\n\t *\t\t\tview: 'marker-search',\n\t *\t\t\tmodel: ( viewElement, conversionApi ) => 'comment:' + viewElement.getAttribute( 'data-comment-id' )\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToMarker( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tattributes: {\n\t *\t\t\t\t\t'data-marker': 'search'\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tmodel: 'search'\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @deprecated\n\t * @method #elementToMarker\n\t * @param {Object} config Conversion configuration.\n\t * @param {module:engine/view/matcher~MatcherPattern} config.view Pattern matching all view elements which should be converted.\n\t * @param {String|Function} config.model Name of the model marker, or a function that takes a view element and returns\n\t * a model marker name.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\telementToMarker( config ) {\n\t\t/**\n\t\t * The {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToMarker `UpcastHelpers#elementToMarker()`}\n\t\t * method was deprecated and will be removed in the near future.\n\t\t * Please use {@link module:engine/conversion/upcasthelpers~UpcastHelpers#dataToMarker `UpcastHelpers#dataToMarker()`} instead.\n\t\t *\n\t\t * @error upcast-helpers-element-to-marker-deprecated\n\t\t */\n\t\tlogWarning( 'upcast-helpers-element-to-marker-deprecated' );\n\n\t\treturn this.add( upcastElementToMarker( config ) );\n\t}\n\n\t/**\n\t * View-to-model marker conversion helper.\n\t *\n\t * Converts view data created by {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToData `#markerToData()`}\n\t * back to a model marker.\n\t *\n\t * This converter looks for specific view elements and view attributes that mark marker boundaries. See\n\t * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToData `#markerToData()`} to learn what view data\n\t * is expected by this converter.\n\t *\n\t * The `config.view` property is equal to the marker group name to convert.\n\t *\n\t * By default, this converter creates markers with the `group:name` name convention (to match the default `markerToData` conversion).\n\t *\n\t * The conversion configuration can take a function that will generate a marker name.\n\t * If such function is set as the `config.model` parameter, it is passed the `name` part from the view element or attribute and it is\n\t * expected to return a string with the marker name.\n\t *\n\t * Basic usage:\n\t *\n\t *\t\t// Using the default conversion.\n\t *\t\t// In this case, all markers from the `comment` group will be converted.\n\t *\t\t// The conversion will look for `<comment-start>` and `<comment-end>` tags and\n\t *\t\t// `data-comment-start-before`, `data-comment-start-after`,\n\t *\t\t// `data-comment-end-before` and `data-comment-end-after` attributes.\n\t *\t\teditor.conversion.for( 'upcast' ).dataToMarker( {\n\t *\t\t\tview: 'comment'\n\t *\t\t} );\n\t *\n\t * An example of a model that may be generated by this conversion:\n\t *\n\t *\t\t// View:\n\t *\t\t<p>Foo<comment-start name=\"commentId:uid\"></comment-start>bar</p>\n\t *\t\t<figure data-comment-end-after=\"commentId:uid\" class=\"image\"><img src=\"abc.jpg\" /></figure>\n\t *\n\t *\t\t// Model:\n\t *\t\t<paragraph>Foo[bar</paragraph>\n\t *\t\t<image src=\"abc.jpg\"></image>]\n\t *\n\t * Where `[]` are boundaries of a marker that will receive the `comment:commentId:uid` name.\n\t *\n\t * Other examples of usage:\n\t *\n\t *\t\t// Using a custom function which is the same as the default conversion:\n\t *\t\teditor.conversion.for( 'upcast' ).dataToMarker( {\n\t *\t\t\tview: 'comment',\n\t *\t\t\tmodel: ( name, conversionApi ) => 'comment:' + name,\n\t *\t\t} );\n\t *\n\t *\t\t// Using the converter priority:\n\t *\t\teditor.conversion.for( 'upcast' ).dataToMarker( {\n\t *\t\t\tview: 'comment',\n\t *\t\t\tmodel: ( name, conversionApi ) => 'comment:' + name,\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #dataToMarker\n\t * @param {Object} config Conversion configuration.\n\t * @param {String} config.view The marker group name to convert.\n\t * @param {Function} [config.model] A function that takes the `name` part from the view element or attribute and\n\t * {@link module:engine/conversion/upcastdispatcher~UpcastConversionApi upcast conversion API} and returns the marker name.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\tdataToMarker( config ) {\n\t\treturn this.add( upcastDataToMarker( config ) );\n\t}\n}\n\n/**\n * Function factory, creates a converter that converts {@link module:engine/view/documentfragment~DocumentFragment view document fragment}\n * or all children of {@link module:engine/view/element~Element} into\n * {@link module:engine/model/documentfragment~DocumentFragment model document fragment}.\n * This is the \"entry-point\" converter for upcast (view to model conversion). This converter starts the conversion of all children\n * of passed view document fragment. Those children {@link module:engine/view/node~Node view nodes} are then handled by other converters.\n *\n * This also a \"default\", last resort converter for all view elements that has not been converted by other converters.\n * When a view element is being converted to the model but it does not have converter specified, that view element\n * will be converted to {@link module:engine/model/documentfragment~DocumentFragment model document fragment} and returned.\n *\n * @returns {Function} Universal converter for view {@link module:engine/view/documentfragment~DocumentFragment fragments} and\n * {@link module:engine/view/element~Element elements} that returns\n * {@link module:engine/model/documentfragment~DocumentFragment model fragment} with children of converted view item.\n */\nexport function convertToModelFragment() {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// Second argument in `consumable.consume` is discarded for ViewDocumentFragment but is needed for ViewElement.\n\t\tif ( !data.modelRange && conversionApi.consumable.consume( data.viewItem, { name: true } ) ) {\n\t\t\tconst { modelRange, modelCursor } = conversionApi.convertChildren( data.viewItem, data.modelCursor );\n\n\t\t\tdata.modelRange = modelRange;\n\t\t\tdata.modelCursor = modelCursor;\n\t\t}\n\t};\n}\n\n/**\n * Function factory, creates a converter that converts {@link module:engine/view/text~Text} to {@link module:engine/model/text~Text}.\n *\n * @returns {Function} {@link module:engine/view/text~Text View text} converter.\n */\nexport function convertText() {\n\treturn ( evt, data, { schema, consumable, writer } ) => {\n\t\tlet position = data.modelCursor;\n\n\t\t// When node is already converted then do nothing.\n\t\tif ( !consumable.test( data.viewItem ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !schema.checkChild( position, '$text' ) ) {\n\t\t\tif ( !isParagraphable( position, '$text', schema ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tposition = wrapInParagraph( position, writer );\n\t\t}\n\n\t\tconsumable.consume( data.viewItem );\n\n\t\tconst text = writer.createText( data.viewItem.data );\n\n\t\twriter.insert( text, position );\n\n\t\tdata.modelRange = writer.createRange(\n\t\t\tposition,\n\t\t\tposition.getShiftedBy( text.offsetSize )\n\t\t);\n\t\tdata.modelCursor = data.modelRange.end;\n\t};\n}\n\n/**\n * Function factory, creates a callback function which converts a {@link module:engine/view/selection~Selection\n * view selection} taken from the {@link module:engine/view/document~Document#event:selectionChange} event\n * and sets in on the {@link module:engine/model/document~Document#selection model}.\n *\n * **Note**: because there is no view selection change dispatcher nor any other advanced view selection to model\n * conversion mechanism, the callback should be set directly on view document.\n *\n *\t\tview.document.on( 'selectionChange', convertSelectionChange( modelDocument, mapper ) );\n *\n * @param {module:engine/model/model~Model} model Data model.\n * @param {module:engine/conversion/mapper~Mapper} mapper Conversion mapper.\n * @returns {Function} {@link module:engine/view/document~Document#event:selectionChange} callback function.\n */\nexport function convertSelectionChange( model, mapper ) {\n\treturn ( evt, data ) => {\n\t\tconst viewSelection = data.newSelection;\n\n\t\tconst ranges = [];\n\n\t\tfor ( const viewRange of viewSelection.getRanges() ) {\n\t\t\tranges.push( mapper.toModelRange( viewRange ) );\n\t\t}\n\n\t\tconst modelSelection = model.createSelection( ranges, { backward: viewSelection.isBackward } );\n\n\t\tif ( !modelSelection.isEqual( model.document.selection ) ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\twriter.setSelection( modelSelection );\n\t\t\t} );\n\t\t}\n\t};\n}\n\n// View element to model element conversion helper.\n//\n// See {@link ~UpcastHelpers#elementToElement `.elementToElement()` upcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {module:engine/view/matcher~MatcherPattern} [config.view] Pattern matching all view elements which should be converted. If not\n// set, the converter will fire for every view element.\n// @param {String|module:engine/model/element~Element|Function} config.model Name of the model element, a model element\n// instance or a function that takes a view element and returns a model element. The model element will be inserted in the model.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction upcastElementToElement( config ) {\n\tconfig = cloneDeep( config );\n\n\tconst converter = prepareToElementConverter( config );\n\n\tconst elementName = getViewElementNameFromConfig( config.view );\n\tconst eventName = elementName ? 'element:' + elementName : 'element';\n\n\treturn dispatcher => {\n\t\tdispatcher.on( eventName, converter, { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// View element to model attribute conversion helper.\n//\n// See {@link ~UpcastHelpers#elementToAttribute `.elementToAttribute()` upcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {module:engine/view/matcher~MatcherPattern} config.view Pattern matching all view elements which should be converted.\n// @param {String|Object} config.model Model attribute key or an object with `key` and `value` properties, describing\n// the model attribute. `value` property may be set as a function that takes a view element and returns the value.\n// If `String` is given, the model attribute value will be set to `true`.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='low'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction upcastElementToAttribute( config ) {\n\tconfig = cloneDeep( config );\n\n\tnormalizeModelAttributeConfig( config );\n\n\tconst converter = prepareToAttributeConverter( config, false );\n\n\tconst elementName = getViewElementNameFromConfig( config.view );\n\tconst eventName = elementName ? 'element:' + elementName : 'element';\n\n\treturn dispatcher => {\n\t\tdispatcher.on( eventName, converter, { priority: config.converterPriority || 'low' } );\n\t};\n}\n\n// View attribute to model attribute conversion helper.\n//\n// See {@link ~UpcastHelpers#attributeToAttribute `.attributeToAttribute()` upcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String|Object} config.view Specifies which view attribute will be converted. If a `String` is passed,\n// attributes with given key will be converted. If an `Object` is passed, it must have a required `key` property,\n// specifying view attribute key, and may have an optional `value` property, specifying view attribute value and optional `name`\n// property specifying a view element name from/on which the attribute should be converted. `value` can be given as a `String`,\n// a `RegExp` or a function callback, that takes view attribute value as the only parameter and returns `Boolean`.\n// @param {String|Object} config.model Model attribute key or an object with `key` and `value` properties, describing\n// the model attribute. `value` property may be set as a function that takes a view element and returns the value.\n// If `String` is given, the model attribute value will be same as view attribute value.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='low'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction upcastAttributeToAttribute( config ) {\n\tconfig = cloneDeep( config );\n\n\tlet viewKey = null;\n\n\tif ( typeof config.view == 'string' || config.view.key ) {\n\t\tviewKey = normalizeViewAttributeKeyValueConfig( config );\n\t}\n\n\tnormalizeModelAttributeConfig( config, viewKey );\n\n\tconst converter = prepareToAttributeConverter( config, true );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( 'element', converter, { priority: config.converterPriority || 'low' } );\n\t};\n}\n\n// View element to model marker conversion helper.\n//\n// See {@link ~UpcastHelpers#elementToMarker `.elementToMarker()` upcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {module:engine/view/matcher~MatcherPattern} config.view Pattern matching all view elements which should be converted.\n// @param {String|Function} config.model Name of the model marker, or a function that takes a view element and returns\n// a model marker name.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction upcastElementToMarker( config ) {\n\tconfig = cloneDeep( config );\n\n\tnormalizeElementToMarkerConfig( config );\n\n\treturn upcastElementToElement( config );\n}\n\n// View data to model marker conversion helper.\n//\n// See {@link ~UpcastHelpers#dataToMarker} to learn more.\n//\n// @param {Object} config\n// @param {String} config.view\n// @param {Function} [config.model]\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal']\n// @returns {Function} Conversion helper.\nfunction upcastDataToMarker( config ) {\n\tconfig = cloneDeep( config );\n\n\t// Default conversion.\n\tif ( !config.model ) {\n\t\tconfig.model = name => {\n\t\t\treturn name ? config.view + ':' + name : config.view;\n\t\t};\n\t}\n\n\tconst converterStart = prepareToElementConverter( normalizeDataToMarkerConfig( config, 'start' ) );\n\tconst converterEnd = prepareToElementConverter( normalizeDataToMarkerConfig( config, 'end' ) );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( 'element:' + config.view + '-start', converterStart, { priority: config.converterPriority || 'normal' } );\n\t\tdispatcher.on( 'element:' + config.view + '-end', converterEnd, { priority: config.converterPriority || 'normal' } );\n\n\t\t// Below is a hack that is needed to properly handle `converterPriority` for both elements and attributes.\n\t\t// Attribute conversion needs to be performed *after* element conversion.\n\t\t// This converter handles both element conversion and attribute conversion, which means that if a single\n\t\t// `config.converterPriority` is used, it will lead to problems. For example, if `'high'` priority is used,\n\t\t// then attribute conversion will be performed before a lot of element upcast converters.\n\t\t// On the other hand we want to support `config.converterPriority` and overwriting conveters.\n\t\t//\n\t\t// To have it work, we need to do some extra processing for priority for attribute converter.\n\t\t// Priority `'low'` value should be the base value and then we will change it depending on `config.converterPriority` value.\n\t\t//\n\t\t// This hack probably would not be needed if attributes are upcasted separately.\n\t\t//\n\t\tconst basePriority = priorities.get( 'low' );\n\t\tconst maxPriority = priorities.get( 'highest' );\n\t\tconst priorityFactor = priorities.get( config.converterPriority ) / maxPriority; // Number in range [ -1, 1 ].\n\n\t\tdispatcher.on( 'element', upcastAttributeToMarker( config ), { priority: basePriority + priorityFactor } );\n\t};\n}\n\n// Function factory, returns a callback function which converts view attributes to a model marker.\n//\n// The converter looks for elements with `data-group-start-before`, `data-group-start-after`, `data-group-end-before`\n// and `data-group-end-after` attributes and inserts `$marker` model elements before/after those elements.\n// `group` part is specified in `config.view`.\n//\n// @param {Object} config\n// @param {String} config.view\n// @param {Function} [config.model]\n// @returns {Function} Marker converter.\nfunction upcastAttributeToMarker( config ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst attrName = `data-${ config.view }`;\n\n\t\t// This converter wants to add a model element, marking a marker, before/after an element (or maybe even group of elements).\n\t\t// To do that, we can use `data.modelRange` which is set on an element (or a group of elements) that has been upcasted.\n\t\t// But, if the processed view element has not been upcasted yet (it does not have been converted), we need to\n\t\t// fire conversion for its children first, then we will have `data.modelRange` available.\n\t\tif ( !data.modelRange ) {\n\t\t\tdata = Object.assign( data, conversionApi.convertChildren( data.viewItem, data.modelCursor ) );\n\t\t}\n\n\t\tif ( conversionApi.consumable.consume( data.viewItem, { attributes: attrName + '-end-after' } ) ) {\n\t\t\taddMarkerElements( data.modelRange.end, data.viewItem.getAttribute( attrName + '-end-after' ).split( ',' ) );\n\t\t}\n\n\t\tif ( conversionApi.consumable.consume( data.viewItem, { attributes: attrName + '-start-after' } ) ) {\n\t\t\taddMarkerElements( data.modelRange.end, data.viewItem.getAttribute( attrName + '-start-after' ).split( ',' ) );\n\t\t}\n\n\t\tif ( conversionApi.consumable.consume( data.viewItem, { attributes: attrName + '-end-before' } ) ) {\n\t\t\taddMarkerElements( data.modelRange.start, data.viewItem.getAttribute( attrName + '-end-before' ).split( ',' ) );\n\t\t}\n\n\t\tif ( conversionApi.consumable.consume( data.viewItem, { attributes: attrName + '-start-before' } ) ) {\n\t\t\taddMarkerElements( data.modelRange.start, data.viewItem.getAttribute( attrName + '-start-before' ).split( ',' ) );\n\t\t}\n\n\t\tfunction addMarkerElements( position, markerViewNames ) {\n\t\t\tfor ( const markerViewName of markerViewNames ) {\n\t\t\t\tconst markerName = config.model( markerViewName, conversionApi );\n\t\t\t\tconst element = conversionApi.writer.createElement( '$marker', { 'data-name': markerName } );\n\n\t\t\t\tconversionApi.writer.insert( element, position );\n\n\t\t\t\tif ( data.modelCursor.isEqual( position ) ) {\n\t\t\t\t\tdata.modelCursor = data.modelCursor.getShiftedBy( 1 );\n\t\t\t\t} else {\n\t\t\t\t\tdata.modelCursor = data.modelCursor._getTransformedByInsertion( position, 1 );\n\t\t\t\t}\n\n\t\t\t\tdata.modelRange = data.modelRange._getTransformedByInsertion( position, 1 )[ 0 ];\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Helper function for from-view-element conversion. Checks if `config.view` directly specifies converted view element's name\n// and if so, returns it.\n//\n// @param {Object} config Conversion view config.\n// @returns {String|null} View element name or `null` if name is not directly set.\nfunction getViewElementNameFromConfig( viewConfig ) {\n\tif ( typeof viewConfig == 'string' ) {\n\t\treturn viewConfig;\n\t}\n\n\tif ( typeof viewConfig == 'object' && typeof viewConfig.name == 'string' ) {\n\t\treturn viewConfig.name;\n\t}\n\n\treturn null;\n}\n\n// Helper for to-model-element conversion. Takes a config object and returns a proper converter function.\n//\n// @param {Object} config Conversion configuration.\n// @returns {Function} View to model converter.\nfunction prepareToElementConverter( config ) {\n\tconst matcher = new Matcher( config.view );\n\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst matcherResult = matcher.match( data.viewItem );\n\n\t\tif ( !matcherResult ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst match = matcherResult.match;\n\n\t\t// Force consuming element's name.\n\t\tmatch.name = true;\n\n\t\tif ( !conversionApi.consumable.test( data.viewItem, match ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst modelElement = getModelElement( config.model, data.viewItem, conversionApi );\n\n\t\tif ( !modelElement ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.safeInsert( modelElement, data.modelCursor ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconversionApi.consumable.consume( data.viewItem, match );\n\t\tconversionApi.convertChildren( data.viewItem, modelElement );\n\t\tconversionApi.updateConversionResult( modelElement, data );\n\t};\n}\n\n// Helper function for upcasting-to-element converter. Takes the model configuration, the converted view element\n// and a writer instance and returns a model element instance to be inserted in the model.\n//\n// @param {String|Function|module:engine/model/element~Element} model Model conversion configuration.\n// @param {module:engine/view/node~Node} input The converted view node.\n// @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi The upcast conversion API.\nfunction getModelElement( model, input, conversionApi ) {\n\tif ( model instanceof Function ) {\n\t\treturn model( input, conversionApi );\n\t} else {\n\t\treturn conversionApi.writer.createElement( model );\n\t}\n}\n\n// Helper function view-attribute-to-model-attribute helper. Normalizes `config.view` which was set as `String` or\n// as an `Object` with `key`, `value` and `name` properties. Normalized `config.view` has is compatible with\n// {@link module:engine/view/matcher~MatcherPattern}.\n//\n// @param {Object} config Conversion config.\n// @returns {String} Key of the converted view attribute.\nfunction normalizeViewAttributeKeyValueConfig( config ) {\n\tif ( typeof config.view == 'string' ) {\n\t\tconfig.view = { key: config.view };\n\t}\n\n\tconst key = config.view.key;\n\tlet normalized;\n\n\tif ( key == 'class' || key == 'style' ) {\n\t\tconst keyName = key == 'class' ? 'classes' : 'styles';\n\n\t\tnormalized = {\n\t\t\t[ keyName ]: config.view.value\n\t\t};\n\t} else {\n\t\tconst value = typeof config.view.value == 'undefined' ? /[\\s\\S]*/ : config.view.value;\n\n\t\tnormalized = {\n\t\t\tattributes: {\n\t\t\t\t[ key ]: value\n\t\t\t}\n\t\t};\n\t}\n\n\tif ( config.view.name ) {\n\t\tnormalized.name = config.view.name;\n\t}\n\n\tconfig.view = normalized;\n\n\treturn key;\n}\n\n// Helper function that normalizes `config.model` in from-model-attribute conversion. `config.model` can be set\n// as a `String`, an `Object` with only `key` property or an `Object` with `key` and `value` properties. Normalized\n// `config.model` is an `Object` with `key` and `value` properties.\n//\n// @param {Object} config Conversion config.\n// @param {String} viewAttributeKeyToCopy Key of the converted view attribute. If it is set, model attribute value\n// will be equal to view attribute value.\nfunction normalizeModelAttributeConfig( config, viewAttributeKeyToCopy = null ) {\n\tconst defaultModelValue = viewAttributeKeyToCopy === null ? true : viewElement => viewElement.getAttribute( viewAttributeKeyToCopy );\n\n\tconst key = typeof config.model != 'object' ? config.model : config.model.key;\n\tconst value = typeof config.model != 'object' || typeof config.model.value == 'undefined' ? defaultModelValue : config.model.value;\n\n\tconfig.model = { key, value };\n}\n\n// Helper for to-model-attribute conversion. Takes the model attribute name and conversion configuration and returns\n// a proper converter function.\n//\n// @param {String} modelAttributeKey The key of the model attribute to set on a model node.\n// @param {Object|Array.<Object>} config Conversion configuration. It is possible to provide multiple configurations in an array.\n// @param {Boolean} shallow If set to `true` the attribute will be set only on top-level nodes. Otherwise, it will be set\n// on all elements in the range.\nfunction prepareToAttributeConverter( config, shallow ) {\n\tconst matcher = new Matcher( config.view );\n\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst match = matcher.match( data.viewItem );\n\n\t\t// If there is no match, this callback should not do anything.\n\t\tif ( !match ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst modelKey = config.model.key;\n\t\tconst modelValue = typeof config.model.value == 'function' ?\n\t\t\tconfig.model.value( data.viewItem, conversionApi ) : config.model.value;\n\n\t\t// Do not convert if attribute building function returned falsy value.\n\t\tif ( modelValue === null ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( onlyViewNameIsDefined( config.view, data.viewItem ) ) {\n\t\t\tmatch.match.name = true;\n\t\t} else {\n\t\t\t// Do not test or consume `name` consumable.\n\t\t\tdelete match.match.name;\n\t\t}\n\n\t\t// Try to consume appropriate values from consumable values list.\n\t\tif ( !conversionApi.consumable.test( data.viewItem, match.match ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Since we are converting to attribute we need an range on which we will set the attribute.\n\t\t// If the range is not created yet, we will create it.\n\t\tif ( !data.modelRange ) {\n\t\t\t// Convert children and set conversion result as a current data.\n\t\t\tdata = Object.assign( data, conversionApi.convertChildren( data.viewItem, data.modelCursor ) );\n\t\t}\n\n\t\t// Set attribute on current `output`. `Schema` is checked inside this helper function.\n\t\tconst attributeWasSet = setAttributeOn( data.modelRange, { key: modelKey, value: modelValue }, shallow, conversionApi );\n\n\t\tif ( attributeWasSet ) {\n\t\t\tconversionApi.consumable.consume( data.viewItem, match.match );\n\t\t}\n\t};\n}\n\n// Helper function that checks if element name should be consumed in attribute converters.\n//\n// @param {Object} config Conversion view config.\n// @returns {Boolean}\nfunction onlyViewNameIsDefined( viewConfig, viewItem ) {\n\t// https://github.com/ckeditor/ckeditor5-engine/issues/1786\n\tconst configToTest = typeof viewConfig == 'function' ? viewConfig( viewItem ) : viewConfig;\n\n\tif ( typeof configToTest == 'object' && !getViewElementNameFromConfig( configToTest ) ) {\n\t\treturn false;\n\t}\n\n\treturn !configToTest.classes && !configToTest.attributes && !configToTest.styles;\n}\n\n// Helper function for to-model-attribute converter. Sets model attribute on given range. Checks {@link module:engine/model/schema~Schema}\n// to ensure proper model structure.\n//\n// @param {module:engine/model/range~Range} modelRange Model range on which attribute should be set.\n// @param {Object} modelAttribute Model attribute to set.\n// @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion API.\n// @param {Boolean} shallow If set to `true` the attribute will be set only on top-level nodes. Otherwise, it will be set\n// on all elements in the range.\n// @returns {Boolean} `true` if attribute was set on at least one node from given `modelRange`.\nfunction setAttributeOn( modelRange, modelAttribute, shallow, conversionApi ) {\n\tlet result = false;\n\n\t// Set attribute on each item in range according to Schema.\n\tfor ( const node of Array.from( modelRange.getItems( { shallow } ) ) ) {\n\t\tif ( conversionApi.schema.checkAttribute( node, modelAttribute.key ) ) {\n\t\t\tconversionApi.writer.setAttribute( modelAttribute.key, modelAttribute.value, node );\n\n\t\t\tresult = true;\n\t\t}\n\t}\n\n\treturn result;\n}\n\n// Helper function for upcasting-to-marker conversion. Takes the config in a format requested by `upcastElementToMarker()`\n// function and converts it to a format that is supported by `upcastElementToElement()` function.\n//\n// @param {Object} config Conversion configuration.\nfunction normalizeElementToMarkerConfig( config ) {\n\tconst oldModel = config.model;\n\n\tconfig.model = ( viewElement, conversionApi ) => {\n\t\tconst markerName = typeof oldModel == 'string' ? oldModel : oldModel( viewElement, conversionApi );\n\n\t\treturn conversionApi.writer.createElement( '$marker', { 'data-name': markerName } );\n\t};\n}\n\n// Helper function for upcasting-to-marker conversion. Takes the config in a format requested by `upcastDataToMarker()`\n// function and converts it to a format that is supported by `upcastElementToElement()` function.\n//\n// @param {Object} config Conversion configuration.\nfunction normalizeDataToMarkerConfig( config, type ) {\n\tconst configForElements = {};\n\n\t// Upcast <markerGroup-start> and <markerGroup-end> elements.\n\tconfigForElements.view = config.view + '-' + type;\n\n\tconfigForElements.model = ( viewElement, conversionApi ) => {\n\t\tconst viewName = viewElement.getAttribute( 'name' );\n\t\tconst markerName = config.model( viewName, conversionApi );\n\n\t\treturn conversionApi.writer.createElement( '$marker', { 'data-name': markerName } );\n\t};\n\n\treturn configForElements;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/controller/editingcontroller\n */\n\nimport RootEditableElement from '../view/rooteditableelement';\nimport View from '../view/view';\nimport Mapper from '../conversion/mapper';\nimport DowncastDispatcher from '../conversion/downcastdispatcher';\nimport { clearAttributes, convertCollapsedSelection, convertRangeSelection, insertText, remove } from '../conversion/downcasthelpers';\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport { convertSelectionChange } from '../conversion/upcasthelpers';\n\n// @if CK_DEBUG_ENGINE // const { dumpTrees, initDocumentDumping } = require( '../dev-utils/utils' );\n\n/**\n * Controller for the editing pipeline. The editing pipeline controls {@link ~EditingController#model model} rendering,\n * including selection handling. It also creates the {@link ~EditingController#view view} which builds a\n * browser-independent virtualization over the DOM elements. The editing controller also attaches default converters.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class EditingController {\n\t/**\n\t * Creates an editing controller instance.\n\t *\n\t * @param {module:engine/model/model~Model} model Editing model.\n\t * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor The styles processor instance.\n\t */\n\tconstructor( model, stylesProcessor ) {\n\t\t/**\n\t\t * Editor model.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/model~Model}\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * Editing view controller.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/view~View}\n\t\t */\n\t\tthis.view = new View( stylesProcessor );\n\n\t\t/**\n\t\t * Mapper which describes the model-view binding.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/mapper~Mapper}\n\t\t */\n\t\tthis.mapper = new Mapper();\n\n\t\t/**\n\t\t * Downcast dispatcher that converts changes from the model to {@link #view the editing view}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/downcastdispatcher~DowncastDispatcher} #downcastDispatcher\n\t\t */\n\t\tthis.downcastDispatcher = new DowncastDispatcher( {\n\t\t\tmapper: this.mapper,\n\t\t\tschema: model.schema\n\t\t} );\n\n\t\tconst doc = this.model.document;\n\t\tconst selection = doc.selection;\n\t\tconst markers = this.model.markers;\n\n\t\t// When plugins listen on model changes (on selection change, post fixers, etc.) and change the view as a result of\n\t\t// model's change, they might trigger view rendering before the conversion is completed (e.g. before the selection\n\t\t// is converted). We disable rendering for the length of the outermost model change() block to prevent that.\n\t\t//\n\t\t// See https://github.com/ckeditor/ckeditor5-engine/issues/1528\n\t\tthis.listenTo( this.model, '_beforeChanges', () => {\n\t\t\tthis.view._disableRendering( true );\n\t\t}, { priority: 'highest' } );\n\n\t\tthis.listenTo( this.model, '_afterChanges', () => {\n\t\t\tthis.view._disableRendering( false );\n\t\t}, { priority: 'lowest' } );\n\n\t\t// Whenever model document is changed, convert those changes to the view (using model.Document#differ).\n\t\t// Do it on 'low' priority, so changes are converted after other listeners did their job.\n\t\t// Also convert model selection.\n\t\tthis.listenTo( doc, 'change', () => {\n\t\t\tthis.view.change( writer => {\n\t\t\t\tthis.downcastDispatcher.convertChanges( doc.differ, markers, writer );\n\t\t\t\tthis.downcastDispatcher.convertSelection( selection, markers, writer );\n\t\t\t} );\n\t\t}, { priority: 'low' } );\n\n\t\t// Convert selection from the view to the model when it changes in the view.\n\t\tthis.listenTo( this.view.document, 'selectionChange', convertSelectionChange( this.model, this.mapper ) );\n\n\t\t// Attach default model converters.\n\t\tthis.downcastDispatcher.on( 'insert:$text', insertText(), { priority: 'lowest' } );\n\t\tthis.downcastDispatcher.on( 'remove', remove(), { priority: 'low' } );\n\n\t\t// Attach default model selection converters.\n\t\tthis.downcastDispatcher.on( 'selection', clearAttributes(), { priority: 'low' } );\n\t\tthis.downcastDispatcher.on( 'selection', convertRangeSelection(), { priority: 'low' } );\n\t\tthis.downcastDispatcher.on( 'selection', convertCollapsedSelection(), { priority: 'low' } );\n\n\t\t// Binds {@link module:engine/view/document~Document#roots view roots collection} to\n\t\t// {@link module:engine/model/document~Document#roots model roots collection} so creating\n\t\t// model root automatically creates corresponding view root.\n\t\tthis.view.document.roots.bindTo( this.model.document.roots ).using( root => {\n\t\t\t// $graveyard is a special root that has no reflection in the view.\n\t\t\tif ( root.rootName == '$graveyard' ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst viewRoot = new RootEditableElement( this.view.document, root.name );\n\n\t\t\tviewRoot.rootName = root.rootName;\n\t\t\tthis.mapper.bindElements( root, viewRoot );\n\n\t\t\treturn viewRoot;\n\t\t} );\n\n\t\t// @if CK_DEBUG_ENGINE // initDocumentDumping( this.model.document );\n\t\t// @if CK_DEBUG_ENGINE // initDocumentDumping( this.view.document );\n\n\t\t// @if CK_DEBUG_ENGINE // dumpTrees( this.model.document, this.model.document.version );\n\t\t// @if CK_DEBUG_ENGINE // dumpTrees( this.view.document, this.model.document.version );\n\n\t\t// @if CK_DEBUG_ENGINE // this.model.document.on( 'change', () => {\n\t\t// @if CK_DEBUG_ENGINE //\tdumpTrees( this.view.document, this.model.document.version );\n\t\t// @if CK_DEBUG_ENGINE // }, { priority: 'lowest' } );\n\t}\n\n\t/**\n\t * Removes all event listeners attached to the `EditingController`. Destroys all objects created\n\t * by `EditingController` that need to be destroyed.\n\t */\n\tdestroy() {\n\t\tthis.view.destroy();\n\t\tthis.stopListening();\n\t}\n}\n\nmix( EditingController, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module core/commandcollection\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Collection of commands. Its instance is available in {@link module:core/editor/editor~Editor#commands `editor.commands`}.\n */\nexport default class CommandCollection {\n\t/**\n\t * Creates collection instance.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Command map.\n\t\t *\n\t\t * @private\n\t\t * @member {Map}\n\t\t */\n\t\tthis._commands = new Map();\n\t}\n\n\t/**\n\t * Registers a new command.\n\t *\n\t * @param {String} commandName The name of the command.\n\t * @param {module:core/command~Command} command\n\t */\n\tadd( commandName, command ) {\n\t\tthis._commands.set( commandName, command );\n\t}\n\n\t/**\n\t * Retrieves a command from the collection.\n\t *\n\t * @param {String} commandName The name of the command.\n\t * @returns {module:core/command~Command}\n\t */\n\tget( commandName ) {\n\t\treturn this._commands.get( commandName );\n\t}\n\n\t/**\n\t * Executes a command.\n\t *\n\t * @param {String} commandName The name of the command.\n\t * @param {*} [...commandParams] Command parameters.\n\t * @returns {*} The value returned by the {@link module:core/command~Command#execute `command.execute()`}.\n\t */\n\texecute( commandName, ...args ) {\n\t\tconst command = this.get( commandName );\n\n\t\tif ( !command ) {\n\t\t\t/**\n\t\t\t * Command does not exist.\n\t\t\t *\n\t\t\t * @error commandcollection-command-not-found\n\t\t\t * @param {String} commandName Name of the command.\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'commandcollection-command-not-found', this, { commandName } );\n\t\t}\n\n\t\treturn command.execute( ...args );\n\t}\n\n\t/**\n\t * Returns iterator of command names.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\t* names() {\n\t\tyield* this._commands.keys();\n\t}\n\n\t/**\n\t * Returns iterator of command instances.\n\t *\n\t * @returns {Iterable.<module:core/command~Command>}\n\t */\n\t* commands() {\n\t\tyield* this._commands.values();\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Returns `[ commandName, commandInstance ]` pairs.\n\t *\n\t * @returns {Iterable.<Array>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._commands[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Destroys all collection commands.\n\t */\n\tdestroy() {\n\t\tfor ( const command of this.commands() ) {\n\t\t\tcommand.destroy();\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/conversion/viewconsumable\n */\n\nimport { isArray } from 'lodash-es';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Class used for handling consumption of view {@link module:engine/view/element~Element elements},\n * {@link module:engine/view/text~Text text nodes} and {@link module:engine/view/documentfragment~DocumentFragment document fragments}.\n * Element's name and its parts (attributes, classes and styles) can be consumed separately. Consuming an element's name\n * does not consume its attributes, classes and styles.\n * To add items for consumption use {@link module:engine/conversion/viewconsumable~ViewConsumable#add add method}.\n * To test items use {@link module:engine/conversion/viewconsumable~ViewConsumable#test test method}.\n * To consume items use {@link module:engine/conversion/viewconsumable~ViewConsumable#consume consume method}.\n * To revert already consumed items use {@link module:engine/conversion/viewconsumable~ViewConsumable#revert revert method}.\n *\n *\t\tviewConsumable.add( element, { name: true } ); // Adds element's name as ready to be consumed.\n *\t\tviewConsumable.add( textNode ); // Adds text node for consumption.\n *\t\tviewConsumable.add( docFragment ); // Adds document fragment for consumption.\n *\t\tviewConsumable.test( element, { name: true }  ); // Tests if element's name can be consumed.\n *\t\tviewConsumable.test( textNode ); // Tests if text node can be consumed.\n *\t\tviewConsumable.test( docFragment ); // Tests if document fragment can be consumed.\n *\t\tviewConsumable.consume( element, { name: true }  ); // Consume element's name.\n *\t\tviewConsumable.consume( textNode ); // Consume text node.\n *\t\tviewConsumable.consume( docFragment ); // Consume document fragment.\n *\t\tviewConsumable.revert( element, { name: true }  ); // Revert already consumed element's name.\n *\t\tviewConsumable.revert( textNode ); // Revert already consumed text node.\n *\t\tviewConsumable.revert( docFragment ); // Revert already consumed document fragment.\n */\nexport default class ViewConsumable {\n\t/**\n\t * Creates new ViewConsumable.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Map of consumable elements. If {@link module:engine/view/element~Element element} is used as a key,\n\t\t * {@link module:engine/conversion/viewconsumable~ViewElementConsumables ViewElementConsumables} instance is stored as value.\n\t\t * For {@link module:engine/view/text~Text text nodes} and\n\t\t * {@link module:engine/view/documentfragment~DocumentFragment document fragments} boolean value is stored as value.\n\t\t *\n\t\t * @protected\n\t\t * @member {Map.<module:engine/conversion/viewconsumable~ViewElementConsumables|Boolean>}\n\t\t*/\n\t\tthis._consumables = new Map();\n\t}\n\n\t/**\n\t * Adds {@link module:engine/view/element~Element view element}, {@link module:engine/view/text~Text text node} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment document fragment} as ready to be consumed.\n\t *\n\t *\t\tviewConsumable.add( p, { name: true } ); // Adds element's name to consume.\n\t *\t\tviewConsumable.add( p, { attributes: 'name' } ); // Adds element's attribute.\n\t *\t\tviewConsumable.add( p, { classes: 'foobar' } ); // Adds element's class.\n\t *\t\tviewConsumable.add( p, { styles: 'color' } ); // Adds element's style\n\t *\t\tviewConsumable.add( p, { attributes: 'name', styles: 'color' } ); // Adds attribute and style.\n\t *\t\tviewConsumable.add( p, { classes: [ 'baz', 'bar' ] } ); // Multiple consumables can be provided.\n\t *\t\tviewConsumable.add( textNode ); // Adds text node to consume.\n\t *\t\tviewConsumable.add( docFragment ); // Adds document fragment to consume.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `viewconsumable-invalid-attribute` when `class` or `style`\n\t * attribute is provided - it should be handled separately by providing actual style/class.\n\t *\n\t *\t\tviewConsumable.add( p, { attributes: 'style' } ); // This call will throw an exception.\n\t *\t\tviewConsumable.add( p, { styles: 'color' } ); // This is properly handled style.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/text~Text|module:engine/view/documentfragment~DocumentFragment} element\n\t * @param {Object} [consumables] Used only if first parameter is {@link module:engine/view/element~Element view element} instance.\n\t * @param {Boolean} consumables.name If set to true element's name will be included.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names.\n\t */\n\tadd( element, consumables ) {\n\t\tlet elementConsumables;\n\n\t\t// For text nodes and document fragments just mark them as consumable.\n\t\tif ( element.is( '$text' ) || element.is( 'documentFragment' ) ) {\n\t\t\tthis._consumables.set( element, true );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// For elements create new ViewElementConsumables or update already existing one.\n\t\tif ( !this._consumables.has( element ) ) {\n\t\t\telementConsumables = new ViewElementConsumables( element );\n\t\t\tthis._consumables.set( element, elementConsumables );\n\t\t} else {\n\t\t\telementConsumables = this._consumables.get( element );\n\t\t}\n\n\t\telementConsumables.add( consumables );\n\t}\n\n\t/**\n\t * Tests if {@link module:engine/view/element~Element view element}, {@link module:engine/view/text~Text text node} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment document fragment} can be consumed.\n\t * It returns `true` when all items included in method's call can be consumed. Returns `false` when\n\t * first already consumed item is found and `null` when first non-consumable item is found.\n\t *\n\t *\t\tviewConsumable.test( p, { name: true } ); // Tests element's name.\n\t *\t\tviewConsumable.test( p, { attributes: 'name' } ); // Tests attribute.\n\t *\t\tviewConsumable.test( p, { classes: 'foobar' } ); // Tests class.\n\t *\t\tviewConsumable.test( p, { styles: 'color' } ); // Tests style.\n\t *\t\tviewConsumable.test( p, { attributes: 'name', styles: 'color' } ); // Tests attribute and style.\n\t *\t\tviewConsumable.test( p, { classes: [ 'baz', 'bar' ] } ); // Multiple consumables can be tested.\n\t *\t\tviewConsumable.test( textNode ); // Tests text node.\n\t *\t\tviewConsumable.test( docFragment ); // Tests document fragment.\n\t *\n\t * Testing classes and styles as attribute will test if all added classes/styles can be consumed.\n\t *\n\t *\t\tviewConsumable.test( p, { attributes: 'class' } ); // Tests if all added classes can be consumed.\n\t *\t\tviewConsumable.test( p, { attributes: 'style' } ); // Tests if all added styles can be consumed.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/text~Text|module:engine/view/documentfragment~DocumentFragment} element\n\t * @param {Object} [consumables] Used only if first parameter is {@link module:engine/view/element~Element view element} instance.\n\t * @param {Boolean} consumables.name If set to true element's name will be included.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names.\n\t * @returns {Boolean|null} Returns `true` when all items included in method's call can be consumed. Returns `false`\n\t * when first already consumed item is found and `null` when first non-consumable item is found.\n\t */\n\ttest( element, consumables ) {\n\t\tconst elementConsumables = this._consumables.get( element );\n\n\t\tif ( elementConsumables === undefined ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// For text nodes and document fragments return stored boolean value.\n\t\tif ( element.is( '$text' ) || element.is( 'documentFragment' ) ) {\n\t\t\treturn elementConsumables;\n\t\t}\n\n\t\t// For elements test consumables object.\n\t\treturn elementConsumables.test( consumables );\n\t}\n\n\t/**\n\t * Consumes {@link module:engine/view/element~Element view element}, {@link module:engine/view/text~Text text node} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment document fragment}.\n\t * It returns `true` when all items included in method's call can be consumed, otherwise returns `false`.\n\t *\n\t *\t\tviewConsumable.consume( p, { name: true } ); // Consumes element's name.\n\t *\t\tviewConsumable.consume( p, { attributes: 'name' } ); // Consumes element's attribute.\n\t *\t\tviewConsumable.consume( p, { classes: 'foobar' } ); // Consumes element's class.\n\t *\t\tviewConsumable.consume( p, { styles: 'color' } ); // Consumes element's style.\n\t *\t\tviewConsumable.consume( p, { attributes: 'name', styles: 'color' } ); // Consumes attribute and style.\n\t *\t\tviewConsumable.consume( p, { classes: [ 'baz', 'bar' ] } ); // Multiple consumables can be consumed.\n\t *\t\tviewConsumable.consume( textNode ); // Consumes text node.\n\t *\t\tviewConsumable.consume( docFragment ); // Consumes document fragment.\n\t *\n\t * Consuming classes and styles as attribute will test if all added classes/styles can be consumed.\n\t *\n\t *\t\tviewConsumable.consume( p, { attributes: 'class' } ); // Consume only if all added classes can be consumed.\n\t *\t\tviewConsumable.consume( p, { attributes: 'style' } ); // Consume only if all added styles can be consumed.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/text~Text|module:engine/view/documentfragment~DocumentFragment} element\n\t * @param {Object} [consumables] Used only if first parameter is {@link module:engine/view/element~Element view element} instance.\n\t * @param {Boolean} consumables.name If set to true element's name will be included.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names.\n\t * @returns {Boolean} Returns `true` when all items included in method's call can be consumed,\n\t * otherwise returns `false`.\n\t */\n\tconsume( element, consumables ) {\n\t\tif ( this.test( element, consumables ) ) {\n\t\t\tif ( element.is( '$text' ) || element.is( 'documentFragment' ) ) {\n\t\t\t\t// For text nodes and document fragments set value to false.\n\t\t\t\tthis._consumables.set( element, false );\n\t\t\t} else {\n\t\t\t\t// For elements - consume consumables object.\n\t\t\t\tthis._consumables.get( element ).consume( consumables );\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Reverts {@link module:engine/view/element~Element view element}, {@link module:engine/view/text~Text text node} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment document fragment} so they can be consumed once again.\n\t * Method does not revert items that were never previously added for consumption, even if they are included in\n\t * method's call.\n\t *\n\t *\t\tviewConsumable.revert( p, { name: true } ); // Reverts element's name.\n\t *\t\tviewConsumable.revert( p, { attributes: 'name' } ); // Reverts element's attribute.\n\t *\t\tviewConsumable.revert( p, { classes: 'foobar' } ); // Reverts element's class.\n\t *\t\tviewConsumable.revert( p, { styles: 'color' } ); // Reverts element's style.\n\t *\t\tviewConsumable.revert( p, { attributes: 'name', styles: 'color' } ); // Reverts attribute and style.\n\t *\t\tviewConsumable.revert( p, { classes: [ 'baz', 'bar' ] } ); // Multiple names can be reverted.\n\t *\t\tviewConsumable.revert( textNode ); // Reverts text node.\n\t *\t\tviewConsumable.revert( docFragment ); // Reverts document fragment.\n\t *\n\t * Reverting classes and styles as attribute will revert all classes/styles that were previously added for\n\t * consumption.\n\t *\n\t *\t\tviewConsumable.revert( p, { attributes: 'class' } ); // Reverts all classes added for consumption.\n\t *\t\tviewConsumable.revert( p, { attributes: 'style' } ); // Reverts all styles added for consumption.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/text~Text|module:engine/view/documentfragment~DocumentFragment} element\n\t * @param {Object} [consumables] Used only if first parameter is {@link module:engine/view/element~Element view element} instance.\n\t * @param {Boolean} consumables.name If set to true element's name will be included.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names.\n\t */\n\trevert( element, consumables ) {\n\t\tconst elementConsumables = this._consumables.get( element );\n\n\t\tif ( elementConsumables !== undefined ) {\n\t\t\tif ( element.is( '$text' ) || element.is( 'documentFragment' ) ) {\n\t\t\t\t// For text nodes and document fragments - set consumable to true.\n\t\t\t\tthis._consumables.set( element, true );\n\t\t\t} else {\n\t\t\t\t// For elements - revert items from consumables object.\n\t\t\t\telementConsumables.revert( consumables );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates consumable object from {@link module:engine/view/element~Element view element}. Consumable object will include\n\t * element's name and all its attributes, classes and styles.\n\t *\n\t * @static\n\t * @param {module:engine/view/element~Element} element\n\t * @returns {Object} consumables\n\t */\n\tstatic consumablesFromElement( element ) {\n\t\tconst consumables = {\n\t\t\telement,\n\t\t\tname: true,\n\t\t\tattributes: [],\n\t\t\tclasses: [],\n\t\t\tstyles: []\n\t\t};\n\n\t\tconst attributes = element.getAttributeKeys();\n\n\t\tfor ( const attribute of attributes ) {\n\t\t\t// Skip classes and styles - will be added separately.\n\t\t\tif ( attribute == 'style' || attribute == 'class' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconsumables.attributes.push( attribute );\n\t\t}\n\n\t\tconst classes = element.getClassNames();\n\n\t\tfor ( const className of classes ) {\n\t\t\tconsumables.classes.push( className );\n\t\t}\n\n\t\tconst styles = element.getStyleNames();\n\n\t\tfor ( const style of styles ) {\n\t\t\tconsumables.styles.push( style );\n\t\t}\n\n\t\treturn consumables;\n\t}\n\n\t/**\n\t * Creates {@link module:engine/conversion/viewconsumable~ViewConsumable ViewConsumable} instance from\n\t * {@link module:engine/view/node~Node node} or {@link module:engine/view/documentfragment~DocumentFragment document fragment}.\n\t * Instance will contain all elements, child nodes, attributes, styles and classes added for consumption.\n\t *\n\t * @static\n\t * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} from View node or document fragment\n\t * from which `ViewConsumable` will be created.\n\t * @param {module:engine/conversion/viewconsumable~ViewConsumable} [instance] If provided, given `ViewConsumable` instance will be used\n\t * to add all consumables. It will be returned instead of a new instance.\n\t */\n\tstatic createFrom( from, instance ) {\n\t\tif ( !instance ) {\n\t\t\tinstance = new ViewConsumable( from );\n\t\t}\n\n\t\tif ( from.is( '$text' ) ) {\n\t\t\tinstance.add( from );\n\n\t\t\treturn instance;\n\t\t}\n\n\t\t// Add `from` itself, if it is an element.\n\t\tif ( from.is( 'element' ) ) {\n\t\t\tinstance.add( from, ViewConsumable.consumablesFromElement( from ) );\n\t\t}\n\n\t\tif ( from.is( 'documentFragment' ) ) {\n\t\t\tinstance.add( from );\n\t\t}\n\n\t\tfor ( const child of from.getChildren() ) {\n\t\t\tinstance = ViewConsumable.createFrom( child, instance );\n\t\t}\n\n\t\treturn instance;\n\t}\n}\n\n/**\n * This is a private helper-class for {@link module:engine/conversion/viewconsumable~ViewConsumable}.\n * It represents and manipulates consumable parts of a single {@link module:engine/view/element~Element}.\n *\n * @private\n */\nclass ViewElementConsumables {\n\t/**\n\t * Creates ViewElementConsumables instance.\n\t *\n\t * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} from View node or document fragment\n\t * from which `ViewElementConsumables` is being created.\n\t */\n\tconstructor( from ) {\n\t\t/**\n\t\t * @readonly\n\t\t * @member {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment}\n\t\t */\n\t\tthis.element = from;\n\n\t\t/**\n\t\t * Flag indicating if name of the element can be consumed.\n\t\t *\n\t\t * @private\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._canConsumeName = null;\n\n\t\t/**\n\t\t * Contains maps of element's consumables: attributes, classes and styles.\n\t\t *\n\t\t * @private\n\t\t * @member {Object}\n\t\t */\n\t\tthis._consumables = {\n\t\t\tattributes: new Map(),\n\t\t\tstyles: new Map(),\n\t\t\tclasses: new Map()\n\t\t};\n\t}\n\n\t/**\n\t * Adds consumable parts of the {@link module:engine/view/element~Element view element}.\n\t * Element's name itself can be marked to be consumed (when element's name is consumed its attributes, classes and\n\t * styles still could be consumed):\n\t *\n\t *\t\tconsumables.add( { name: true } );\n\t *\n\t * Attributes classes and styles:\n\t *\n\t *\t\tconsumables.add( { attributes: 'title', classes: 'foo', styles: 'color' } );\n\t *\t\tconsumables.add( { attributes: [ 'title', 'name' ], classes: [ 'foo', 'bar' ] );\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `viewconsumable-invalid-attribute` when `class` or `style`\n\t * attribute is provided - it should be handled separately by providing `style` and `class` in consumables object.\n\t *\n\t * @param {Object} consumables Object describing which parts of the element can be consumed.\n\t * @param {Boolean} consumables.name If set to `true` element's name will be added as consumable.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names to add as consumable.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names to add as consumable.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names to add as consumable.\n\t */\n\tadd( consumables ) {\n\t\tif ( consumables.name ) {\n\t\t\tthis._canConsumeName = true;\n\t\t}\n\n\t\tfor ( const type in this._consumables ) {\n\t\t\tif ( type in consumables ) {\n\t\t\t\tthis._add( type, consumables[ type ] );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Tests if parts of the {@link module:engine/view/node~Node view node} can be consumed.\n\t *\n\t * Element's name can be tested:\n\t *\n\t *\t\tconsumables.test( { name: true } );\n\t *\n\t * Attributes classes and styles:\n\t *\n\t *\t\tconsumables.test( { attributes: 'title', classes: 'foo', styles: 'color' } );\n\t *\t\tconsumables.test( { attributes: [ 'title', 'name' ], classes: [ 'foo', 'bar' ] );\n\t *\n\t * @param {Object} consumables Object describing which parts of the element should be tested.\n\t * @param {Boolean} consumables.name If set to `true` element's name will be tested.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names to test.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names to test.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names to test.\n\t * @returns {Boolean|null} `true` when all tested items can be consumed, `null` when even one of the items\n\t * was never marked for consumption and `false` when even one of the items was already consumed.\n\t */\n\ttest( consumables ) {\n\t\t// Check if name can be consumed.\n\t\tif ( consumables.name && !this._canConsumeName ) {\n\t\t\treturn this._canConsumeName;\n\t\t}\n\n\t\tfor ( const type in this._consumables ) {\n\t\t\tif ( type in consumables ) {\n\t\t\t\tconst value = this._test( type, consumables[ type ] );\n\n\t\t\t\tif ( value !== true ) {\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Return true only if all can be consumed.\n\t\treturn true;\n\t}\n\n\t/**\n\t * Consumes parts of {@link module:engine/view/element~Element view element}. This function does not check if consumable item\n\t * is already consumed - it consumes all consumable items provided.\n\t * Element's name can be consumed:\n\t *\n\t *\t\tconsumables.consume( { name: true } );\n\t *\n\t * Attributes classes and styles:\n\t *\n\t *\t\tconsumables.consume( { attributes: 'title', classes: 'foo', styles: 'color' } );\n\t *\t\tconsumables.consume( { attributes: [ 'title', 'name' ], classes: [ 'foo', 'bar' ] );\n\t *\n\t * @param {Object} consumables Object describing which parts of the element should be consumed.\n\t * @param {Boolean} consumables.name If set to `true` element's name will be consumed.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names to consume.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names to consume.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names to consume.\n\t */\n\tconsume( consumables ) {\n\t\tif ( consumables.name ) {\n\t\t\tthis._canConsumeName = false;\n\t\t}\n\n\t\tfor ( const type in this._consumables ) {\n\t\t\tif ( type in consumables ) {\n\t\t\t\tthis._consume( type, consumables[ type ] );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Revert already consumed parts of {@link module:engine/view/element~Element view Element}, so they can be consumed once again.\n\t * Element's name can be reverted:\n\t *\n\t *\t\tconsumables.revert( { name: true } );\n\t *\n\t * Attributes classes and styles:\n\t *\n\t *\t\tconsumables.revert( { attributes: 'title', classes: 'foo', styles: 'color' } );\n\t *\t\tconsumables.revert( { attributes: [ 'title', 'name' ], classes: [ 'foo', 'bar' ] );\n\t *\n\t * @param {Object} consumables Object describing which parts of the element should be reverted.\n\t * @param {Boolean} consumables.name If set to `true` element's name will be reverted.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names to revert.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names to revert.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names to revert.\n\t */\n\trevert( consumables ) {\n\t\tif ( consumables.name ) {\n\t\t\tthis._canConsumeName = true;\n\t\t}\n\n\t\tfor ( const type in this._consumables ) {\n\t\t\tif ( type in consumables ) {\n\t\t\t\tthis._revert( type, consumables[ type ] );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Helper method that adds consumables of a given type: attribute, class or style.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `viewconsumable-invalid-attribute` when `class` or `style`\n\t * type is provided - it should be handled separately by providing actual style/class type.\n\t *\n\t * @private\n\t * @param {String} type Type of the consumable item: `attributes`, `classes` or `styles`.\n\t * @param {String|Array.<String>} item Consumable item or array of items.\n\t */\n\t_add( type, item ) {\n\t\tconst items = isArray( item ) ? item : [ item ];\n\t\tconst consumables = this._consumables[ type ];\n\n\t\tfor ( const name of items ) {\n\t\t\tif ( type === 'attributes' && ( name === 'class' || name === 'style' ) ) {\n\t\t\t\t/**\n\t\t\t\t * Class and style attributes should be handled separately in\n\t\t\t\t * {@link module:engine/conversion/viewconsumable~ViewConsumable#add `ViewConsumable#add()`}.\n\t\t\t\t *\n\t\t\t\t * What you have done is trying to use:\n\t\t\t\t *\n\t\t\t\t *\t\tconsumables.add( { attributes: [ 'class', 'style' ] } );\n\t\t\t\t *\n\t\t\t\t * While each class and style should be registered separately:\n\t\t\t\t *\n\t\t\t\t *\t\tconsumables.add( { classes: 'some-class', styles: 'font-weight' } );\n\t\t\t\t *\n\t\t\t\t * @error viewconsumable-invalid-attribute\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'viewconsumable-invalid-attribute', this );\n\t\t\t}\n\n\t\t\tconsumables.set( name, true );\n\n\t\t\tif ( type === 'styles' ) {\n\t\t\t\tfor ( const alsoName of this.element.document.stylesProcessor.getRelatedStyles( name ) ) {\n\t\t\t\t\tconsumables.set( alsoName, true );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Helper method that tests consumables of a given type: attribute, class or style.\n\t *\n\t * @private\n\t * @param {String} type Type of the consumable item: `attributes`, `classes` or `styles`.\n\t * @param {String|Array.<String>} item Consumable item or array of items.\n\t * @returns {Boolean|null} Returns `true` if all items can be consumed, `null` when one of the items cannot be\n\t * consumed and `false` when one of the items is already consumed.\n\t */\n\t_test( type, item ) {\n\t\tconst items = isArray( item ) ? item : [ item ];\n\t\tconst consumables = this._consumables[ type ];\n\n\t\tfor ( const name of items ) {\n\t\t\tif ( type === 'attributes' && ( name === 'class' || name === 'style' ) ) {\n\t\t\t\tconst consumableName = name == 'class' ? 'classes' : 'styles';\n\n\t\t\t\t// Check all classes/styles if class/style attribute is tested.\n\t\t\t\tconst value = this._test( consumableName, [ ...this._consumables[ consumableName ].keys() ] );\n\n\t\t\t\tif ( value !== true ) {\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst value = consumables.get( name );\n\t\t\t\t// Return null if attribute is not found.\n\t\t\t\tif ( value === undefined ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tif ( !value ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Helper method that consumes items of a given type: attribute, class or style.\n\t *\n\t * @private\n\t * @param {String} type Type of the consumable item: `attributes`, `classes` or `styles`.\n\t * @param {String|Array.<String>} item Consumable item or array of items.\n\t */\n\t_consume( type, item ) {\n\t\tconst items = isArray( item ) ? item : [ item ];\n\t\tconst consumables = this._consumables[ type ];\n\n\t\tfor ( const name of items ) {\n\t\t\tif ( type === 'attributes' && ( name === 'class' || name === 'style' ) ) {\n\t\t\t\tconst consumableName = name == 'class' ? 'classes' : 'styles';\n\n\t\t\t\t// If class or style is provided for consumption - consume them all.\n\t\t\t\tthis._consume( consumableName, [ ...this._consumables[ consumableName ].keys() ] );\n\t\t\t} else {\n\t\t\t\tconsumables.set( name, false );\n\n\t\t\t\tif ( type == 'styles' ) {\n\t\t\t\t\tfor ( const toConsume of this.element.document.stylesProcessor.getRelatedStyles( name ) ) {\n\t\t\t\t\t\tconsumables.set( toConsume, false );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Helper method that reverts items of a given type: attribute, class or style.\n\t *\n\t * @private\n\t * @param {String} type Type of the consumable item: `attributes`, `classes` or , `styles`.\n\t * @param {String|Array.<String>} item Consumable item or array of items.\n\t */\n\t_revert( type, item ) {\n\t\tconst items = isArray( item ) ? item : [ item ];\n\t\tconst consumables = this._consumables[ type ];\n\n\t\tfor ( const name of items ) {\n\t\t\tif ( type === 'attributes' && ( name === 'class' || name === 'style' ) ) {\n\t\t\t\tconst consumableName = name == 'class' ? 'classes' : 'styles';\n\n\t\t\t\t// If class or style is provided for reverting - revert them all.\n\t\t\t\tthis._revert( consumableName, [ ...this._consumables[ consumableName ].keys() ] );\n\t\t\t} else {\n\t\t\t\tconst value = consumables.get( name );\n\n\t\t\t\tif ( value === false ) {\n\t\t\t\t\tconsumables.set( name, true );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/schema\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\nimport Range from './range';\nimport Position from './position';\nimport Element from './element';\nimport Text from './text';\nimport TreeWalker from './treewalker';\n\n/**\n * The model's schema. It defines allowed and disallowed structures of nodes as well as nodes' attributes.\n * The schema is usually defined by features and based on them the editing framework and features\n * make decisions how to change and process the model.\n *\n * The instance of schema is available in {@link module:engine/model/model~Model#schema `editor.model.schema`}.\n *\n * Read more about the schema in:\n *\n * * {@glink framework/guides/architecture/editing-engine#schema Schema} section of the\n * {@glink framework/guides/architecture/editing-engine Introduction to the Editing engine architecture}.\n * * {@glink framework/guides/deep-dive/schema Schema deep dive} guide.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Schema {\n\t/**\n\t * Creates schema instance.\n\t */\n\tconstructor() {\n\t\tthis._sourceDefinitions = {};\n\n\t\t/**\n\t\t * A dictionary containing attribute properties.\n\t\t *\n\t\t * @private\n\t\t * @member {Object.<String,String>}\n\t\t */\n\t\tthis._attributeProperties = {};\n\n\t\tthis.decorate( 'checkChild' );\n\t\tthis.decorate( 'checkAttribute' );\n\n\t\tthis.on( 'checkAttribute', ( evt, args ) => {\n\t\t\targs[ 0 ] = new SchemaContext( args[ 0 ] );\n\t\t}, { priority: 'highest' } );\n\n\t\tthis.on( 'checkChild', ( evt, args ) => {\n\t\t\targs[ 0 ] = new SchemaContext( args[ 0 ] );\n\t\t\targs[ 1 ] = this.getDefinition( args[ 1 ] );\n\t\t}, { priority: 'highest' } );\n\t}\n\n\t/**\n\t * Registers schema item. Can only be called once for every item name.\n\t *\n\t *\t\tschema.register( 'paragraph', {\n\t *\t\t\tinheritAllFrom: '$block'\n\t *\t\t} );\n\t *\n\t * @param {String} itemName\n\t * @param {module:engine/model/schema~SchemaItemDefinition} definition\n\t */\n\tregister( itemName, definition ) {\n\t\tif ( this._sourceDefinitions[ itemName ] ) {\n\t\t\t/**\n\t\t\t * A single item cannot be registered twice in the schema.\n\t\t\t *\n\t\t\t * This situation may happen when:\n\t\t\t *\n\t\t\t * * Two or more plugins called {@link #register `register()`} with the same name. This will usually mean that\n\t\t\t * there is a collision between plugins which try to use the same element in the model. Unfortunately,\n\t\t\t * the only way to solve this is by modifying one of these plugins to use a unique model element name.\n\t\t\t * * A single plugin was loaded twice. This happens when it is installed by npm/yarn in two versions\n\t\t\t * and usually means one or more of the following issues:\n\t\t\t *     * a version mismatch (two of your dependencies require two different versions of this plugin),\n\t\t\t *     * incorrect imports (this plugin is somehow imported twice in a way which confuses webpack),\n\t\t\t *     * mess in `node_modules/` (`rm -rf node_modules/` may help).\n\t\t\t *\n\t\t\t * **Note:** Check the logged `itemName` to better understand which plugin was duplicated/conflicting.\n\t\t\t *\n\t\t\t * @param itemName The name of the model element that is being registered twice.\n\t\t\t * @error schema-cannot-register-item-twice\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'schema-cannot-register-item-twice',\n\t\t\t\tthis,\n\t\t\t\t{\n\t\t\t\t\titemName\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\tthis._sourceDefinitions[ itemName ] = [\n\t\t\tObject.assign( {}, definition )\n\t\t];\n\n\t\tthis._clearCache();\n\t}\n\n\t/**\n\t * Extends a {@link #register registered} item's definition.\n\t *\n\t * Extending properties such as `allowIn` will add more items to the existing properties,\n\t * while redefining properties such as `isBlock` will override the previously defined ones.\n\t *\n\t *\t\tschema.register( 'foo', {\n\t *\t\t\tallowIn: '$root',\n\t *\t\t\tisBlock: true;\n\t *\t\t} );\n\t *\t\tschema.extend( 'foo', {\n\t *\t\t\tallowIn: 'blockQuote',\n\t *\t\t\tisBlock: false\n\t *\t\t} );\n\t *\n\t *\t\tschema.getDefinition( 'foo' );\n\t *\t\t//\t{\n\t *\t\t//\t\tallowIn: [ '$root', 'blockQuote' ],\n\t *\t\t// \t\tisBlock: false\n\t *\t\t//\t}\n\t *\n\t * @param {String} itemName\n\t * @param {module:engine/model/schema~SchemaItemDefinition} definition\n\t */\n\textend( itemName, definition ) {\n\t\tif ( !this._sourceDefinitions[ itemName ] ) {\n\t\t\t/**\n\t\t\t * Cannot extend an item which was not registered yet.\n\t\t\t *\n\t\t\t * This error happens when a plugin tries to extend the schema definition of an item which was not\n\t\t\t * {@link #register registered} yet.\n\t\t\t *\n\t\t\t * @param itemName The name of the model element which is being extended.\n\t\t\t * @error schema-cannot-extend-missing-item\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'schema-cannot-extend-missing-item', this, {\n\t\t\t\titemName\n\t\t\t} );\n\t\t}\n\n\t\tthis._sourceDefinitions[ itemName ].push( Object.assign( {}, definition ) );\n\n\t\tthis._clearCache();\n\t}\n\n\t/**\n\t * Returns data of all registered items.\n\t *\n\t * This method should normally be used for reflection purposes (e.g. defining a clone of a certain element,\n\t * checking a list of all block elements, etc).\n\t * Use specific methods (such as {@link #checkChild `checkChild()`} or {@link #isLimit `isLimit()`})\n\t * in other cases.\n\t *\n\t * @returns {Object.<String,module:engine/model/schema~SchemaCompiledItemDefinition>}\n\t */\n\tgetDefinitions() {\n\t\tif ( !this._compiledDefinitions ) {\n\t\t\tthis._compile();\n\t\t}\n\n\t\treturn this._compiledDefinitions;\n\t}\n\n\t/**\n\t * Returns a definition of the given item or `undefined` if an item is not registered.\n\t *\n\t * This method should normally be used for reflection purposes (e.g. defining a clone of a certain element,\n\t * checking a list of all block elements, etc).\n\t * Use specific methods (such as {@link #checkChild `checkChild()`} or {@link #isLimit `isLimit()`})\n\t * in other cases.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t * @returns {module:engine/model/schema~SchemaCompiledItemDefinition}\n\t */\n\tgetDefinition( item ) {\n\t\tlet itemName;\n\n\t\tif ( typeof item == 'string' ) {\n\t\t\titemName = item;\n\t\t} else if ( item.is && ( item.is( '$text' ) || item.is( '$textProxy' ) ) ) {\n\t\t\titemName = '$text';\n\t\t}\n\t\t// Element or module:engine/model/schema~SchemaContextItem.\n\t\telse {\n\t\t\titemName = item.name;\n\t\t}\n\n\t\treturn this.getDefinitions()[ itemName ];\n\t}\n\n\t/**\n\t * Returns `true` if the given item is registered in the schema.\n\t *\n\t *\t\tschema.isRegistered( 'paragraph' ); // -> true\n\t *\t\tschema.isRegistered( editor.model.document.getRoot() ); // -> true\n\t *\t\tschema.isRegistered( 'foo' ); // -> false\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisRegistered( item ) {\n\t\treturn !!this.getDefinition( item );\n\t}\n\n\t/**\n\t * Returns `true` if the given item is defined to be\n\t * a block by the {@link module:engine/model/schema~SchemaItemDefinition}'s `isBlock` property.\n\t *\n\t *\t\tschema.isBlock( 'paragraph' ); // -> true\n\t *\t\tschema.isBlock( '$root' ); // -> false\n\t *\n\t *\t\tconst paragraphElement = writer.createElement( 'paragraph' );\n\t *\t\tschema.isBlock( paragraphElement ); // -> true\n\t *\n\t * See the {@glink framework/guides/deep-dive/schema#block-elements Block elements} section of the Schema deep dive\n\t * guide for more details.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisBlock( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\treturn !!( def && def.isBlock );\n\t}\n\n\t/**\n\t * Returns `true` if the given item should be treated as a limit element.\n\t *\n\t * It considers an item to be a limit element if its\n\t * {@link module:engine/model/schema~SchemaItemDefinition}'s\n\t * {@link module:engine/model/schema~SchemaItemDefinition#isLimit `isLimit`} or\n\t * {@link module:engine/model/schema~SchemaItemDefinition#isObject `isObject`} property\n\t * was set to `true`.\n\t *\n\t *\t\tschema.isLimit( 'paragraph' ); // -> false\n\t *\t\tschema.isLimit( '$root' ); // -> true\n\t *\t\tschema.isLimit( editor.model.document.getRoot() ); // -> true\n\t *\t\tschema.isLimit( 'image' ); // -> true\n\t *\n\t * See the {@glink framework/guides/deep-dive/schema#limit-elements Limit elements} section of the Schema deep dive\n\t * guide for more details.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisLimit( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !!( def.isLimit || def.isObject );\n\t}\n\n\t/**\n\t * Returns `true` if the given item should be treated as an object element.\n\t *\n\t * It considers an item to be an object element if its\n\t * {@link module:engine/model/schema~SchemaItemDefinition}'s\n\t * {@link module:engine/model/schema~SchemaItemDefinition#isObject `isObject`} property\n\t * was set to `true`.\n\t *\n\t *\t\tschema.isObject( 'paragraph' ); // -> false\n\t *\t\tschema.isObject( 'image' ); // -> true\n\t *\n\t *\t\tconst imageElement = writer.createElement( 'image' );\n\t *\t\tschema.isObject( imageElement ); // -> true\n\t *\n\t * See the {@glink framework/guides/deep-dive/schema#object-elements Object elements} section of the Schema deep dive\n\t * guide for more details.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisObject( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Note: Check out the implementation of #isLimit(), #isSelectable(), and #isContent()\n\t\t// to understand why these three constitute an object.\n\t\treturn !!( def.isObject || ( def.isLimit && def.isSelectable && def.isContent ) );\n\t}\n\n\t/**\n\t * Returns `true` if the given item is defined to be\n\t * an inline element by the {@link module:engine/model/schema~SchemaItemDefinition}'s `isInline` property.\n\t *\n\t *\t\tschema.isInline( 'paragraph' ); // -> false\n\t *\t\tschema.isInline( 'softBreak' ); // -> true\n\t *\n\t *\t\tconst text = writer.createText( 'foo' );\n\t *\t\tschema.isInline( text ); // -> true\n\t *\n\t * See the {@glink framework/guides/deep-dive/schema#inline-elements Inline elements} section of the Schema deep dive\n\t * guide for more details.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisInline( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\treturn !!( def && def.isInline );\n\t}\n\n\t/**\n\t * Returns `true` if the given item is defined to be\n\t * a selectable element by the {@link module:engine/model/schema~SchemaItemDefinition}'s `isSelectable` property.\n\t *\n\t *\t\tschema.isSelectable( 'paragraph' ); // -> false\n\t *\t\tschema.isSelectable( 'heading1' ); // -> false\n\t *\t\tschema.isSelectable( 'image' ); // -> true\n\t *\t\tschema.isSelectable( 'tableCell' ); // -> true\n\t *\n\t *\t\tconst text = writer.createText( 'foo' );\n\t *\t\tschema.isSelectable( text ); // -> false\n\t *\n\t * See the {@glink framework/guides/deep-dive/schema#selectable-elements Selectable elements} section of the Schema deep dive}\n\t * guide for more details.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisSelectable( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !!( def.isSelectable || def.isObject );\n\t}\n\n\t/**\n\t * Returns `true` if the given item is defined to be\n\t * a content by the {@link module:engine/model/schema~SchemaItemDefinition}'s `isContent` property.\n\t *\n\t *\t\tschema.isContent( 'paragraph' ); // -> false\n\t *\t\tschema.isContent( 'heading1' ); // -> false\n\t *\t\tschema.isContent( 'image' ); // -> true\n\t *\t\tschema.isContent( 'horizontalLine' ); // -> true\n\t *\n\t *\t\tconst text = writer.createText( 'foo' );\n\t *\t\tschema.isContent( text ); // -> true\n\t *\n\t * See the {@glink framework/guides/deep-dive/schema#content-elements Content elements} section of the Schema deep dive}\n\t * guide for more details.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisContent( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !!( def.isContent || def.isObject );\n\t}\n\n\t/**\n\t * Checks whether the given node (`child`) can be a child of the given context.\n\t *\n\t *\t\tschema.checkChild( model.document.getRoot(), paragraph ); // -> false\n\t *\n\t *\t\tschema.register( 'paragraph', {\n\t *\t\t\tallowIn: '$root'\n\t *\t\t} );\n\t *\t\tschema.checkChild( model.document.getRoot(), paragraph ); // -> true\n\t *\n\t * Note: When verifying whether the given node can be a child of the given context, the\n\t * schema also verifies the entire context &mdash; from its root to its last element. Therefore, it is possible\n\t * for `checkChild()` to return `false` even though the context's last element can contain the checked child.\n\t * It happens if one of the context's elements does not allow its child.\n\t *\n\t * @fires checkChild\n\t * @param {module:engine/model/schema~SchemaContextDefinition} context The context in which the child will be checked.\n\t * @param {module:engine/model/node~Node|String} def The child to check.\n\t */\n\tcheckChild( context, def ) {\n\t\t// Note: context and child are already normalized here to a SchemaContext and SchemaCompiledItemDefinition.\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this._checkContextMatch( def, context );\n\t}\n\n\t/**\n\t * Checks whether the given attribute can be applied in the given context (on the last\n\t * item of the context).\n\t *\n\t *\t\tschema.checkAttribute( textNode, 'bold' ); // -> false\n\t *\n\t *\t\tschema.extend( '$text', {\n\t *\t\t\tallowAttributes: 'bold'\n\t *\t\t} );\n\t *\t\tschema.checkAttribute( textNode, 'bold' ); // -> true\n\t *\n\t * @fires checkAttribute\n\t * @param {module:engine/model/schema~SchemaContextDefinition} context The context in which the attribute will be checked.\n\t * @param {String} attributeName\n\t */\n\tcheckAttribute( context, attributeName ) {\n\t\tconst def = this.getDefinition( context.last );\n\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn def.allowAttributes.includes( attributeName );\n\t}\n\n\t/**\n\t * Checks whether the given element (`elementToMerge`) can be merged with the specified base element (`positionOrBaseElement`).\n\t *\n\t * In other words &mdash; whether `elementToMerge`'s children {@link #checkChild are allowed} in the `positionOrBaseElement`.\n\t *\n\t * This check ensures that elements merged with {@link module:engine/model/writer~Writer#merge `Writer#merge()`}\n\t * will be valid.\n\t *\n\t * Instead of elements, you can pass the instance of the {@link module:engine/model/position~Position} class as the\n\t * `positionOrBaseElement`. It means that the elements before and after the position will be checked whether they can be merged.\n\t *\n\t * @param {module:engine/model/position~Position|module:engine/model/element~Element} positionOrBaseElement The position or base\n\t * element to which the `elementToMerge` will be merged.\n\t * @param {module:engine/model/element~Element} elementToMerge The element to merge. Required if `positionOrBaseElement` is an element.\n\t * @returns {Boolean}\n\t */\n\tcheckMerge( positionOrBaseElement, elementToMerge = null ) {\n\t\tif ( positionOrBaseElement instanceof Position ) {\n\t\t\tconst nodeBefore = positionOrBaseElement.nodeBefore;\n\t\t\tconst nodeAfter = positionOrBaseElement.nodeAfter;\n\n\t\t\tif ( !( nodeBefore instanceof Element ) ) {\n\t\t\t\t/**\n\t\t\t\t * The node before the merge position must be an element.\n\t\t\t\t *\n\t\t\t\t * @error schema-check-merge-no-element-before\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'schema-check-merge-no-element-before',\n\t\t\t\t\tthis\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif ( !( nodeAfter instanceof Element ) ) {\n\t\t\t\t/**\n\t\t\t\t * The node after the merge position must be an element.\n\t\t\t\t *\n\t\t\t\t * @error schema-check-merge-no-element-after\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'schema-check-merge-no-element-after',\n\t\t\t\t\tthis\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn this.checkMerge( nodeBefore, nodeAfter );\n\t\t}\n\n\t\tfor ( const child of elementToMerge.getChildren() ) {\n\t\t\tif ( !this.checkChild( positionOrBaseElement, child ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Allows registering a callback to the {@link #checkChild} method calls.\n\t *\n\t * Callbacks allow you to implement rules which are not otherwise possible to achieve\n\t * by using the declarative API of {@link module:engine/model/schema~SchemaItemDefinition}.\n\t * For example, by using this method you can disallow elements in specific contexts.\n\t *\n\t * This method is a shorthand for using the {@link #event:checkChild} event. For even better control,\n\t * you can use that event instead.\n\t *\n\t * Example:\n\t *\n\t *\t\t// Disallow heading1 directly inside a blockQuote.\n\t *\t\tschema.addChildCheck( ( context, childDefinition ) => {\n\t *\t\t\tif ( context.endsWith( 'blockQuote' ) && childDefinition.name == 'heading1' ) {\n\t *\t\t\t\treturn false;\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * Which translates to:\n\t *\n\t *\t\tschema.on( 'checkChild', ( evt, args ) => {\n\t *\t\t\tconst context = args[ 0 ];\n\t *\t\t\tconst childDefinition = args[ 1 ];\n\t *\n\t *\t\t\tif ( context.endsWith( 'blockQuote' ) && childDefinition && childDefinition.name == 'heading1' ) {\n\t *\t\t\t\t// Prevent next listeners from being called.\n\t *\t\t\t\tevt.stop();\n\t *\t\t\t\t// Set the checkChild()'s return value.\n\t *\t\t\t\tevt.return = false;\n\t *\t\t\t}\n\t *\t\t}, { priority: 'high' } );\n\t *\n\t * @param {Function} callback The callback to be called. It is called with two parameters:\n\t * {@link module:engine/model/schema~SchemaContext} (context) instance and\n\t * {@link module:engine/model/schema~SchemaCompiledItemDefinition} (child-to-check definition).\n\t * The callback may return `true/false` to override `checkChild()`'s return value. If it does not return\n\t * a boolean value, the default algorithm (or other callbacks) will define `checkChild()`'s return value.\n\t */\n\taddChildCheck( callback ) {\n\t\tthis.on( 'checkChild', ( evt, [ ctx, childDef ] ) => {\n\t\t\t// checkChild() was called with a non-registered child.\n\t\t\t// In 99% cases such check should return false, so not to overcomplicate all callbacks\n\t\t\t// don't even execute them.\n\t\t\tif ( !childDef ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst retValue = callback( ctx, childDef );\n\n\t\t\tif ( typeof retValue == 'boolean' ) {\n\t\t\t\tevt.stop();\n\t\t\t\tevt.return = retValue;\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * Allows registering a callback to the {@link #checkAttribute} method calls.\n\t *\n\t * Callbacks allow you to implement rules which are not otherwise possible to achieve\n\t * by using the declarative API of {@link module:engine/model/schema~SchemaItemDefinition}.\n\t * For example, by using this method you can disallow attribute if node to which it is applied\n\t * is contained within some other element (e.g. you want to disallow `bold` on `$text` within `heading1`).\n\t *\n\t * This method is a shorthand for using the {@link #event:checkAttribute} event. For even better control,\n\t * you can use that event instead.\n\t *\n\t * Example:\n\t *\n\t *\t\t// Disallow bold on $text inside heading1.\n\t *\t\tschema.addAttributeCheck( ( context, attributeName ) => {\n\t *\t\t\tif ( context.endsWith( 'heading1 $text' ) && attributeName == 'bold' ) {\n\t *\t\t\t\treturn false;\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * Which translates to:\n\t *\n\t *\t\tschema.on( 'checkAttribute', ( evt, args ) => {\n\t *\t\t\tconst context = args[ 0 ];\n\t *\t\t\tconst attributeName = args[ 1 ];\n\t *\n\t *\t\t\tif ( context.endsWith( 'heading1 $text' ) && attributeName == 'bold' ) {\n\t *\t\t\t\t// Prevent next listeners from being called.\n\t *\t\t\t\tevt.stop();\n\t *\t\t\t\t// Set the checkAttribute()'s return value.\n\t *\t\t\t\tevt.return = false;\n\t *\t\t\t}\n\t *\t\t}, { priority: 'high' } );\n\t *\n\t * @param {Function} callback The callback to be called. It is called with two parameters:\n\t * {@link module:engine/model/schema~SchemaContext} (context) instance and attribute name.\n\t * The callback may return `true/false` to override `checkAttribute()`'s return value. If it does not return\n\t * a boolean value, the default algorithm (or other callbacks) will define `checkAttribute()`'s return value.\n\t */\n\taddAttributeCheck( callback ) {\n\t\tthis.on( 'checkAttribute', ( evt, [ ctx, attributeName ] ) => {\n\t\t\tconst retValue = callback( ctx, attributeName );\n\n\t\t\tif ( typeof retValue == 'boolean' ) {\n\t\t\t\tevt.stop();\n\t\t\t\tevt.return = retValue;\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * This method allows assigning additional metadata to the model attributes. For example,\n\t * {@link module:engine/model/schema~AttributeProperties `AttributeProperties#isFormatting` property} is\n\t * used to mark formatting attributes (like `bold` or `italic`).\n\t *\n\t *\t\t// Mark bold as a formatting attribute.\n\t *\t\tschema.setAttributeProperties( 'bold', {\n\t *\t\t\tisFormatting: true\n\t *\t\t} );\n\t *\n\t *\t\t// Override code not to be considered a formatting markup.\n\t *\t\tschema.setAttributeProperties( 'code', {\n\t *\t\t\tisFormatting: false\n\t *\t\t} );\n\t *\n\t * Properties are not limited to members defined in the\n\t * {@link module:engine/model/schema~AttributeProperties `AttributeProperties` type} and you can also use custom properties:\n\t *\n\t *\t\tschema.setAttributeProperties( 'blockQuote', {\n\t *\t\t\tcustomProperty: 'value'\n\t *\t\t} );\n\t *\n\t * Subsequent calls with the same attribute will extend its custom properties:\n\t *\n\t *\t\tschema.setAttributeProperties( 'blockQuote', {\n\t *\t\t\tone: 1\n\t *\t\t} );\n\t *\n\t *\t\tschema.setAttributeProperties( 'blockQuote', {\n\t *\t\t\ttwo: 2\n\t *\t\t} );\n\t *\n\t *\t\tconsole.log( schema.getAttributeProperties( 'blockQuote' ) );\n\t *\t\t// Logs: { one: 1, two: 2 }\n\t *\n\t * @param {String} attributeName A name of the attribute to receive the properties.\n\t * @param {module:engine/model/schema~AttributeProperties} properties A dictionary of properties.\n\t */\n\tsetAttributeProperties( attributeName, properties ) {\n\t\tthis._attributeProperties[ attributeName ] = Object.assign( this.getAttributeProperties( attributeName ), properties );\n\t}\n\n\t/**\n\t * Returns properties associated with a given model attribute. See {@link #setAttributeProperties `setAttributeProperties()`}.\n\t *\n\t * @param {String} attributeName A name of the attribute.\n\t * @returns {module:engine/model/schema~AttributeProperties}\n\t */\n\tgetAttributeProperties( attributeName ) {\n\t\treturn this._attributeProperties[ attributeName ] || {};\n\t}\n\n\t/**\n\t * Returns the lowest {@link module:engine/model/schema~Schema#isLimit limit element} containing the entire\n\t * selection/range/position or the root otherwise.\n\t *\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection|\n\t * module:engine/model/range~Range|module:engine/model/position~Position} selectionOrRangeOrPosition\n\t * The selection/range/position to check.\n\t * @returns {module:engine/model/element~Element} The lowest limit element containing\n\t * the entire `selectionOrRangeOrPosition`.\n\t */\n\tgetLimitElement( selectionOrRangeOrPosition ) {\n\t\tlet element;\n\n\t\tif ( selectionOrRangeOrPosition instanceof Position ) {\n\t\t\telement = selectionOrRangeOrPosition.parent;\n\t\t} else {\n\t\t\tconst ranges = selectionOrRangeOrPosition instanceof Range ?\n\t\t\t\t[ selectionOrRangeOrPosition ] :\n\t\t\t\tArray.from( selectionOrRangeOrPosition.getRanges() );\n\n\t\t\t// Find the common ancestor for all selection's ranges.\n\t\t\telement = ranges\n\t\t\t\t.reduce( ( element, range ) => {\n\t\t\t\t\tconst rangeCommonAncestor = range.getCommonAncestor();\n\n\t\t\t\t\tif ( !element ) {\n\t\t\t\t\t\treturn rangeCommonAncestor;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn element.getCommonAncestor( rangeCommonAncestor, { includeSelf: true } );\n\t\t\t\t}, null );\n\t\t}\n\n\t\twhile ( !this.isLimit( element ) ) {\n\t\t\tif ( element.parent ) {\n\t\t\t\telement = element.parent;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn element;\n\t}\n\n\t/**\n\t * Checks whether the attribute is allowed in selection:\n\t *\n\t * * if the selection is not collapsed, then checks if the attribute is allowed on any of nodes in that range,\n\t * * if the selection is collapsed, then checks if on the selection position there's a text with the\n\t * specified attribute allowed.\n\t *\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n\t * Selection which will be checked.\n\t * @param {String} attribute The name of the attribute to check.\n\t * @returns {Boolean}\n\t */\n\tcheckAttributeInSelection( selection, attribute ) {\n\t\tif ( selection.isCollapsed ) {\n\t\t\tconst firstPosition = selection.getFirstPosition();\n\t\t\tconst context = [\n\t\t\t\t...firstPosition.getAncestors(),\n\t\t\t\tnew Text( '', selection.getAttributes() )\n\t\t\t];\n\n\t\t\t// Check whether schema allows for a text with the attribute in the selection.\n\t\t\treturn this.checkAttribute( context, attribute );\n\t\t} else {\n\t\t\tconst ranges = selection.getRanges();\n\n\t\t\t// For all ranges, check nodes in them until you find a node that is allowed to have the attribute.\n\t\t\tfor ( const range of ranges ) {\n\t\t\t\tfor ( const value of range ) {\n\t\t\t\t\tif ( this.checkAttribute( value.item, attribute ) ) {\n\t\t\t\t\t\t// If we found a node that is allowed to have the attribute, return true.\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// If we haven't found such node, return false.\n\t\treturn false;\n\t}\n\n\t/**\n\t * Transforms the given set of ranges into a set of ranges where the given attribute is allowed (and can be applied).\n\t *\n\t * @param {Array.<module:engine/model/range~Range>} ranges Ranges to be validated.\n\t * @param {String} attribute The name of the attribute to check.\n\t * @returns {Iterable.<module:engine/model/range~Range>} Ranges in which the attribute is allowed.\n\t */\n\t* getValidRanges( ranges, attribute ) {\n\t\tranges = convertToMinimalFlatRanges( ranges );\n\n\t\tfor ( const range of ranges ) {\n\t\t\tyield* this._getValidRangesForRange( range, attribute );\n\t\t}\n\t}\n\n\t/**\n\t * Basing on given `position`, finds and returns a {@link module:engine/model/range~Range range} which is\n\t * nearest to that `position` and is a correct range for selection.\n\t *\n\t * The correct selection range might be collapsed when it is located in a position where the text node can be placed.\n\t * Non-collapsed range is returned when selection can be placed around element marked as an \"object\" in\n\t * the {@link module:engine/model/schema~Schema schema}.\n\t *\n\t * Direction of searching for the nearest correct selection range can be specified as:\n\t *\n\t * * `both` - searching will be performed in both ways,\n\t * * `forward` - searching will be performed only forward,\n\t * * `backward` - searching will be performed only backward.\n\t *\n\t * When valid selection range cannot be found, `null` is returned.\n\t *\n\t * @param {module:engine/model/position~Position} position Reference position where new selection range should be looked for.\n\t * @param {'both'|'forward'|'backward'} [direction='both'] Search direction.\n\t * @returns {module:engine/model/range~Range|null} Nearest selection range or `null` if one cannot be found.\n\t */\n\tgetNearestSelectionRange( position, direction = 'both' ) {\n\t\t// Return collapsed range if provided position is valid.\n\t\tif ( this.checkChild( position, '$text' ) ) {\n\t\t\treturn new Range( position );\n\t\t}\n\n\t\tlet backwardWalker, forwardWalker;\n\n\t\t// Never leave a limit element.\n\t\tconst limitElement = position.getAncestors().reverse().find( item => this.isLimit( item ) ) || position.root;\n\n\t\tif ( direction == 'both' || direction == 'backward' ) {\n\t\t\tbackwardWalker = new TreeWalker( {\n\t\t\t\tboundaries: Range._createIn( limitElement ),\n\t\t\t\tstartPosition: position,\n\t\t\t\tdirection: 'backward'\n\t\t\t} );\n\t\t}\n\n\t\tif ( direction == 'both' || direction == 'forward' ) {\n\t\t\tforwardWalker = new TreeWalker( {\n\t\t\t\tboundaries: Range._createIn( limitElement ),\n\t\t\t\tstartPosition: position\n\t\t\t} );\n\t\t}\n\n\t\tfor ( const data of combineWalkers( backwardWalker, forwardWalker ) ) {\n\t\t\tconst type = ( data.walker == backwardWalker ? 'elementEnd' : 'elementStart' );\n\t\t\tconst value = data.value;\n\n\t\t\tif ( value.type == type && this.isObject( value.item ) ) {\n\t\t\t\treturn Range._createOn( value.item );\n\t\t\t}\n\n\t\t\tif ( this.checkChild( value.nextPosition, '$text' ) ) {\n\t\t\t\treturn new Range( value.nextPosition );\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Tries to find position ancestors that allow to insert a given node.\n\t * It starts searching from the given position and goes node by node to the top of the model tree\n\t * as long as a {@link module:engine/model/schema~Schema#isLimit limit element}, an\n\t * {@link module:engine/model/schema~Schema#isObject object element} or a topmost ancestor is not reached.\n\t *\n\t * @param {module:engine/model/position~Position} position The position that the search will start from.\n\t * @param {module:engine/model/node~Node|String} node The node for which an allowed parent should be found or its name.\n\t * @returns {module:engine/model/element~Element|null} element Allowed parent or null if nothing was found.\n\t */\n\tfindAllowedParent( position, node ) {\n\t\tlet parent = position.parent;\n\n\t\twhile ( parent ) {\n\t\t\tif ( this.checkChild( parent, node ) ) {\n\t\t\t\treturn parent;\n\t\t\t}\n\n\t\t\t// Do not split limit elements.\n\t\t\tif ( this.isLimit( parent ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Removes attributes disallowed by the schema.\n\t *\n\t * @param {Iterable.<module:engine/model/node~Node>} nodes Nodes that will be filtered.\n\t * @param {module:engine/model/writer~Writer} writer\n\t */\n\tremoveDisallowedAttributes( nodes, writer ) {\n\t\tfor ( const node of nodes ) {\n\t\t\t// When node is a `Text` it has no children, so just filter it out.\n\t\t\tif ( node.is( '$text' ) ) {\n\t\t\t\tremoveDisallowedAttributeFromNode( this, node, writer );\n\t\t\t}\n\t\t\t// In a case of `Element` iterates through positions between nodes inside this element\n\t\t\t// and filter out node before the current position, or position parent when position\n\t\t\t// is at start of an element. Using positions prevent from omitting merged nodes\n\t\t\t// see https://github.com/ckeditor/ckeditor5-engine/issues/1789.\n\t\t\telse {\n\t\t\t\tconst rangeInNode = Range._createIn( node );\n\t\t\t\tconst positionsInRange = rangeInNode.getPositions();\n\n\t\t\t\tfor ( const position of positionsInRange ) {\n\t\t\t\t\tconst item = position.nodeBefore || position.parent;\n\n\t\t\t\t\tremoveDisallowedAttributeFromNode( this, item, writer );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates an instance of the schema context.\n\t *\n\t * @param {module:engine/model/schema~SchemaContextDefinition} context\n\t * @returns {module:engine/model/schema~SchemaContext}\n\t */\n\tcreateContext( context ) {\n\t\treturn new SchemaContext( context );\n\t}\n\n\t/**\n\t * @private\n\t */\n\t_clearCache() {\n\t\tthis._compiledDefinitions = null;\n\t}\n\n\t/**\n\t * @private\n\t */\n\t_compile() {\n\t\tconst compiledDefinitions = {};\n\t\tconst sourceRules = this._sourceDefinitions;\n\t\tconst itemNames = Object.keys( sourceRules );\n\n\t\tfor ( const itemName of itemNames ) {\n\t\t\tcompiledDefinitions[ itemName ] = compileBaseItemRule( sourceRules[ itemName ], itemName );\n\t\t}\n\n\t\tfor ( const itemName of itemNames ) {\n\t\t\tcompileAllowContentOf( compiledDefinitions, itemName );\n\t\t}\n\n\t\tfor ( const itemName of itemNames ) {\n\t\t\tcompileAllowWhere( compiledDefinitions, itemName );\n\t\t}\n\n\t\tfor ( const itemName of itemNames ) {\n\t\t\tcompileAllowAttributesOf( compiledDefinitions, itemName );\n\t\t\tcompileInheritPropertiesFrom( compiledDefinitions, itemName );\n\t\t}\n\n\t\tfor ( const itemName of itemNames ) {\n\t\t\tcleanUpAllowIn( compiledDefinitions, itemName );\n\t\t\tcleanUpAllowAttributes( compiledDefinitions, itemName );\n\t\t}\n\n\t\tthis._compiledDefinitions = compiledDefinitions;\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:engine/model/schema~SchemaCompiledItemDefinition} def\n\t * @param {module:engine/model/schema~SchemaContext} context\n\t * @param {Number} contextItemIndex\n\t */\n\t_checkContextMatch( def, context, contextItemIndex = context.length - 1 ) {\n\t\tconst contextItem = context.getItem( contextItemIndex );\n\n\t\tif ( def.allowIn.includes( contextItem.name ) ) {\n\t\t\tif ( contextItemIndex == 0 ) {\n\t\t\t\treturn true;\n\t\t\t} else {\n\t\t\t\tconst parentRule = this.getDefinition( contextItem );\n\n\t\t\t\treturn this._checkContextMatch( parentRule, context, contextItemIndex - 1 );\n\t\t\t}\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Takes a flat range and an attribute name. Traverses the range recursively and deeply to find and return all ranges\n\t * inside the given range on which the attribute can be applied.\n\t *\n\t * This is a helper function for {@link ~Schema#getValidRanges}.\n\t *\n\t * @private\n\t * @param {module:engine/model/range~Range} range The range to process.\n\t * @param {String} attribute The name of the attribute to check.\n\t * @returns {Iterable.<module:engine/model/range~Range>} Ranges in which the attribute is allowed.\n\t */\n\t* _getValidRangesForRange( range, attribute ) {\n\t\tlet start = range.start;\n\t\tlet end = range.start;\n\n\t\tfor ( const item of range.getItems( { shallow: true } ) ) {\n\t\t\tif ( item.is( 'element' ) ) {\n\t\t\t\tyield* this._getValidRangesForRange( Range._createIn( item ), attribute );\n\t\t\t}\n\n\t\t\tif ( !this.checkAttribute( item, attribute ) ) {\n\t\t\t\tif ( !start.isEqual( end ) ) {\n\t\t\t\t\tyield new Range( start, end );\n\t\t\t\t}\n\n\t\t\t\tstart = Position._createAfter( item );\n\t\t\t}\n\n\t\t\tend = Position._createAfter( item );\n\t\t}\n\n\t\tif ( !start.isEqual( end ) ) {\n\t\t\tyield new Range( start, end );\n\t\t}\n\t}\n}\n\nmix( Schema, ObservableMixin );\n\n/**\n * Event fired when the {@link #checkChild} method is called. It allows plugging in\n * additional behavior, for example implementing rules which cannot be defined using the declarative\n * {@link module:engine/model/schema~SchemaItemDefinition} interface.\n *\n * **Note:** The {@link #addChildCheck} method is a more handy way to register callbacks. Internally,\n * it registers a listener to this event but comes with a simpler API and it is the recommended choice\n * in most of the cases.\n *\n * The {@link #checkChild} method fires an event because it is\n * {@link module:utils/observablemixin~ObservableMixin#decorate decorated} with it. Thanks to that you can\n * use this event in various ways, but the most important use case is overriding standard behavior of the\n * `checkChild()` method. Let's see a typical listener template:\n *\n *\t\tschema.on( 'checkChild', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst childDefinition = args[ 1 ];\n *\t\t}, { priority: 'high' } );\n *\n * The listener is added with a `high` priority to be executed before the default method is really called. The `args` callback\n * parameter contains arguments passed to `checkChild( context, child )`. However, the `context` parameter is already\n * normalized to a {@link module:engine/model/schema~SchemaContext} instance and `child` to a\n * {@link module:engine/model/schema~SchemaCompiledItemDefinition} instance, so you do not have to worry about\n * the various ways how `context` and `child` may be passed to `checkChild()`.\n *\n * **Note:** `childDefinition` may be `undefined` if `checkChild()` was called with a non-registered element.\n *\n * So, in order to implement a rule \"disallow `heading1` in `blockQuote`\", you can add such a listener:\n *\n *\t\tschema.on( 'checkChild', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst childDefinition = args[ 1 ];\n *\n *\t\t\tif ( context.endsWith( 'blockQuote' ) && childDefinition && childDefinition.name == 'heading1' ) {\n *\t\t\t\t// Prevent next listeners from being called.\n *\t\t\t\tevt.stop();\n *\t\t\t\t// Set the checkChild()'s return value.\n *\t\t\t\tevt.return = false;\n *\t\t\t}\n *\t\t}, { priority: 'high' } );\n *\n * Allowing elements in specific contexts will be a far less common use case, because it is normally handled by the\n * `allowIn` rule from {@link module:engine/model/schema~SchemaItemDefinition}. But if you have a complex scenario\n * where `listItem` should be allowed only in element `foo` which must be in element `bar`, then this would be the way:\n *\n *\t\tschema.on( 'checkChild', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst childDefinition = args[ 1 ];\n *\n *\t\t\tif ( context.endsWith( 'bar foo' ) && childDefinition.name == 'listItem' ) {\n *\t\t\t\t// Prevent next listeners from being called.\n *\t\t\t\tevt.stop();\n *\t\t\t\t// Set the checkChild()'s return value.\n *\t\t\t\tevt.return = true;\n *\t\t\t}\n *\t\t}, { priority: 'high' } );\n *\n * @event checkChild\n * @param {Array} args The `checkChild()`'s arguments.\n */\n\n/**\n * Event fired when the {@link #checkAttribute} method is called. It allows plugging in\n * additional behavior, for example implementing rules which cannot be defined using the declarative\n * {@link module:engine/model/schema~SchemaItemDefinition} interface.\n *\n * **Note:** The {@link #addAttributeCheck} method is a more handy way to register callbacks. Internally,\n * it registers a listener to this event but comes with a simpler API and it is the recommended choice\n * in most of the cases.\n *\n * The {@link #checkAttribute} method fires an event because it is\n * {@link module:utils/observablemixin~ObservableMixin#decorate decorated} with it. Thanks to that you can\n * use this event in various ways, but the most important use case is overriding the standard behavior of the\n * `checkAttribute()` method. Let's see a typical listener template:\n *\n *\t\tschema.on( 'checkAttribute', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst attributeName = args[ 1 ];\n *\t\t}, { priority: 'high' } );\n *\n * The listener is added with a `high` priority to be executed before the default method is really called. The `args` callback\n * parameter contains arguments passed to `checkAttribute( context, attributeName )`. However, the `context` parameter is already\n * normalized to a {@link module:engine/model/schema~SchemaContext} instance, so you do not have to worry about\n * the various ways how `context` may be passed to `checkAttribute()`.\n *\n * So, in order to implement a rule \"disallow `bold` in a text which is in a `heading1`, you can add such a listener:\n *\n *\t\tschema.on( 'checkAttribute', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst attributeName = args[ 1 ];\n *\n *\t\t\tif ( context.endsWith( 'heading1 $text' ) && attributeName == 'bold' ) {\n *\t\t\t\t// Prevent next listeners from being called.\n *\t\t\t\tevt.stop();\n *\t\t\t\t// Set the checkAttribute()'s return value.\n *\t\t\t\tevt.return = false;\n *\t\t\t}\n *\t\t}, { priority: 'high' } );\n *\n * Allowing attributes in specific contexts will be a far less common use case, because it is normally handled by the\n * `allowAttributes` rule from {@link module:engine/model/schema~SchemaItemDefinition}. But if you have a complex scenario\n * where `bold` should be allowed only in element `foo` which must be in element `bar`, then this would be the way:\n *\n *\t\tschema.on( 'checkAttribute', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst attributeName = args[ 1 ];\n *\n *\t\t\tif ( context.endsWith( 'bar foo $text' ) && attributeName == 'bold' ) {\n *\t\t\t\t// Prevent next listeners from being called.\n *\t\t\t\tevt.stop();\n *\t\t\t\t// Set the checkAttribute()'s return value.\n *\t\t\t\tevt.return = true;\n *\t\t\t}\n *\t\t}, { priority: 'high' } );\n *\n * @event checkAttribute\n * @param {Array} args The `checkAttribute()`'s arguments.\n */\n\n/**\n * A definition of a {@link module:engine/model/schema~Schema schema} item.\n *\n * You can define the following rules:\n *\n * * {@link ~SchemaItemDefinition#allowIn `allowIn`} &ndash; Defines in which other items this item will be allowed.\n * * {@link ~SchemaItemDefinition#allowAttributes `allowAttributes`} &ndash; Defines allowed attributes of the given item.\n * * {@link ~SchemaItemDefinition#allowContentOf `allowContentOf`} &ndash; Inherits \"allowed children\" from other items.\n * * {@link ~SchemaItemDefinition#allowWhere `allowWhere`} &ndash; Inherits \"allowed in\" from other items.\n * * {@link ~SchemaItemDefinition#allowAttributesOf `allowAttributesOf`} &ndash; Inherits attributes from other items.\n * * {@link ~SchemaItemDefinition#inheritTypesFrom `inheritTypesFrom`} &ndash; Inherits `is*` properties of other items.\n * * {@link ~SchemaItemDefinition#inheritAllFrom `inheritAllFrom`} &ndash;\n * A shorthand for `allowContentOf`, `allowWhere`, `allowAttributesOf`, `inheritTypesFrom`.\n *\n * # The `is*` properties\n *\n * There are a couple commonly used `is*` properties. Their role is to assign additional semantics to schema items.\n * You can define more properties but you will also need to implement support for them in the existing editor features.\n *\n * * {@link ~SchemaItemDefinition#isBlock `isBlock`} &ndash; Whether this item is paragraph-like.\n * Generally speaking, content is usually made out of blocks like paragraphs, list items, images, headings, etc.\n * * {@link ~SchemaItemDefinition#isInline `isInline`} &ndash; Whether an item is \"text-like\" and should be treated as an inline node.\n * Examples of inline elements: `$text`, `softBreak` (`<br>`), etc.\n * * {@link ~SchemaItemDefinition#isLimit `isLimit`} &ndash; It can be understood as whether this element\n * should not be split by <kbd>Enter</kbd>. Examples of limit elements: `$root`, table cell, image caption, etc.\n * In other words, all actions that happen inside a limit element are limited to its content.\n * All objects are treated as limit elements, too.\n * * {@link ~SchemaItemDefinition#isObject `isObject`} &ndash; Whether an item is \"self-contained\" and should be treated as a whole.\n * Examples of object elements: `image`, `table`, `video`, etc. An object is also a limit, so\n * {@link module:engine/model/schema~Schema#isLimit `isLimit()`} returns `true` for object elements automatically.\n *\n * Read more about the meaning of these types in the\n * {@glink framework/guides/deep-dive/schema#defining-additional-semantics dedicated section of the Schema deep dive} guide.\n *\n * # Generic items\n *\n * There are three basic generic items: `$root`, `$block` and `$text`.\n * They are defined as follows:\n *\n *\t\tthis.schema.register( '$root', {\n *\t\t\tisLimit: true\n *\t\t} );\n *\t\tthis.schema.register( '$block', {\n *\t\t\tallowIn: '$root',\n *\t\t\tisBlock: true\n *\t\t} );\n *\t\tthis.schema.register( '$text', {\n *\t\t\tallowIn: '$block',\n *\t\t\tisInline: true\n *\t\t} );\n *\n * They reflect typical editor content that is contained within one root, consists of several blocks\n * (paragraphs, lists items, headings, images) which, in turn, may contain text inside.\n *\n * By inheriting from the generic items you can define new items which will get extended by other editor features.\n * Read more about generic types in the {@glink framework/guides/deep-dive/schema Schema deep dive} guide.\n *\n * # Example definitions\n *\n * Allow `paragraph` in roots and block quotes:\n *\n *\t\tschema.register( 'paragraph', {\n *\t\t\tallowIn: [ '$root', 'blockQuote' ],\n *\t\t\tisBlock: true\n *\t\t} );\n *\n * Allow `paragraph` everywhere where `$block` is allowed (i.e. in `$root`):\n *\n *\t\tschema.register( 'paragraph', {\n *\t\t\tallowWhere: '$block',\n *\t\t\tisBlock: true\n *\t\t} );\n *\n * Make `image` a block object, which is allowed everywhere where `$block` is.\n * Also, allow `src` and `alt` attributes in it:\n *\n *\t\tschema.register( 'image', {\n *\t\t\tallowWhere: '$block',\n *\t\t\tallowAttributes: [ 'src', 'alt' ],\n *\t\t\tisBlock: true,\n *\t\t\tisObject: true\n *\t\t} );\n *\n * Make `caption` allowed in `image` and make it allow all the content of `$block`s (usually, `$text`).\n * Also, mark it as a limit element so it cannot be split:\n *\n *\t\tschema.register( 'caption', {\n *\t\t\tallowIn: 'image',\n *\t\t\tallowContentOf: '$block',\n *\t\t\tisLimit: true\n *\t\t} );\n *\n * Make `listItem` inherit all from `$block` but also allow additional attributes:\n *\n *\t\tschema.register( 'listItem', {\n *\t\t\tinheritAllFrom: '$block',\n *\t\t\tallowAttributes: [ 'listType', 'listIndent' ]\n *\t\t} );\n *\n * Which translates to:\n *\n *\t\tschema.register( 'listItem', {\n *\t\t\tallowWhere: '$block',\n *\t\t\tallowContentOf: '$block',\n *\t\t\tallowAttributesOf: '$block',\n *\t\t\tinheritTypesFrom: '$block',\n *\t\t\tallowAttributes: [ 'listType', 'listIndent' ]\n *\t\t} );\n *\n * # Tips\n *\n * * Check schema definitions of existing features to see how they are defined.\n * * If you want to publish your feature so other developers can use it, try to use\n * generic items as much as possible.\n * * Keep your model clean. Limit it to the actual data and store information in a normalized way.\n * * Remember about defining the `is*` properties. They do not affect the allowed structures, but they can\n * affect how the editor features treat your elements.\n *\n * @typedef {Object} module:engine/model/schema~SchemaItemDefinition\n *\n * @property {String|Array.<String>} allowIn Defines in which other items this item will be allowed.\n * @property {String|Array.<String>} allowAttributes Defines allowed attributes of the given item.\n * @property {String|Array.<String>} allowContentOf Inherits \"allowed children\" from other items.\n * @property {String|Array.<String>} allowWhere Inherits \"allowed in\" from other items.\n * @property {String|Array.<String>} allowAttributesOf Inherits attributes from other items.\n * @property {String|Array.<String>} inheritTypesFrom Inherits `is*` properties of other items.\n * @property {String} inheritAllFrom A shorthand for `allowContentOf`, `allowWhere`, `allowAttributesOf`, `inheritTypesFrom`.\n *\n * @property {Boolean} isBlock\n * Whether this item is paragraph-like. Generally speaking, content is usually made out of blocks\n * like paragraphs, list items, images, headings, etc. All these elements are marked as blocks. A block\n * should not allow another block inside. Note: There is also the `$block` generic item which has `isBlock` set to `true`.\n * Most block type items will inherit from `$block` (through `inheritAllFrom`).\n *\n * Read more about the block elements in the\n * {@glink framework/guides/deep-dive/schema#block-elements Block elements} section of the Schema deep dive} guide.\n *\n * @property {Boolean} isInline\n * Whether an item is \"text-like\" and should be treated as an inline node. Examples of inline elements:\n * `$text`, `softBreak` (`<br>`), etc.\n *\n * Read more about the inline elements in the\n * {@glink framework/guides/deep-dive/schema#inline-elements Inline elements} section of the Schema deep dive} guide.\n *\n * @property {Boolean} isLimit\n * It can be understood as whether this element should not be split by <kbd>Enter</kbd>.\n * Examples of limit elements: `$root`, table cell, image caption, etc. In other words, all actions that happen inside\n * a limit element are limited to its content.\n *\n * Read more about the limit elements in the\n * {@glink framework/guides/deep-dive/schema#limit-elements Limit elements} section of the Schema deep dive} guide.\n *\n * @property {Boolean} isObject\n * Whether an item is \"self-contained\" and should be treated as a whole. Examples of object elements:\n * `image`, `table`, `video`, etc.\n *\n * **Note:** An object is also a limit, so\n * {@link module:engine/model/schema~Schema#isLimit `isLimit()`} returns `true` for object elements automatically.\n *\n * Read more about the object elements in the\n * {@glink framework/guides/deep-dive/schema#object-elements Object elements} section of the Schema deep dive} guide.\n *\n * @property {Boolean} isSelectable\n * `true` when an element should be selectable as a whole by the user. Examples of selectable elements: `image`, `table`, `tableCell`, etc.\n *\n * **Note:** An object is also a selectable element, so\n * {@link module:engine/model/schema~Schema#isSelectable `isSelectable()`} returns `true` for object elements automatically.\n *\n * Read more about selectable elements in the\n * {@glink framework/guides/deep-dive/schema#selectable-elements Selectable elements} section of the Schema deep dive} guide.\n *\n * @property {Boolean} isContent\n * An item is a content when it always finds its way to the editor data output regardless of the number and type of its descendants.\n * Examples of content elements: `$text`, `image`, `table`, etc. (but not `paragraph`, `heading1` or `tableCell`).\n *\n * **Note:** An object is also a content element, so\n * {@link module:engine/model/schema~Schema#isContent `isContent()`} returns `true` for object elements automatically.\n *\n * Read more about content elements in the\n * {@glink framework/guides/deep-dive/schema#content-elements Content elements} section of the Schema deep dive} guide.\n */\n\n/**\n * A simplified version of {@link module:engine/model/schema~SchemaItemDefinition} after\n * compilation by the {@link module:engine/model/schema~Schema schema}.\n * Rules fed to the schema by {@link module:engine/model/schema~Schema#register}\n * and {@link module:engine/model/schema~Schema#extend} methods are defined in the\n * {@link module:engine/model/schema~SchemaItemDefinition} format.\n * Later on, they are compiled to `SchemaCompiledItemDefinition` so when you use e.g.\n * the {@link module:engine/model/schema~Schema#getDefinition} method you get the compiled version.\n *\n * The compiled version contains only the following properties:\n *\n * * The `name` property,\n * * The `is*` properties,\n * * The `allowIn` array,\n * * The `allowAttributes` array.\n *\n * @typedef {Object} module:engine/model/schema~SchemaCompiledItemDefinition\n */\n\n/**\n * A schema context &mdash; a list of ancestors of a given position in the document.\n *\n * Considering such position:\n *\n *\t\t<$root>\n *\t\t\t<blockQuote>\n *\t\t\t\t<paragraph>\n *\t\t\t\t\t^\n *\t\t\t\t</paragraph>\n *\t\t\t</blockQuote>\n *\t\t</$root>\n *\n * The context of this position is its {@link module:engine/model/position~Position#getAncestors lists of ancestors}:\n *\n *\t\t[ rootElement, blockQuoteElement, paragraphElement ]\n *\n * Contexts are used in the {@link module:engine/model/schema~Schema#event:checkChild `Schema#checkChild`} and\n * {@link module:engine/model/schema~Schema#event:checkAttribute `Schema#checkAttribute`} events as a definition\n * of a place in the document where the check occurs. The context instances are created based on the first arguments\n * of the {@link module:engine/model/schema~Schema#checkChild `Schema#checkChild()`} and\n * {@link module:engine/model/schema~Schema#checkAttribute `Schema#checkAttribute()`} methods so when\n * using these methods you need to use {@link module:engine/model/schema~SchemaContextDefinition}s.\n */\nexport class SchemaContext {\n\t/**\n\t * Creates an instance of the context.\n\t *\n\t * @param {module:engine/model/schema~SchemaContextDefinition} context\n\t */\n\tconstructor( context ) {\n\t\tif ( context instanceof SchemaContext ) {\n\t\t\treturn context;\n\t\t}\n\n\t\tif ( typeof context == 'string' ) {\n\t\t\tcontext = [ context ];\n\t\t} else if ( !Array.isArray( context ) ) {\n\t\t\t// `context` is item or position.\n\t\t\t// Position#getAncestors() doesn't accept any parameters but it works just fine here.\n\t\t\tcontext = context.getAncestors( { includeSelf: true } );\n\t\t}\n\n\t\tif ( context[ 0 ] && typeof context[ 0 ] != 'string' && context[ 0 ].is( 'documentFragment' ) ) {\n\t\t\tcontext.shift();\n\t\t}\n\n\t\tthis._items = context.map( mapContextItem );\n\t}\n\n\t/**\n\t * The number of items.\n\t *\n\t * @type {Number}\n\t */\n\tget length() {\n\t\treturn this._items.length;\n\t}\n\n\t/**\n\t * The last item (the lowest node).\n\t *\n\t * @type {module:engine/model/schema~SchemaContextItem}\n\t */\n\tget last() {\n\t\treturn this._items[ this._items.length - 1 ];\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over all context items.\n\t *\n\t * @returns {Iterable.<module:engine/model/schema~SchemaContextItem>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._items[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Returns a new schema context instance with an additional item.\n\t *\n\t * Item can be added as:\n\t *\n\t * \t\tconst context = new SchemaContext( [ '$root' ] );\n\t *\n\t * \t\t// An element.\n\t * \t\tconst fooElement = writer.createElement( 'fooElement' );\n\t * \t\tconst newContext = context.push( fooElement ); // [ '$root', 'fooElement' ]\n\t *\n\t * \t\t// A text node.\n\t * \t\tconst text = writer.createText( 'foobar' );\n\t * \t\tconst newContext = context.push( text ); // [ '$root', '$text' ]\n\t *\n\t * \t\t// A string (element name).\n\t * \t\tconst newContext = context.push( 'barElement' ); // [ '$root', 'barElement' ]\n\t *\n\t * **Note** {@link module:engine/model/node~Node} that is already in the model tree will be added as the only item\n\t * (without ancestors).\n\t *\n\t * @param {String|module:engine/model/node~Node|Array<String|module:engine/model/node~Node>} item An item that will be added\n\t * to the current context.\n\t * @returns {module:engine/model/schema~SchemaContext} A new schema context instance with an additional item.\n\t */\n\tpush( item ) {\n\t\tconst ctx = new SchemaContext( [ item ] );\n\n\t\tctx._items = [ ...this._items, ...ctx._items ];\n\n\t\treturn ctx;\n\t}\n\n\t/**\n\t * Gets an item on the given index.\n\t *\n\t * @returns {module:engine/model/schema~SchemaContextItem}\n\t */\n\tgetItem( index ) {\n\t\treturn this._items[ index ];\n\t}\n\n\t/**\n\t * Returns the names of items.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\t* getNames() {\n\t\tyield* this._items.map( item => item.name );\n\t}\n\n\t/**\n\t * Checks whether the context ends with the given nodes.\n\t *\n\t *\t\tconst ctx = new SchemaContext( [ rootElement, paragraphElement, textNode ] );\n\t *\n\t *\t\tctx.endsWith( '$text' ); // -> true\n\t *\t\tctx.endsWith( 'paragraph $text' ); // -> true\n\t *\t\tctx.endsWith( '$root' ); // -> false\n\t *\t\tctx.endsWith( 'paragraph' ); // -> false\n\t *\n\t * @param {String} query\n\t * @returns {Boolean}\n\t */\n\tendsWith( query ) {\n\t\treturn Array.from( this.getNames() ).join( ' ' ).endsWith( query );\n\t}\n\n\t/**\n\t * Checks whether the context starts with the given nodes.\n\t *\n\t *\t\tconst ctx = new SchemaContext( [ rootElement, paragraphElement, textNode ] );\n\t *\n\t *\t\tctx.endsWith( '$root' ); // -> true\n\t *\t\tctx.endsWith( '$root paragraph' ); // -> true\n\t *\t\tctx.endsWith( '$text' ); // -> false\n\t *\t\tctx.endsWith( 'paragraph' ); // -> false\n\t *\n\t * @param {String} query\n\t * @returns {Boolean}\n\t */\n\tstartsWith( query ) {\n\t\treturn Array.from( this.getNames() ).join( ' ' ).startsWith( query );\n\t}\n}\n\n/**\n * The definition of a {@link module:engine/model/schema~SchemaContext schema context}.\n *\n * Contexts can be created in multiple ways:\n *\n * * By defining a **node** – in this cases this node and all its ancestors will be used.\n * * By defining a **position** in the document – in this case all its ancestors will be used.\n * * By defining an **array of nodes** – in this case this array defines the entire context.\n * * By defining a **name of node** - in this case node will be \"mocked\". It is not recommended because context\n * will be unrealistic (e.g. attributes of these nodes are not specified). However, at times this may be the only\n * way to define the context (e.g. when checking some hypothetical situation).\n * * By defining an **array of node names** (potentially, mixed with real nodes) – The same as **name of node**\n * but it is possible to create a path.\n * * By defining a {@link module:engine/model/schema~SchemaContext} instance - in this case the same instance as provided\n * will be return.\n *\n * Examples of context definitions passed to the {@link module:engine/model/schema~Schema#checkChild `Schema#checkChild()`}\n * method:\n *\n *\t\t// Assuming that we have a $root > blockQuote > paragraph structure, the following code\n *\t\t// will check node 'foo' in the following context:\n *\t\t// [ rootElement, blockQuoteElement, paragraphElement ]\n *\t\tconst contextDefinition = paragraphElement;\n * \t\tconst childToCheck = 'foo';\n *\t\tschema.checkChild( contextDefinition, childToCheck );\n *\n *\t\t// Also check in [ rootElement, blockQuoteElement, paragraphElement ].\n *\t\tschema.checkChild( model.createPositionAt( paragraphElement, 0 ), 'foo' );\n *\n *\t\t// Check in [ rootElement, paragraphElement ].\n *\t\tschema.checkChild( [ rootElement, paragraphElement ], 'foo' );\n *\n *\t\t// Check only fakeParagraphElement.\n *\t\tschema.checkChild( 'paragraph', 'foo' );\n *\n *\t\t// Check in [ fakeRootElement, fakeBarElement, paragraphElement ].\n *\t\tschema.checkChild( [ '$root', 'bar', paragraphElement ], 'foo' );\n *\n * All these `checkChild()` calls will fire {@link module:engine/model/schema~Schema#event:checkChild `Schema#checkChild`}\n * events in which `args[ 0 ]` is an instance of the context. Therefore, you can write a listener like this:\n *\n *\t\tschema.on( 'checkChild', ( evt, args ) => {\n *\t\t\tconst ctx = args[ 0 ];\n *\n *\t\t\tconsole.log( Array.from( ctx.getNames() ) );\n *\t\t} );\n *\n * Which will log the following:\n *\n *\t\t[ '$root', 'blockQuote', 'paragraph' ]\n *\t\t[ '$root', 'paragraph' ]\n *\t\t[ '$root', 'bar', 'paragraph' ]\n *\n * Note: When using the {@link module:engine/model/schema~Schema#checkAttribute `Schema#checkAttribute()`} method\n * you may want to check whether a text node may have an attribute. A {@link module:engine/model/text~Text} is a\n * correct way to define a context so you can do this:\n *\n *\t\tschema.checkAttribute( textNode, 'bold' );\n *\n * But sometimes you want to check whether a text at a given position might've had some attribute,\n * in which case you can create a context by missing an array of elements with a `'$text'` string:\n *\n *\t\t// Check in [ rootElement, paragraphElement, textNode ].\n *\t\tschema.checkChild( [ ...positionInParagraph.getAncestors(), '$text' ], 'bold' );\n *\n * @typedef {module:engine/model/node~Node|module:engine/model/position~Position|module:engine/model/schema~SchemaContext|\n * String|Array.<String|module:engine/model/node~Node>} module:engine/model/schema~SchemaContextDefinition\n */\n\n/**\n * An item of the {@link module:engine/model/schema~SchemaContext schema context}.\n *\n * It contains 3 properties:\n *\n * * `name` – the name of this item,\n * * `* getAttributeKeys()` – a generator of keys of item attributes,\n * * `getAttribute( keyName )` – a method to get attribute values.\n *\n * The context item interface is a highly simplified version of {@link module:engine/model/node~Node} and its role\n * is to expose only the information which schema checks are able to provide (which is the name of the node and\n * node's attributes).\n *\n *\t\tschema.on( 'checkChild', ( evt, args ) => {\n *\t\t\tconst ctx = args[ 0 ];\n *\t\t\tconst firstItem = ctx.getItem( 0 );\n *\n *\t\t\tconsole.log( firstItem.name ); // -> '$root'\n *\t\t\tconsole.log( firstItem.getAttribute( 'foo' ) ); // -> 'bar'\n *\t\t\tconsole.log( Array.from( firstItem.getAttributeKeys() ) ); // -> [ 'foo', 'faa' ]\n *\t\t} );\n *\n * @typedef {Object} module:engine/model/schema~SchemaContextItem\n */\n\n/**\n * A structure containing additional metadata describing the attribute.\n *\n * See {@link module:engine/model/schema~Schema#setAttributeProperties `Schema#setAttributeProperties()`} for usage examples.\n *\n * @typedef {Object} module:engine/model/schema~AttributeProperties\n * @property {Boolean} [isFormatting] Indicates that the attribute should be considered as a visual formatting, like `bold`, `italic` or\n * `fontSize` rather than semantic attribute (such as `src`, `listType`, etc.). For example, it is used by the \"Remove format\" feature.\n * @property {Boolean} [copyOnEnter] Indicates that given text attribute should be copied to the next block when enter is pressed.\n */\n\nfunction compileBaseItemRule( sourceItemRules, itemName ) {\n\tconst itemRule = {\n\t\tname: itemName,\n\n\t\tallowIn: [],\n\t\tallowContentOf: [],\n\t\tallowWhere: [],\n\n\t\tallowAttributes: [],\n\t\tallowAttributesOf: [],\n\n\t\tinheritTypesFrom: []\n\t};\n\n\tcopyTypes( sourceItemRules, itemRule );\n\n\tcopyProperty( sourceItemRules, itemRule, 'allowIn' );\n\tcopyProperty( sourceItemRules, itemRule, 'allowContentOf' );\n\tcopyProperty( sourceItemRules, itemRule, 'allowWhere' );\n\n\tcopyProperty( sourceItemRules, itemRule, 'allowAttributes' );\n\tcopyProperty( sourceItemRules, itemRule, 'allowAttributesOf' );\n\n\tcopyProperty( sourceItemRules, itemRule, 'inheritTypesFrom' );\n\n\tmakeInheritAllWork( sourceItemRules, itemRule );\n\n\treturn itemRule;\n}\n\nfunction compileAllowContentOf( compiledDefinitions, itemName ) {\n\tfor ( const allowContentOfItemName of compiledDefinitions[ itemName ].allowContentOf ) {\n\t\t// The allowContentOf property may point to an unregistered element.\n\t\tif ( compiledDefinitions[ allowContentOfItemName ] ) {\n\t\t\tconst allowedChildren = getAllowedChildren( compiledDefinitions, allowContentOfItemName );\n\n\t\t\tallowedChildren.forEach( allowedItem => {\n\t\t\t\tallowedItem.allowIn.push( itemName );\n\t\t\t} );\n\t\t}\n\t}\n\n\tdelete compiledDefinitions[ itemName ].allowContentOf;\n}\n\nfunction compileAllowWhere( compiledDefinitions, itemName ) {\n\tfor ( const allowWhereItemName of compiledDefinitions[ itemName ].allowWhere ) {\n\t\tconst inheritFrom = compiledDefinitions[ allowWhereItemName ];\n\n\t\t// The allowWhere property may point to an unregistered element.\n\t\tif ( inheritFrom ) {\n\t\t\tconst allowedIn = inheritFrom.allowIn;\n\n\t\t\tcompiledDefinitions[ itemName ].allowIn.push( ...allowedIn );\n\t\t}\n\t}\n\n\tdelete compiledDefinitions[ itemName ].allowWhere;\n}\n\nfunction compileAllowAttributesOf( compiledDefinitions, itemName ) {\n\tfor ( const allowAttributeOfItem of compiledDefinitions[ itemName ].allowAttributesOf ) {\n\t\tconst inheritFrom = compiledDefinitions[ allowAttributeOfItem ];\n\n\t\tif ( inheritFrom ) {\n\t\t\tconst inheritAttributes = inheritFrom.allowAttributes;\n\n\t\t\tcompiledDefinitions[ itemName ].allowAttributes.push( ...inheritAttributes );\n\t\t}\n\t}\n\n\tdelete compiledDefinitions[ itemName ].allowAttributesOf;\n}\n\nfunction compileInheritPropertiesFrom( compiledDefinitions, itemName ) {\n\tconst item = compiledDefinitions[ itemName ];\n\n\tfor ( const inheritPropertiesOfItem of item.inheritTypesFrom ) {\n\t\tconst inheritFrom = compiledDefinitions[ inheritPropertiesOfItem ];\n\n\t\tif ( inheritFrom ) {\n\t\t\tconst typeNames = Object.keys( inheritFrom ).filter( name => name.startsWith( 'is' ) );\n\n\t\t\tfor ( const name of typeNames ) {\n\t\t\t\tif ( !( name in item ) ) {\n\t\t\t\t\titem[ name ] = inheritFrom[ name ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tdelete item.inheritTypesFrom;\n}\n\n// Remove items which weren't registered (because it may break some checks or we'd need to complicate them).\n// Make sure allowIn doesn't contain repeated values.\nfunction cleanUpAllowIn( compiledDefinitions, itemName ) {\n\tconst itemRule = compiledDefinitions[ itemName ];\n\tconst existingItems = itemRule.allowIn.filter( itemToCheck => compiledDefinitions[ itemToCheck ] );\n\n\titemRule.allowIn = Array.from( new Set( existingItems ) );\n}\n\nfunction cleanUpAllowAttributes( compiledDefinitions, itemName ) {\n\tconst itemRule = compiledDefinitions[ itemName ];\n\n\titemRule.allowAttributes = Array.from( new Set( itemRule.allowAttributes ) );\n}\n\nfunction copyTypes( sourceItemRules, itemRule ) {\n\tfor ( const sourceItemRule of sourceItemRules ) {\n\t\tconst typeNames = Object.keys( sourceItemRule ).filter( name => name.startsWith( 'is' ) );\n\n\t\tfor ( const name of typeNames ) {\n\t\t\titemRule[ name ] = sourceItemRule[ name ];\n\t\t}\n\t}\n}\n\nfunction copyProperty( sourceItemRules, itemRule, propertyName ) {\n\tfor ( const sourceItemRule of sourceItemRules ) {\n\t\tif ( typeof sourceItemRule[ propertyName ] == 'string' ) {\n\t\t\titemRule[ propertyName ].push( sourceItemRule[ propertyName ] );\n\t\t} else if ( Array.isArray( sourceItemRule[ propertyName ] ) ) {\n\t\t\titemRule[ propertyName ].push( ...sourceItemRule[ propertyName ] );\n\t\t}\n\t}\n}\n\nfunction makeInheritAllWork( sourceItemRules, itemRule ) {\n\tfor ( const sourceItemRule of sourceItemRules ) {\n\t\tconst inheritFrom = sourceItemRule.inheritAllFrom;\n\n\t\tif ( inheritFrom ) {\n\t\t\titemRule.allowContentOf.push( inheritFrom );\n\t\t\titemRule.allowWhere.push( inheritFrom );\n\t\t\titemRule.allowAttributesOf.push( inheritFrom );\n\t\t\titemRule.inheritTypesFrom.push( inheritFrom );\n\t\t}\n\t}\n}\n\nfunction getAllowedChildren( compiledDefinitions, itemName ) {\n\tconst itemRule = compiledDefinitions[ itemName ];\n\n\treturn getValues( compiledDefinitions ).filter( def => def.allowIn.includes( itemRule.name ) );\n}\n\nfunction getValues( obj ) {\n\treturn Object.keys( obj ).map( key => obj[ key ] );\n}\n\nfunction mapContextItem( ctxItem ) {\n\tif ( typeof ctxItem == 'string' ) {\n\t\treturn {\n\t\t\tname: ctxItem,\n\n\t\t\t* getAttributeKeys() {},\n\n\t\t\tgetAttribute() {}\n\t\t};\n\t} else {\n\t\treturn {\n\t\t\t// '$text' means text nodes and text proxies.\n\t\t\tname: ctxItem.is( 'element' ) ? ctxItem.name : '$text',\n\n\t\t\t* getAttributeKeys() {\n\t\t\t\tyield* ctxItem.getAttributeKeys();\n\t\t\t},\n\n\t\t\tgetAttribute( key ) {\n\t\t\t\treturn ctxItem.getAttribute( key );\n\t\t\t}\n\t\t};\n\t}\n}\n\n// Generator function returning values from provided walkers, switching between them at each iteration. If only one walker\n// is provided it will return data only from that walker.\n//\n// @param {module:engine/module/treewalker~TreeWalker} [backward] Walker iterating in backward direction.\n// @param {module:engine/module/treewalker~TreeWalker} [forward] Walker iterating in forward direction.\n// @returns {Iterable.<Object>} Object returned at each iteration contains `value` and `walker` (informing which walker returned\n// given value) fields.\nfunction* combineWalkers( backward, forward ) {\n\tlet done = false;\n\n\twhile ( !done ) {\n\t\tdone = true;\n\n\t\tif ( backward ) {\n\t\t\tconst step = backward.next();\n\n\t\t\tif ( !step.done ) {\n\t\t\t\tdone = false;\n\t\t\t\tyield {\n\t\t\t\t\twalker: backward,\n\t\t\t\t\tvalue: step.value\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( forward ) {\n\t\t\tconst step = forward.next();\n\n\t\t\tif ( !step.done ) {\n\t\t\t\tdone = false;\n\t\t\t\tyield {\n\t\t\t\t\twalker: forward,\n\t\t\t\t\tvalue: step.value\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Takes an array of non-intersecting ranges. For each of them gets minimal flat ranges covering that range and returns\n// all those minimal flat ranges.\n//\n// @param {Array.<module:engine/model/range~Range>} ranges Ranges to process.\n// @returns {Iterable.<module:engine/model/range~Range>} Minimal flat ranges of given `ranges`.\nfunction* convertToMinimalFlatRanges( ranges ) {\n\tfor ( const range of ranges ) {\n\t\tyield* range.getMinimalFlatRanges();\n\t}\n}\n\nfunction removeDisallowedAttributeFromNode( schema, node, writer ) {\n\tfor ( const attribute of node.getAttributeKeys() ) {\n\t\tif ( !schema.checkAttribute( node, attribute ) ) {\n\t\t\twriter.removeAttribute( attribute, node );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/conversion/upcastdispatcher\n */\n\nimport ViewConsumable from './viewconsumable';\nimport ModelRange from '../model/range';\nimport ModelPosition from '../model/position';\nimport { SchemaContext } from '../model/schema';\nimport { isParagraphable, wrapInParagraph } from '../model/utils/autoparagraphing';\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Upcast dispatcher is a central point of the view-to-model conversion, which is a process of\n * converting a given {@link module:engine/view/documentfragment~DocumentFragment view document fragment} or\n * {@link module:engine/view/element~Element view element} into a correct model structure.\n *\n * During the conversion process, the dispatcher fires events for all {@link module:engine/view/node~Node view nodes}\n * from the converted view document fragment.\n * Special callbacks called \"converters\" should listen to these events in order to convert the view nodes.\n *\n * The second parameter of the callback is the `data` object with the following properties:\n *\n * * `data.viewItem` contains a {@link module:engine/view/node~Node view node} or a\n * {@link module:engine/view/documentfragment~DocumentFragment view document fragment}\n * that is converted at the moment and might be handled by the callback.\n * * `data.modelRange` is used to point to the result\n * of the current conversion (e.g. the element that is being inserted)\n * and is always a {@link module:engine/model/range~Range} when the conversion succeeds.\n * * `data.modelCursor` is a {@link module:engine/model/position~Position position} on which the converter should insert\n * the newly created items.\n *\n * The third parameter of the callback is an instance of {@link module:engine/conversion/upcastdispatcher~UpcastConversionApi}\n * which provides additional tools for converters.\n *\n * You can read more about conversion in the following guides:\n *\n * * {@glink framework/guides/deep-dive/conversion/conversion-introduction Advanced conversion concepts &mdash; attributes}\n * * {@glink framework/guides/deep-dive/conversion/custom-element-conversion Custom element conversion}\n *\n * Examples of event-based converters:\n *\n *\t\t// A converter for links (<a>).\n *\t\teditor.data.upcastDispatcher.on( 'element:a', ( evt, data, conversionApi ) => {\n *\t\t\tif ( conversionApi.consumable.consume( data.viewItem, { name: true, attributes: [ 'href' ] } ) ) {\n *\t\t\t\t// The <a> element is inline and is represented by an attribute in the model.\n *\t\t\t\t// This is why you need to convert only children.\n *\t\t\t\tconst { modelRange } = conversionApi.convertChildren( data.viewItem, data.modelCursor );\n *\n *\t\t\t\tfor ( let item of modelRange.getItems() ) {\n *\t\t\t\t\tif ( conversionApi.schema.checkAttribute( item, 'linkHref' ) ) {\n *\t\t\t\t\t\tconversionApi.writer.setAttribute( 'linkHref', data.viewItem.getAttribute( 'href' ), item );\n *\t\t\t\t\t}\n *\t\t\t\t}\n *\t\t\t}\n *\t\t} );\n *\n *\t\t// Convert <p> element's font-size style.\n *\t\t// Note: You should use a low-priority observer in order to ensure that\n *\t\t// it is executed after the element-to-element converter.\n *\t\teditor.data.upcastDispatcher.on( 'element:p', ( evt, data, conversionApi ) => {\n *\t\t\tconst { consumable, schema, writer } = conversionApi;\n *\n *\t\t\tif ( !consumable.consume( data.viewItem, { style: 'font-size' } ) ) {\n *\t\t\t\treturn;\n *\t\t\t}\n *\n *\t\t\tconst fontSize = data.viewItem.getStyle( 'font-size' );\n *\n *\t\t\t// Do not go for the model element after data.modelCursor because it might happen\n *\t\t\t// that a single view element was converted to multiple model elements. Get all of them.\n *\t\t\tfor ( const item of data.modelRange.getItems( { shallow: true } ) ) {\n *\t\t\t\tif ( schema.checkAttribute( item, 'fontSize' ) ) {\n *\t\t\t\t\twriter.setAttribute( 'fontSize', fontSize, item );\n *\t\t\t\t}\n *\t\t\t}\n *\t\t}, { priority: 'low' } );\n *\n *\t\t// Convert all elements which have no custom converter into a paragraph (autoparagraphing).\n *\t\teditor.data.upcastDispatcher.on( 'element', ( evt, data, conversionApi ) => {\n *\t\t\t// Check if an element can be converted.\n *\t\t\tif ( !conversionApi.consumable.test( data.viewItem, { name: data.viewItem.name } ) ) {\n *\t\t\t\t// When an element is already consumed by higher priority converters, do nothing.\n *\t\t\t\treturn;\n *\t\t\t}\n *\n *\t\t\tconst paragraph = conversionApi.writer.createElement( 'paragraph' );\n *\n *\t\t\t// Try to safely insert a paragraph at the model cursor - it will find an allowed parent for the current element.\n *\t\t\tif ( !conversionApi.safeInsert( paragraph, data.modelCursor ) ) {\n *\t\t\t\t// When an element was not inserted, it means that you cannot insert a paragraph at this position.\n *\t\t\t\treturn;\n *\t\t\t}\n *\n *\t\t\t// Consume the inserted element.\n *\t\t\tconversionApi.consumable.consume( data.viewItem, { name: data.viewItem.name } ) );\n *\n *\t\t\t// Convert the children to a paragraph.\n *\t\t\tconst { modelRange } = conversionApi.convertChildren( data.viewItem,  paragraph ) );\n *\n *\t\t\t// Update `modelRange` and `modelCursor` in the `data` as a conversion result.\n *\t\t\tconversionApi.updateConversionResult( paragraph, data );\n *\t\t}, { priority: 'low' } );\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n * @fires viewCleanup\n * @fires element\n * @fires text\n * @fires documentFragment\n */\nexport default class UpcastDispatcher {\n\t/**\n\t * Creates an upcast dispatcher that operates using the passed API.\n\t *\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi\n\t * @param {Object} [conversionApi] Additional properties for an interface that will be passed to events fired\n\t * by the upcast dispatcher.\n\t */\n\tconstructor( conversionApi = {} ) {\n\t\t/**\n\t\t * The list of elements that were created during splitting.\n\t\t *\n\t\t * After the conversion process the list is cleared.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.<module:engine/model/element~Element,Array.<module:engine/model/element~Element>>}\n\t\t */\n\t\tthis._splitParts = new Map();\n\n\t\t/**\n\t\t * The list of cursor parent elements that were created during splitting.\n\t\t *\n\t\t * After the conversion process the list is cleared.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.<module:engine/model/element~Element,Array.<module:engine/model/element~Element>>}\n\t\t */\n\t\tthis._cursorParents = new Map();\n\n\t\t/**\n\t\t * The position in the temporary structure where the converted content is inserted. The structure reflects the context of\n\t\t * the target position where the content will be inserted. This property is built based on the context parameter of the\n\t\t * convert method.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/model/position~Position|null}\n\t\t */\n\t\tthis._modelCursor = null;\n\n\t\t/**\n\t\t * An interface passed by the dispatcher to the event callbacks.\n\t\t *\n\t\t * @member {module:engine/conversion/upcastdispatcher~UpcastConversionApi}\n\t\t */\n\t\tthis.conversionApi = Object.assign( {}, conversionApi );\n\n\t\t// The below methods are bound to this `UpcastDispatcher` instance and set on `conversionApi`.\n\t\t// This way only a part of `UpcastDispatcher` API is exposed.\n\t\tthis.conversionApi.convertItem = this._convertItem.bind( this );\n\t\tthis.conversionApi.convertChildren = this._convertChildren.bind( this );\n\t\tthis.conversionApi.safeInsert = this._safeInsert.bind( this );\n\t\tthis.conversionApi.updateConversionResult = this._updateConversionResult.bind( this );\n\t\t// Advanced API - use only if custom position handling is needed.\n\t\tthis.conversionApi.splitToAllowedParent = this._splitToAllowedParent.bind( this );\n\t\tthis.conversionApi.getSplitParts = this._getSplitParts.bind( this );\n\t}\n\n\t/**\n\t * Starts the conversion process. The entry point for the conversion.\n\t *\n\t * @fires element\n\t * @fires text\n\t * @fires documentFragment\n\t * @param {module:engine/view/documentfragment~DocumentFragment|module:engine/view/element~Element} viewItem\n\t * The part of the view to be converted.\n\t * @param {module:engine/model/writer~Writer} writer An instance of the model writer.\n\t * @param {module:engine/model/schema~SchemaContextDefinition} [context=['$root']] Elements will be converted according to this context.\n\t * @returns {module:engine/model/documentfragment~DocumentFragment} Model data that is the result of the conversion process\n\t * wrapped in `DocumentFragment`. Converted marker elements will be set as the document fragment's\n\t * {@link module:engine/model/documentfragment~DocumentFragment#markers static markers map}.\n\t */\n\tconvert( viewItem, writer, context = [ '$root' ] ) {\n\t\tthis.fire( 'viewCleanup', viewItem );\n\n\t\t// Create context tree and set position in the top element.\n\t\t// Items will be converted according to this position.\n\t\tthis._modelCursor = createContextTree( context, writer );\n\n\t\t// Store writer in conversion as a conversion API\n\t\t// to be sure that conversion process will use the same batch.\n\t\tthis.conversionApi.writer = writer;\n\n\t\t// Create consumable values list for conversion process.\n\t\tthis.conversionApi.consumable = ViewConsumable.createFrom( viewItem );\n\n\t\t// Custom data stored by converter for conversion process.\n\t\tthis.conversionApi.store = {};\n\n\t\t// Do the conversion.\n\t\tconst { modelRange } = this._convertItem( viewItem, this._modelCursor );\n\n\t\t// Conversion result is always a document fragment so let's create it.\n\t\tconst documentFragment = writer.createDocumentFragment();\n\n\t\t// When there is a conversion result.\n\t\tif ( modelRange ) {\n\t\t\t// Remove all empty elements that were create while splitting.\n\t\t\tthis._removeEmptyElements();\n\n\t\t\t// Move all items that were converted in context tree to the document fragment.\n\t\t\tfor ( const item of Array.from( this._modelCursor.parent.getChildren() ) ) {\n\t\t\t\twriter.append( item, documentFragment );\n\t\t\t}\n\n\t\t\t// Extract temporary markers elements from model and set as static markers collection.\n\t\t\tdocumentFragment.markers = extractMarkersFromModelFragment( documentFragment, writer );\n\t\t}\n\n\t\t// Clear context position.\n\t\tthis._modelCursor = null;\n\n\t\t// Clear split elements & parents lists.\n\t\tthis._splitParts.clear();\n\t\tthis._cursorParents.clear();\n\n\t\t// Clear conversion API.\n\t\tthis.conversionApi.writer = null;\n\t\tthis.conversionApi.store = null;\n\n\t\t// Return fragment as conversion result.\n\t\treturn documentFragment;\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#convertItem\n\t */\n\t_convertItem( viewItem, modelCursor ) {\n\t\tconst data = Object.assign( { viewItem, modelCursor, modelRange: null } );\n\n\t\tif ( viewItem.is( 'element' ) ) {\n\t\t\tthis.fire( 'element:' + viewItem.name, data, this.conversionApi );\n\t\t} else if ( viewItem.is( '$text' ) ) {\n\t\t\tthis.fire( 'text', data, this.conversionApi );\n\t\t} else {\n\t\t\tthis.fire( 'documentFragment', data, this.conversionApi );\n\t\t}\n\n\t\t// Handle incorrect conversion result.\n\t\tif ( data.modelRange && !( data.modelRange instanceof ModelRange ) ) {\n\t\t\t/**\n\t\t\t * Incorrect conversion result was dropped.\n\t\t\t *\n\t\t\t * {@link module:engine/model/range~Range Model range} should be a conversion result.\n\t\t\t *\n\t\t\t * @error view-conversion-dispatcher-incorrect-result\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-conversion-dispatcher-incorrect-result', this );\n\t\t}\n\n\t\treturn { modelRange: data.modelRange, modelCursor: data.modelCursor };\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#convertChildren\n\t */\n\t_convertChildren( viewItem, elementOrModelCursor ) {\n\t\tlet nextModelCursor = elementOrModelCursor.is( 'position' ) ?\n\t\t\telementOrModelCursor : ModelPosition._createAt( elementOrModelCursor, 0 );\n\n\t\tconst modelRange = new ModelRange( nextModelCursor );\n\n\t\tfor ( const viewChild of Array.from( viewItem.getChildren() ) ) {\n\t\t\tconst result = this._convertItem( viewChild, nextModelCursor );\n\n\t\t\tif ( result.modelRange instanceof ModelRange ) {\n\t\t\t\tmodelRange.end = result.modelRange.end;\n\t\t\t\tnextModelCursor = result.modelCursor;\n\t\t\t}\n\t\t}\n\n\t\treturn { modelRange, modelCursor: nextModelCursor };\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#safeInsert\n\t */\n\t_safeInsert( modelElement, position ) {\n\t\t// Find allowed parent for element that we are going to insert.\n\t\t// If current parent does not allow to insert element but one of the ancestors does\n\t\t// then split nodes to allowed parent.\n\t\tconst splitResult = this._splitToAllowedParent( modelElement, position );\n\n\t\t// When there is no split result it means that we can't insert element to model tree, so let's skip it.\n\t\tif ( !splitResult ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Insert element on allowed position.\n\t\tthis.conversionApi.writer.insert( modelElement, splitResult.position );\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#updateConversionResult\n\t */\n\t_updateConversionResult( modelElement, data ) {\n\t\tconst parts = this._getSplitParts( modelElement );\n\n\t\tconst writer = this.conversionApi.writer;\n\n\t\t// Set conversion result range - only if not set already.\n\t\tif ( !data.modelRange ) {\n\t\t\tdata.modelRange = writer.createRange(\n\t\t\t\twriter.createPositionBefore( modelElement ),\n\t\t\t\twriter.createPositionAfter( parts[ parts.length - 1 ] )\n\t\t\t);\n\t\t}\n\n\t\tconst savedCursorParent = this._cursorParents.get( modelElement );\n\n\t\t// Now we need to check where the `modelCursor` should be.\n\t\tif ( savedCursorParent ) {\n\t\t\t// If we split parent to insert our element then we want to continue conversion in the new part of the split parent.\n\t\t\t//\n\t\t\t// before: <allowed><notAllowed>foo[]</notAllowed></allowed>\n\t\t\t// after:  <allowed><notAllowed>foo</notAllowed> <converted></converted> <notAllowed>[]</notAllowed></allowed>\n\n\t\t\tdata.modelCursor = writer.createPositionAt( savedCursorParent, 0 );\n\t\t} else {\n\t\t\t// Otherwise just continue after inserted element.\n\n\t\t\tdata.modelCursor = data.modelRange.end;\n\t\t}\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#splitToAllowedParent\n\t */\n\t_splitToAllowedParent( node, modelCursor ) {\n\t\tconst { schema, writer } = this.conversionApi;\n\n\t\t// Try to find allowed parent.\n\t\tlet allowedParent = schema.findAllowedParent( modelCursor, node );\n\n\t\tif ( allowedParent ) {\n\t\t\t// When current position parent allows to insert node then return this position.\n\t\t\tif ( allowedParent === modelCursor.parent ) {\n\t\t\t\treturn { position: modelCursor };\n\t\t\t}\n\n\t\t\t// When allowed parent is in context tree (it's outside the converted tree).\n\t\t\tif ( this._modelCursor.parent.getAncestors().includes( allowedParent ) ) {\n\t\t\t\tallowedParent = null;\n\t\t\t}\n\t\t}\n\n\t\tif ( !allowedParent ) {\n\t\t\t// Check if the node wrapped with a paragraph would be accepted by the schema.\n\t\t\tif ( !isParagraphable( modelCursor, node, schema ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tposition: wrapInParagraph( modelCursor, writer )\n\t\t\t};\n\t\t}\n\n\t\t// Split element to allowed parent.\n\t\tconst splitResult = this.conversionApi.writer.split( modelCursor, allowedParent );\n\n\t\t// Using the range returned by `model.Writer#split`, we will pair original elements with their split parts.\n\t\t//\n\t\t// The range returned from the writer spans \"over the split\" or, precisely saying, from the end of the original element (the one\n\t\t// that got split) to the beginning of the other part of that element:\n\t\t//\n\t\t// <limit><a><b><c>X[]Y</c></b><a></limit> ->\n\t\t// <limit><a><b><c>X[</c></b></a><a><b><c>]Y</c></b></a>\n\t\t//\n\t\t// After the split there cannot be any full node between the positions in `splitRange`. The positions are touching.\n\t\t// Also, because of how splitting works, it is easy to notice, that \"closing tags\" are in the reverse order than \"opening tags\".\n\t\t// Also, since we split all those elements, each of them has to have the other part.\n\t\t//\n\t\t// With those observations in mind, we will pair the original elements with their split parts by saving \"closing tags\" and matching\n\t\t// them with \"opening tags\" in the reverse order. For that we can use a stack.\n\t\tconst stack = [];\n\n\t\tfor ( const treeWalkerValue of splitResult.range.getWalker() ) {\n\t\t\tif ( treeWalkerValue.type == 'elementEnd' ) {\n\t\t\t\tstack.push( treeWalkerValue.item );\n\t\t\t} else {\n\t\t\t\t// There should not be any text nodes after the element is split, so the only other value is `elementStart`.\n\t\t\t\tconst originalPart = stack.pop();\n\t\t\t\tconst splitPart = treeWalkerValue.item;\n\n\t\t\t\tthis._registerSplitPair( originalPart, splitPart );\n\t\t\t}\n\t\t}\n\n\t\tconst cursorParent = splitResult.range.end.parent;\n\t\tthis._cursorParents.set( node, cursorParent );\n\n\t\treturn {\n\t\t\tposition: splitResult.position,\n\t\t\tcursorParent\n\t\t};\n\t}\n\n\t/**\n\t * Registers that a `splitPart` element is a split part of the `originalPart` element.\n\t *\n\t * The data set by this method is used by {@link #_getSplitParts} and {@link #_removeEmptyElements}.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} originalPart\n\t * @param {module:engine/model/element~Element} splitPart\n\t */\n\t_registerSplitPair( originalPart, splitPart ) {\n\t\tif ( !this._splitParts.has( originalPart ) ) {\n\t\t\tthis._splitParts.set( originalPart, [ originalPart ] );\n\t\t}\n\n\t\tconst list = this._splitParts.get( originalPart );\n\n\t\tthis._splitParts.set( splitPart, list );\n\t\tlist.push( splitPart );\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#getSplitParts\n\t */\n\t_getSplitParts( element ) {\n\t\tlet parts;\n\n\t\tif ( !this._splitParts.has( element ) ) {\n\t\t\tparts = [ element ];\n\t\t} else {\n\t\t\tparts = this._splitParts.get( element );\n\t\t}\n\n\t\treturn parts;\n\t}\n\n\t/**\n\t * Checks if there are any empty elements created while splitting and removes them.\n\t *\n\t * This method works recursively to re-check empty elements again after at least one element was removed in the initial call,\n\t * as some elements might have become empty after other empty elements were removed from them.\n\t *\n\t * @private\n\t */\n\t_removeEmptyElements() {\n\t\tlet anyRemoved = false;\n\n\t\tfor ( const element of this._splitParts.keys() ) {\n\t\t\tif ( element.isEmpty ) {\n\t\t\t\tthis.conversionApi.writer.remove( element );\n\t\t\t\tthis._splitParts.delete( element );\n\n\t\t\t\tanyRemoved = true;\n\t\t\t}\n\t\t}\n\n\t\tif ( anyRemoved ) {\n\t\t\tthis._removeEmptyElements();\n\t\t}\n\t}\n\n\t/**\n\t * Fired before the first conversion event, at the beginning of the upcast (view-to-model conversion) process.\n\t *\n\t * @event viewCleanup\n\t * @param {module:engine/view/documentfragment~DocumentFragment|module:engine/view/element~Element}\n\t * viewItem A part of the view to be converted.\n\t */\n\n\t/**\n\t * Fired when an {@link module:engine/view/element~Element} is converted.\n\t *\n\t * `element` is a namespace event for a class of events. Names of actually called events follow the pattern of\n\t * `element:<elementName>` where `elementName` is the name of the converted element. This way listeners may listen to\n\t * a conversion of all or just specific elements.\n\t *\n\t * @event element\n\t * @param {module:engine/conversion/upcastdispatcher~UpcastConversionData} data The conversion data. Keep in mind that this object is\n\t * shared by reference between all callbacks that will be called. This means that callbacks can override values if needed, and these\n\t * values will be available in other callbacks.\n\t * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion utilities to be used by the\n\t * callback.\n\t */\n\n\t/**\n\t * Fired when a {@link module:engine/view/text~Text} is converted.\n\t *\n\t * @event text\n\t * @see #event:element\n\t */\n\n\t/**\n\t * Fired when a {@link module:engine/view/documentfragment~DocumentFragment} is converted.\n\t *\n\t * @event documentFragment\n\t * @see #event:element\n\t */\n}\n\nmix( UpcastDispatcher, EmitterMixin );\n\n// Traverses given model item and searches elements which marks marker range. Found element is removed from\n// DocumentFragment but path of this element is stored in a Map which is then returned.\n//\n// @param {module:engine/view/documentfragment~DocumentFragment|module:engine/view/node~Node} modelItem Fragment of model.\n// @returns {Map<String, module:engine/model/range~Range>} List of static markers.\nfunction extractMarkersFromModelFragment( modelItem, writer ) {\n\tconst markerElements = new Set();\n\tconst markers = new Map();\n\n\t// Create ModelTreeWalker.\n\tconst range = ModelRange._createIn( modelItem ).getItems();\n\n\t// Walk through DocumentFragment and collect marker elements.\n\tfor ( const item of range ) {\n\t\t// Check if current element is a marker.\n\t\tif ( item.name == '$marker' ) {\n\t\t\tmarkerElements.add( item );\n\t\t}\n\t}\n\n\t// Walk through collected marker elements store its path and remove its from the DocumentFragment.\n\tfor ( const markerElement of markerElements ) {\n\t\tconst markerName = markerElement.getAttribute( 'data-name' );\n\t\tconst currentPosition = writer.createPositionBefore( markerElement );\n\n\t\t// When marker of given name is not stored it means that we have found the beginning of the range.\n\t\tif ( !markers.has( markerName ) ) {\n\t\t\tmarkers.set( markerName, new ModelRange( currentPosition.clone() ) );\n\t\t// Otherwise is means that we have found end of the marker range.\n\t\t} else {\n\t\t\tmarkers.get( markerName ).end = currentPosition.clone();\n\t\t}\n\n\t\t// Remove marker element from DocumentFragment.\n\t\twriter.remove( markerElement );\n\t}\n\n\treturn markers;\n}\n\n// Creates model fragment according to given context and returns position in the bottom (the deepest) element.\nfunction createContextTree( contextDefinition, writer ) {\n\tlet position;\n\n\tfor ( const item of new SchemaContext( contextDefinition ) ) {\n\t\tconst attributes = {};\n\n\t\tfor ( const key of item.getAttributeKeys() ) {\n\t\t\tattributes[ key ] = item.getAttribute( key );\n\t\t}\n\n\t\tconst current = writer.createElement( item.name, attributes );\n\n\t\tif ( position ) {\n\t\t\twriter.append( current, position );\n\t\t}\n\n\t\tposition = ModelPosition._createAt( current, 0 );\n\t}\n\n\treturn position;\n}\n\n/**\n * A set of conversion utilities available as the third parameter of the\n * {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher upcast dispatcher}'s events.\n *\n * @interface module:engine/conversion/upcastdispatcher~UpcastConversionApi\n */\n\n/**\n * Starts the conversion of a given item by firing an appropriate event.\n *\n * Every fired event is passed (as the first parameter) an object with the `modelRange` property. Every event may set and/or\n * modify that property. When all callbacks are done, the final value of the `modelRange` property is returned by this method.\n * The `modelRange` must be a {@link module:engine/model/range~Range model range} or `null` (as set by default).\n *\n * @method #convertItem\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:text\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:documentFragment\n * @param {module:engine/view/item~Item} viewItem Item to convert.\n * @param {module:engine/model/position~Position} modelCursor The conversion position.\n * @returns {Object} result The conversion result.\n * @returns {module:engine/model/range~Range|null} result.modelRange The model range containing the result of the item conversion,\n * created and modified by callbacks attached to the fired event, or `null` if the conversion result was incorrect.\n * @returns {module:engine/model/position~Position} result.modelCursor The position where the conversion should be continued.\n */\n\n/**\n * Starts the conversion of all children of a given item by firing appropriate events for all the children.\n *\n * @method #convertChildren\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:text\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:documentFragment\n * @param {module:engine/view/item~Item} viewItem An element whose children should be converted.\n * @param {module:engine/model/position~Position|module:engine/model/element~Element} positionOrElement A position or an element of\n * the conversion.\n * @returns {Object} result The conversion result.\n * @returns {module:engine/model/range~Range} result.modelRange The model range containing the results of the conversion of all children\n * of the given item. When no child was converted, the range is collapsed.\n * @returns {module:engine/model/position~Position} result.modelCursor The position where the conversion should be continued.\n */\n\n/**\n * Safely inserts an element to the document, checking the {@link module:engine/model/schema~Schema schema} to find an allowed parent for\n * an element that you are going to insert, starting from the given position. If the current parent does not allow to insert the element\n * but one of the ancestors does, then splits the nodes to allowed parent.\n *\n * If the schema allows to insert the node in a given position, nothing is split.\n *\n * If it was not possible to find an allowed parent, `false` is returned and nothing is split.\n *\n * Otherwise, ancestors are split.\n *\n * For instance, if `<image>` is not allowed in `<paragraph>` but is allowed in `$root`:\n *\n *\t\t<paragraph>foo[]bar</paragraph>\n *\n *\t\t-> safe insert for `<image>` will split ->\n *\n *\t\t<paragraph>foo</paragraph>[]<paragraph>bar</paragraph>\n *\n * Example usage:\n *\n *\t\tconst myElement = conversionApi.writer.createElement( 'myElement' );\n *\n *\t\tif ( !conversionApi.safeInsert( myElement, data.modelCursor ) ) {\n *\t\t\treturn;\n *\t\t}\n *\n * The split result is saved and {@link #updateConversionResult} should be used to update the\n * {@link module:engine/conversion/upcastdispatcher~UpcastConversionData conversion data}.\n *\n * @method #safeInsert\n * @param {module:engine/model/node~Node} node The node to insert.\n * @param {module:engine/model/position~Position} position The position where an element is going to be inserted.\n * @returns {Boolean} The split result. If it was not possible to find an allowed position, `false` is returned.\n */\n\n/**\n * Updates the conversion result and sets a proper {@link module:engine/conversion/upcastdispatcher~UpcastConversionData#modelRange} and\n * the next {@link module:engine/conversion/upcastdispatcher~UpcastConversionData#modelCursor} after the conversion.\n * Used together with {@link #safeInsert}, it enables you to easily convert elements without worrying if the node was split\n * during the conversion of its children.\n *\n * A usage example in converter code:\n *\n *\t\tconst myElement = conversionApi.writer.createElement( 'myElement' );\n *\n *\t\tif ( !conversionApi.safeInsert( myElement, data.modelCursor ) ) {\n *\t\t\treturn;\n *\t\t}\n *\n *\t\t// Children conversion may split `myElement`.\n *\t\tconversionApi.convertChildren( data.viewItem, myElement );\n *\n *\t\tconversionApi.updateConversionResult( myElement, data );\n *\n * @method #updateConversionResult\n * @param {module:engine/model/element~Element} element\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionData} data Conversion data.\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion utilities to be used by the callback.\n */\n\n/**\n * Checks the {@link module:engine/model/schema~Schema schema} to find an allowed parent for an element that is going to be inserted\n * starting from the given position. If the current parent does not allow inserting an element but one of the ancestors does, the method\n * splits nodes to allowed parent.\n *\n * If the schema allows inserting the node in the given position, nothing is split and an object with that position is returned.\n *\n * If it was not possible to find an allowed parent, `null` is returned and nothing is split.\n *\n * Otherwise, ancestors are split and an object with a position and the copy of the split element is returned.\n *\n * For instance, if `<image>` is not allowed in `<paragraph>` but is allowed in `$root`:\n *\n *\t\t<paragraph>foo[]bar</paragraph>\n *\n *\t\t-> split for `<image>` ->\n *\n *\t\t<paragraph>foo</paragraph>[]<paragraph>bar</paragraph>\n *\n * In the example above, the position between `<paragraph>` elements will be returned as `position` and the second `paragraph`\n * as `cursorParent`.\n *\n * **Note:** This is an advanced method. For most cases {@link #safeInsert} and {@link #updateConversionResult} should be used.\n *\n * @method #splitToAllowedParent\n * @param {module:engine/model/position~Position} position The position where the element is going to be inserted.\n * @param {module:engine/model/node~Node} node The node to insert.\n * @returns {Object|null} The split result. If it was not possible to find an allowed position, `null` is returned.\n * @returns {module:engine/model/position~Position} The position between split elements.\n * @returns {module:engine/model/element~Element} [cursorParent] The element inside which the cursor should be placed to\n * continue the conversion. When the element is not defined it means that there was no split.\n */\n\n/**\n * Returns all the split parts of the given `element` that were created during upcasting through using {@link #splitToAllowedParent}.\n * It enables you to easily track these elements and continue processing them after they are split during the conversion of their children.\n *\n *\t\t<paragraph>Foo<image />bar<image />baz</paragraph> ->\n *\t\t<paragraph>Foo</paragraph><image /><paragraph>bar</paragraph><image /><paragraph>baz</paragraph>\n *\n * For a reference to any of above paragraphs, the function will return all three paragraphs (the original element included),\n * sorted in the order of their creation (the original element is the first one).\n *\n * If the given `element` was not split, an array with a single element is returned.\n *\n * A usage example in the converter code:\n *\n *\t\tconst myElement = conversionApi.writer.createElement( 'myElement' );\n *\n *\t\t// Children conversion may split `myElement`.\n *\t\tconversionApi.convertChildren( data.viewItem, data.modelCursor );\n *\n *\t\tconst splitParts = conversionApi.getSplitParts( myElement );\n *\t\tconst lastSplitPart = splitParts[ splitParts.length - 1 ];\n *\n *\t\t// Setting `data.modelRange` basing on split parts:\n *\t\tdata.modelRange = conversionApi.writer.createRange(\n *\t\t\tconversionApi.writer.createPositionBefore( myElement ),\n *\t\t\tconversionApi.writer.createPositionAfter( lastSplitPart )\n *\t\t);\n *\n *\t\t// Setting `data.modelCursor` to continue after the last split element:\n *\t\tdata.modelCursor = conversionApi.writer.createPositionAfter( lastSplitPart );\n *\n * **Tip:** If you are unable to get a reference to the original element (for example because the code is split into multiple converters\n * or even classes) but it has already been converted, you may want to check the first element in `data.modelRange`. This is a common\n * situation if an attribute converter is separated from an element converter.\n *\n * **Note:** This is an advanced method. For most cases {@link #safeInsert} and {@link #updateConversionResult} should be used.\n *\n * @method #getSplitParts\n * @param {module:engine/model/element~Element} element\n * @returns {Array.<module:engine/model/element~Element>}\n */\n\n/**\n * Stores information about what parts of the processed view item are still waiting to be handled. After a piece of view item\n * was converted, an appropriate consumable value should be\n * {@link module:engine/conversion/viewconsumable~ViewConsumable#consume consumed}.\n *\n * @member {module:engine/conversion/viewconsumable~ViewConsumable} #consumable\n */\n\n/**\n * Custom data stored by converters for the conversion process. Custom properties of this object can be defined and use to\n * pass parameters between converters.\n *\n * The difference between this property and the `data` parameter of\n * {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element} is that the `data` parameters allow you\n * to pass parameters within a single event and `store` within the whole conversion.\n *\n * @member {Object} #store\n */\n\n/**\n * The model's schema instance.\n *\n * @member {module:engine/model/schema~Schema} #schema\n */\n\n/**\n * The {@link module:engine/model/writer~Writer} instance used to manipulate the data during conversion.\n *\n * @member {module:engine/model/writer~Writer} #writer\n */\n\n/**\n * Conversion data.\n *\n * **Note:** Keep in mind that this object is shared by reference between all conversion callbacks that will be called.\n * This means that callbacks can override values if needed, and these values will be available in other callbacks.\n *\n * @typedef {Object} module:engine/conversion/upcastdispatcher~UpcastConversionData\n *\n * @property {module:engine/view/item~Item} viewItem The converted item.\n * @property {module:engine/model/position~Position} modelCursor The position where the converter should start changes.\n * Change this value for the next converter to tell where the conversion should continue.\n * @property {module:engine/model/range~Range} [modelRange] The current state of conversion result. Every change to\n * the converted element should be reflected by setting or modifying this property.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/controller/datacontroller\n */\n\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\nimport Mapper from '../conversion/mapper';\n\nimport DowncastDispatcher from '../conversion/downcastdispatcher';\nimport { insertText } from '../conversion/downcasthelpers';\n\nimport UpcastDispatcher from '../conversion/upcastdispatcher';\nimport { convertText, convertToModelFragment } from '../conversion/upcasthelpers';\n\nimport ViewDocumentFragment from '../view/documentfragment';\nimport ViewDocument from '../view/document';\nimport ViewDowncastWriter from '../view/downcastwriter';\n\nimport ModelRange from '../model/range';\nimport { autoParagraphEmptyRoots } from '../model/utils/autoparagraphing';\n\n/**\n * Controller for the data pipeline. The data pipeline controls how data is retrieved from the document\n * and set inside it. Hence, the controller features two methods which allow to {@link ~DataController#get get}\n * and {@link ~DataController#set set} data of the {@link ~DataController#model model}\n * using given:\n *\n * * {@link module:engine/dataprocessor/dataprocessor~DataProcessor data processor},\n * * downcast converters,\n * * upcast converters.\n *\n * An instance of the data controller is always available in the {@link module:core/editor/editor~Editor#data `editor.data`}\n * property:\n *\n *\t\teditor.data.get( { rootName: 'customRoot' } ); // -> '<p>Hello!</p>'\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class DataController {\n\t/**\n\t * Creates a data controller instance.\n\t *\n\t * @param {module:engine/model/model~Model} model Data model.\n\t * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor The styles processor instance.\n\t */\n\tconstructor( model, stylesProcessor ) {\n\t\t/**\n\t\t * Data model.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/model~Model}\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * Styles processor used during the conversion.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/stylesmap~StylesProcessor}\n\t\t */\n\t\tthis.stylesProcessor = stylesProcessor;\n\n\t\t/**\n\t\t * Data processor used during the conversion.\n\t\t *\n\t\t * @member {module:engine/dataprocessor/dataprocessor~DataProcessor} #processor\n\t\t */\n\t\tthis.processor = undefined;\n\n\t\t/**\n\t\t * Mapper used for the conversion. It has no permanent bindings, because they are created when getting data and\n\t\t * cleared directly after the data are converted. However, the mapper is defined as a class property, because\n\t\t * it needs to be passed to the `DowncastDispatcher` as a conversion API.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/mapper~Mapper}\n\t\t */\n\t\tthis.mapper = new Mapper();\n\n\t\t/**\n\t\t * Downcast dispatcher used by the {@link #get get method}. Downcast converters should be attached to it.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/downcastdispatcher~DowncastDispatcher}\n\t\t */\n\t\tthis.downcastDispatcher = new DowncastDispatcher( {\n\t\t\tmapper: this.mapper,\n\t\t\tschema: model.schema\n\t\t} );\n\t\tthis.downcastDispatcher.on( 'insert:$text', insertText(), { priority: 'lowest' } );\n\n\t\t/**\n\t\t * Upcast dispatcher used by the {@link #set set method}. Upcast converters should be attached to it.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/upcastdispatcher~UpcastDispatcher}\n\t\t */\n\t\tthis.upcastDispatcher = new UpcastDispatcher( {\n\t\t\tschema: model.schema\n\t\t} );\n\n\t\t/**\n\t\t * The view document used by the data controller.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/document~Document}\n\t\t */\n\t\tthis.viewDocument = new ViewDocument( stylesProcessor );\n\n\t\t/**\n\t\t * The view downcast writer just for data conversion purposes, i.e. to modify\n\t\t * the {@link #viewDocument}.\n\t\t *\n\t\t * @private\n\t\t * @readonly\n\t\t * @member {module:engine/view/downcastwriter~DowncastWriter}\n\t\t */\n\t\tthis._viewWriter = new ViewDowncastWriter( this.viewDocument );\n\n\t\t// Define default converters for text and elements.\n\t\t//\n\t\t// Note that if there is no default converter for the element it will be skipped, for instance `<b>foo</b>` will be\n\t\t// converted to nothing. We therefore add `convertToModelFragment` as a last converter so it converts children of that\n\t\t// element to the document fragment and so `<b>foo</b>` will be converted to `foo` if there is no converter for `<b>`.\n\t\tthis.upcastDispatcher.on( 'text', convertText(), { priority: 'lowest' } );\n\t\tthis.upcastDispatcher.on( 'element', convertToModelFragment(), { priority: 'lowest' } );\n\t\tthis.upcastDispatcher.on( 'documentFragment', convertToModelFragment(), { priority: 'lowest' } );\n\n\t\tthis.decorate( 'init' );\n\t\tthis.decorate( 'set' );\n\n\t\t// Fire the `ready` event when the initialization has completed. Such low-level listener gives possibility\n\t\t// to plug into the initialization pipeline without interrupting the initialization flow.\n\t\tthis.on( 'init', () => {\n\t\t\tthis.fire( 'ready' );\n\t\t}, { priority: 'lowest' } );\n\n\t\t// Fix empty roots after DataController is 'ready' (note that init method could be decorated and stopped).\n\t\t// We need to handle this event because initial data could be empty and post-fixer would not get triggered.\n\t\tthis.on( 'ready', () => {\n\t\t\tthis.model.enqueueChange( 'transparent', autoParagraphEmptyRoots );\n\t\t}, { priority: 'lowest' } );\n\t}\n\n\t/**\n\t * Returns the model's data converted by downcast dispatchers attached to {@link #downcastDispatcher} and\n\t * formatted by the {@link #processor data processor}.\n\t *\n\t * @param {Object} [options] Additional configuration for the retrieved data. `DataController` provides two optional\n\t * properties: `rootName` and `trim`. Other properties of this object are specified by various editor features.\n\t * @param {String} [options.rootName='main'] Root name.\n\t * @param {String} [options.trim='empty'] Whether returned data should be trimmed. This option is set to `empty` by default,\n\t * which means whenever editor content is considered empty, an empty string will be returned. To turn off trimming completely\n\t * use `'none'`. In such cases exact content will be returned (for example `<p>&nbsp;</p>` for an empty editor).\n\t * @returns {String} Output data.\n\t */\n\tget( options = {} ) {\n\t\tconst { rootName = 'main', trim = 'empty' } = options;\n\n\t\tif ( !this._checkIfRootsExists( [ rootName ] ) ) {\n\t\t\t/**\n\t\t\t * Cannot get data from a non-existing root. This error is thrown when {@link #get DataController#get() method}\n\t\t\t * is called with non-existent root name. For example, if there is an editor instance with only `main` root,\n\t\t\t * calling {@link #get} like:\n\t\t\t *\n\t\t\t *\t\tdata.get( { rootName: 'root2' } );\n\t\t\t *\n\t\t\t * will throw this error.\n\t\t\t *\n\t\t\t * @error datacontroller-get-non-existent-root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'datacontroller-get-non-existent-root', this );\n\t\t}\n\n\t\tconst root = this.model.document.getRoot( rootName );\n\n\t\tif ( trim === 'empty' && !this.model.hasContent( root, { ignoreWhitespaces: true } ) ) {\n\t\t\treturn '';\n\t\t}\n\n\t\treturn this.stringify( root, options );\n\t}\n\n\t/**\n\t * Returns the content of the given {@link module:engine/model/element~Element model's element} or\n\t * {@link module:engine/model/documentfragment~DocumentFragment model document fragment} converted by the downcast converters\n\t * attached to {@link #downcastDispatcher} and formatted by the {@link #processor data processor}.\n\t *\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} modelElementOrFragment\n\t * Element whose content will be stringified.\n\t * @param {Object} [options] Additional configuration passed to the conversion process.\n\t * @returns {String} Output data.\n\t */\n\tstringify( modelElementOrFragment, options ) {\n\t\t// Model -> view.\n\t\tconst viewDocumentFragment = this.toView( modelElementOrFragment, options );\n\n\t\t// View -> data.\n\t\treturn this.processor.toData( viewDocumentFragment );\n\t}\n\n\t/**\n\t * Returns the content of the given {@link module:engine/model/element~Element model element} or\n\t * {@link module:engine/model/documentfragment~DocumentFragment model document fragment} converted by the downcast\n\t * converters attached to {@link #downcastDispatcher} to a\n\t * {@link module:engine/view/documentfragment~DocumentFragment view document fragment}.\n\t *\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} modelElementOrFragment\n\t * Element or document fragment whose content will be converted.\n\t * @param {Object} [options] Additional configuration that will be available through\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi#options} during the conversion process.\n\t * @returns {module:engine/view/documentfragment~DocumentFragment} Output view DocumentFragment.\n\t */\n\ttoView( modelElementOrFragment, options ) {\n\t\tconst viewDocument = this.viewDocument;\n\t\tconst viewWriter = this._viewWriter;\n\n\t\t// Clear bindings so the call to this method gives correct results.\n\t\tthis.mapper.clearBindings();\n\n\t\t// First, convert elements.\n\t\tconst modelRange = ModelRange._createIn( modelElementOrFragment );\n\t\tconst viewDocumentFragment = new ViewDocumentFragment( viewDocument );\n\n\t\tthis.mapper.bindElements( modelElementOrFragment, viewDocumentFragment );\n\n\t\t// Make additional options available during conversion process through `conversionApi`.\n\t\tthis.downcastDispatcher.conversionApi.options = options;\n\n\t\t// We have no view controller and rendering to DOM in DataController so view.change() block is not used here.\n\t\tthis.downcastDispatcher.convertInsert( modelRange, viewWriter );\n\n\t\tif ( !modelElementOrFragment.is( 'documentFragment' ) ) {\n\t\t\t// Then, if a document element is converted, convert markers.\n\t\t\t// From all document markers, get those, which \"intersect\" with the converter element.\n\t\t\tconst markers = _getMarkersRelativeToElement( modelElementOrFragment );\n\n\t\t\tfor ( const [ name, range ] of markers ) {\n\t\t\t\tthis.downcastDispatcher.convertMarkerAdd( name, range, viewWriter );\n\t\t\t}\n\t\t}\n\n\t\t// Clean `conversionApi`.\n\t\tdelete this.downcastDispatcher.conversionApi.options;\n\n\t\treturn viewDocumentFragment;\n\t}\n\n\t/**\n\t * Sets initial input data parsed by the {@link #processor data processor} and\n\t * converted by the {@link #upcastDispatcher view-to-model converters}.\n\t * Initial data can be set only to document that {@link module:engine/model/document~Document#version} is equal 0.\n\t *\n\t * **Note** This method is {@link module:utils/observablemixin~ObservableMixin#decorate decorated} which is\n\t * used by e.g. collaborative editing plugin that syncs remote data on init.\n\t *\n\t * When data is passed as a string it is initialized on a default `main` root:\n\t *\n\t *\t\tdataController.init( '<p>Foo</p>' ); // Initializes data on the `main` root.\n\t *\n\t * To initialize data on a different root or multiple roots at once, object containing `rootName` - `data` pairs should be passed:\n\t *\n\t *\t\tdataController.init( { main: '<p>Foo</p>', title: '<h1>Bar</h1>' } ); // Initializes data on the `main` and `title` roots.\n\t *\n\t * @fires init\n\t * @param {String|Object.<String,String>} data Input data as a string or an object containing `rootName` - `data`\n\t * pairs to initialize data on multiple roots at once.\n\t * @returns {Promise} Promise that is resolved after the data is set on the editor.\n\t */\n\tinit( data ) {\n\t\tif ( this.model.document.version ) {\n\t\t\t/**\n\t\t\t * Cannot set initial data to not empty {@link module:engine/model/document~Document}.\n\t\t\t * Initial data should be set once, during {@link module:core/editor/editor~Editor} initialization,\n\t\t\t * when the {@link module:engine/model/document~Document#version} is equal 0.\n\t\t\t *\n\t\t\t * @error datacontroller-init-document-not-empty\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'datacontroller-init-document-not-empty', this );\n\t\t}\n\n\t\tlet initialData = {};\n\t\tif ( typeof data === 'string' ) {\n\t\t\tinitialData.main = data; // Default root is 'main'. To initiate data on a different root, object should be passed.\n\t\t} else {\n\t\t\tinitialData = data;\n\t\t}\n\n\t\tif ( !this._checkIfRootsExists( Object.keys( initialData ) ) ) {\n\t\t\t/**\n\t\t\t * Cannot init data on a non-existing root. This error is thrown when {@link #init DataController#init() method}\n\t\t\t * is called with non-existent root name. For example, if there is an editor instance with only `main` root,\n\t\t\t * calling {@link #init} like:\n\t\t\t *\n\t\t\t * \t\tdata.init( { main: '<p>Foo</p>', root2: '<p>Bar</p>' } );\n\t\t\t *\n\t\t\t * will throw this error.\n\t\t\t *\n\t\t\t * @error datacontroller-init-non-existent-root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'datacontroller-init-non-existent-root', this );\n\t\t}\n\n\t\tthis.model.enqueueChange( 'transparent', writer => {\n\t\t\tfor ( const rootName of Object.keys( initialData ) ) {\n\t\t\t\tconst modelRoot = this.model.document.getRoot( rootName );\n\t\t\t\twriter.insert( this.parse( initialData[ rootName ], modelRoot ), modelRoot, 0 );\n\t\t\t}\n\t\t} );\n\n\t\treturn Promise.resolve();\n\t}\n\n\t/**\n\t * Sets input data parsed by the {@link #processor data processor} and\n\t * converted by the {@link #upcastDispatcher view-to-model converters}.\n\t * This method can be used any time to replace existing editor data by the new one without clearing the\n\t * {@link module:engine/model/document~Document#history document history}.\n\t *\n\t * This method also creates a batch with all the changes applied. If all you need is to parse data, use\n\t * the {@link #parse} method.\n\t *\n\t * When data is passed as a string it is set on a default `main` root:\n\t *\n\t *\t\tdataController.set( '<p>Foo</p>' ); // Sets data on the `main` root.\n\t *\n\t * To set data on a different root or multiple roots at once, object containing `rootName` - `data` pairs should be passed:\n\t *\n\t *\t\tdataController.set( { main: '<p>Foo</p>', title: '<h1>Bar</h1>' } ); // Sets data on the `main` and `title` roots.\n\t *\n\t * @fires set\n\t * @param {String|Object.<String,String>} data Input data as a string or an object containing `rootName` - `data`\n\t * pairs to set data on multiple roots at once.\n\t */\n\tset( data ) {\n\t\tlet newData = {};\n\n\t\tif ( typeof data === 'string' ) {\n\t\t\tnewData.main = data; // Default root is 'main'. To set data on a different root, object should be passed.\n\t\t} else {\n\t\t\tnewData = data;\n\t\t}\n\n\t\tif ( !this._checkIfRootsExists( Object.keys( newData ) ) ) {\n\t\t\t/**\n\t\t\t * Cannot set data on a non-existing root. This error is thrown when {@link #set DataController#set() method}\n\t\t\t * is called with non-existent root name. For example, if there is an editor instance with only `main` root,\n\t\t\t * calling {@link #set} like:\n\t\t\t *\n\t\t\t * \t\tdata.set( { main: '<p>Foo</p>', root2: '<p>Bar</p>' } );\n\t\t\t *\n\t\t\t * will throw this error.\n\t\t\t *\n\t\t\t * @error datacontroller-set-non-existent-root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'datacontroller-set-non-existent-root', this );\n\t\t}\n\n\t\tthis.model.enqueueChange( 'transparent', writer => {\n\t\t\twriter.setSelection( null );\n\t\t\twriter.removeSelectionAttribute( this.model.document.selection.getAttributeKeys() );\n\n\t\t\tfor ( const rootName of Object.keys( newData ) ) {\n\t\t\t\t// Save to model.\n\t\t\t\tconst modelRoot = this.model.document.getRoot( rootName );\n\n\t\t\t\twriter.remove( writer.createRangeIn( modelRoot ) );\n\t\t\t\twriter.insert( this.parse( newData[ rootName ], modelRoot ), modelRoot, 0 );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Returns the data parsed by the {@link #processor data processor} and then converted by upcast converters\n\t * attached to the {@link #upcastDispatcher}.\n\t *\n\t * @see #set\n\t * @param {String} data Data to parse.\n\t * @param {module:engine/model/schema~SchemaContextDefinition} [context='$root'] Base context in which the view will\n\t * be converted to the model. See: {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#convert}.\n\t * @returns {module:engine/model/documentfragment~DocumentFragment} Parsed data.\n\t */\n\tparse( data, context = '$root' ) {\n\t\t// data -> view\n\t\tconst viewDocumentFragment = this.processor.toView( data );\n\n\t\t// view -> model\n\t\treturn this.toModel( viewDocumentFragment, context );\n\t}\n\n\t/**\n\t * Returns the result of the given {@link module:engine/view/element~Element view element} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment view document fragment} converted by the\n\t * {@link #upcastDispatcher view-to-model converters}, wrapped by {@link module:engine/model/documentfragment~DocumentFragment}.\n\t *\n\t * When marker elements were converted during the conversion process, it will be set as a document fragment's\n\t * {@link module:engine/model/documentfragment~DocumentFragment#markers static markers map}.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} viewElementOrFragment\n\t * Element or document fragment whose content will be converted.\n\t * @param {module:engine/model/schema~SchemaContextDefinition} [context='$root'] Base context in which the view will\n\t * be converted to the model. See: {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#convert}.\n\t * @returns {module:engine/model/documentfragment~DocumentFragment} Output document fragment.\n\t */\n\ttoModel( viewElementOrFragment, context = '$root' ) {\n\t\treturn this.model.change( writer => {\n\t\t\treturn this.upcastDispatcher.convert( viewElementOrFragment, writer, context );\n\t\t} );\n\t}\n\n\t/**\n\t * Adds a style processor normalization rules.\n\t *\n\t * You can implement your own rules as well as use one of the available processor rules:\n\t *\n\t * * background: {@link module:engine/view/styles/background~addBackgroundRules}\n\t * * border: {@link module:engine/view/styles/border~addBorderRules}\n\t * * margin: {@link module:engine/view/styles/margin~addMarginRules}\n\t * * padding: {@link module:engine/view/styles/padding~addPaddingRules}\n\t *\n\t * @param {Function} callback\n\t */\n\taddStyleProcessorRules( callback ) {\n\t\tcallback( this.stylesProcessor );\n\t}\n\n\t/**\n\t * Removes all event listeners set by the DataController.\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Checks if all provided root names are existing editor roots.\n\t *\n\t * @private\n\t * @param {Array.<String>} rootNames Root names to check.\n\t * @returns {Boolean} Whether all provided root names are existing editor roots.\n\t */\n\t_checkIfRootsExists( rootNames ) {\n\t\tfor ( const rootName of rootNames ) {\n\t\t\tif ( !this.model.document.getRootNames().includes( rootName ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Event fired once the data initialization has finished.\n\t *\n\t * @event ready\n\t */\n\n\t/**\n\t * Event fired after the {@link #init `init()` method} was run. It can be {@link #listenTo listened to} in order to adjust or modify\n\t * the initialization flow. However, if the `init` event is stopped or prevented, the {@link #event:ready `ready` event}\n\t * should be fired manually.\n\t *\n\t * The `init` event is fired by the decorated {@link #init} method.\n\t * See {@link module:utils/observablemixin~ObservableMixin#decorate} for more information and samples.\n\t *\n\t * @event init\n\t */\n\n\t/**\n\t * Event fired after {@link #set set() method} has been run.\n\t *\n\t * The `set` event is fired by decorated {@link #set} method.\n\t * See {@link module:utils/observablemixin~ObservableMixin#decorate} for more information and samples.\n\t *\n\t * @event set\n\t */\n}\n\nmix( DataController, ObservableMixin );\n\n// Helper function for downcast conversion.\n//\n// Takes a document element (element that is added to a model document) and checks which markers are inside it\n// and which markers are containing it. If the marker is intersecting with element, the intersection is returned.\nfunction _getMarkersRelativeToElement( element ) {\n\tconst result = [];\n\tconst doc = element.root.document;\n\n\tif ( !doc ) {\n\t\treturn [];\n\t}\n\n\tconst elementRange = ModelRange._createIn( element );\n\n\tfor ( const marker of doc.model.markers ) {\n\t\tconst intersection = elementRange.getIntersection( marker.getRange() );\n\n\t\tif ( intersection ) {\n\t\t\tresult.push( [ marker.name, intersection ] );\n\t\t}\n\t}\n\n\treturn result;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/conversion/conversion\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport UpcastHelpers from './upcasthelpers';\nimport DowncastHelpers from './downcasthelpers';\nimport toArray from '@ckeditor/ckeditor5-utils/src/toarray';\n\n/**\n * A utility class that helps add converters to upcast and downcast dispatchers.\n *\n * We recommend reading the {@glink framework/guides/architecture/editing-engine Editing engine architecture} guide first to\n * understand the core concepts of the conversion mechanisms.\n *\n * An instance of the conversion manager is available in the\n * {@link module:core/editor/editor~Editor#conversion `editor.conversion`} property\n * and by default has the following groups of dispatchers (i.e. directions of conversion):\n *\n * * `downcast` (editing and data downcasts)\n * * `editingDowncast`\n * * `dataDowncast`\n * * `upcast`\n *\n * # One-way converters\n *\n * To add a converter to a specific group, use the {@link module:engine/conversion/conversion~Conversion#for `for()`}\n * method:\n *\n *\t\t// Add a converter to editing downcast and data downcast.\n *\t\teditor.conversion.for( 'downcast' ).elementToElement( config ) );\n *\n *\t\t// Add a converter to the data pipepline only:\n *\t\teditor.conversion.for( 'dataDowncast' ).elementToElement( dataConversionConfig ) );\n *\n *\t\t// And a slightly different one for the editing pipeline:\n *\t\teditor.conversion.for( 'editingDowncast' ).elementToElement( editingConversionConfig ) );\n *\n * See {@link module:engine/conversion/conversion~Conversion#for `for()`} method documentation to learn more about\n * available conversion helpers and how to use your custom ones.\n *\n * # Two-way converters\n *\n * Besides using one-way converters via the `for()` method, you can also use other methods available in this\n * class to add two-way converters (upcast and downcast):\n *\n * * {@link module:engine/conversion/conversion~Conversion#elementToElement `elementToElement()`} &ndash;\n * Model element to view element and vice versa.\n * * {@link module:engine/conversion/conversion~Conversion#attributeToElement `attributeToElement()`} &ndash;\n * Model attribute to view element and vice versa.\n * * {@link module:engine/conversion/conversion~Conversion#attributeToAttribute `attributeToAttribute()`} &ndash;\n * Model attribute to view element and vice versa.\n */\nexport default class Conversion {\n\t/**\n\t * Creates a new conversion instance.\n\t *\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastDispatcher|\n\t * Array.<module:engine/conversion/downcastdispatcher~DowncastDispatcher>} downcastDispatchers\n\t * @param {module:engine/conversion/upcastdispatcher~UpcastDispatcher|\n\t * Array.<module:engine/conversion/upcastdispatcher~UpcastDispatcher>} upcastDispatchers\n\t */\n\tconstructor( downcastDispatchers, upcastDispatchers ) {\n\t\t/**\n\t\t * Maps dispatchers group name to ConversionHelpers instances.\n\t\t *\n\t\t * @private\n\t\t * @member {Map.<String,module:engine/conversion/conversionhelpers~ConversionHelpers>}\n\t\t */\n\t\tthis._helpers = new Map();\n\n\t\t// Define default 'downcast' & 'upcast' dispatchers groups. Those groups are always available as two-way converters needs them.\n\t\tthis._downcast = toArray( downcastDispatchers );\n\t\tthis._createConversionHelpers( { name: 'downcast', dispatchers: this._downcast, isDowncast: true } );\n\n\t\tthis._upcast = toArray( upcastDispatchers );\n\t\tthis._createConversionHelpers( { name: 'upcast', dispatchers: this._upcast, isDowncast: false } );\n\t}\n\n\t/**\n\t * Define an alias for registered dispatcher.\n\t *\n\t *\t\tconst conversion = new Conversion(\n\t *\t\t\t[ dataDowncastDispatcher, editingDowncastDispatcher ],\n\t *\t\t\tupcastDispatcher\n\t *\t\t);\n\t *\n\t *\t\tconversion.addAlias( 'dataDowncast', dataDowncastDispatcher );\n\t *\n\t * @param {String} alias An alias of a dispatcher.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastDispatcher|\n\t * module:engine/conversion/upcastdispatcher~UpcastDispatcher} dispatcher Dispatcher which should have an alias.\n\t */\n\taddAlias( alias, dispatcher ) {\n\t\tconst isDowncast = this._downcast.includes( dispatcher );\n\t\tconst isUpcast = this._upcast.includes( dispatcher );\n\n\t\tif ( !isUpcast && !isDowncast ) {\n\t\t\t/**\n\t\t\t * Trying to register and alias for a dispatcher that nas not been registered.\n\t\t\t *\n\t\t\t * @error conversion-add-alias-dispatcher-not-registered\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'conversion-add-alias-dispatcher-not-registered',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tthis._createConversionHelpers( { name: alias, dispatchers: [ dispatcher ], isDowncast } );\n\t}\n\n\t/**\n\t * Provides a chainable API to assign converters to conversion dispatchers group.\n\t *\n\t * If the given group name has not been registered, the\n\t * {@link module:utils/ckeditorerror~CKEditorError `conversion-for-unknown-group` error} is thrown.\n\t *\n\t * You can use conversion helpers available directly in the `for()` chain or your custom ones via\n\t * the {@link module:engine/conversion/conversionhelpers~ConversionHelpers#add `add()`} method.\n\t *\n\t * # Using bulit-in conversion helpers\n\t *\n\t * The `for()` chain comes with a set of conversion helpers which you can use like this:\n\t *\n\t *\t\teditor.conversion.for( 'downcast' )\n\t *\t\t\t.elementToElement( config1 )        // Adds an element-to-element downcast converter.\n\t *\t\t\t.attributeToElement( config2 );     // Adds an attribute-to-element downcast converter.\n\t *\n\t *\t\teditor.conversion.for( 'upcast' )\n\t *\t\t\t.elementToAttribute( config3 );     // Adds an element-to-attribute upcast converter.\n\t *\n\t * Refer to the documentation of built-in conversion helpers to learn about their configuration options.\n\t *\n\t * * downcast (model-to-view) conversion helpers:\n\t *\n\t *\t* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`},\n\t *\t* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToElement `attributeToElement()`},\n\t *\t* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToAttribute `attributeToAttribute()`}.\n\t *\t* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToElement `markerToElement()`}.\n\t *\t* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToHighlight `markerToHighlight()`}.\n\t *\n\t * * upcast (view-to-model) conversion helpers:\n\t *\n\t *\t* {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToElement `elementToElement()`},\n\t *\t* {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToAttribute `elementToAttribute()`},\n\t *\t* {@link module:engine/conversion/upcasthelpers~UpcastHelpers#attributeToAttribute `attributeToAttribute()`}.\n\t *\t* {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToMarker `elementToMarker()`}.\n\t *\n\t * # Using custom conversion helpers\n\t *\n\t * If you need to implement a nontypical converter, you can do so by calling:\n\t *\n\t *\t\teditor.conversion.for( direction ).add( customHelper );\n\t *\n\t * The `.add()` method takes exactly one parameter, which is a function. This function should accept one parameter that\n\t * is a dispatcher instance. The function should add an actual converter to the passed dispatcher instance.\n\t *\n\t * Example:\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).add( dispatcher => {\n\t *\t\t\tdispatcher.on( 'element:a',  ( evt, data, conversionApi ) => {\n\t *\t\t\t\t// Do something with a view <a> element.\n\t *\t\t\t} );\n\t *\t\t} );\n\t *\n\t * Refer to the documentation of {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher}\n\t * and {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher} to learn how to write\n\t * custom converters.\n\t *\n\t * @param {String} groupName The name of dispatchers group to add the converters to.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers|module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\tfor( groupName ) {\n\t\tif ( !this._helpers.has( groupName ) ) {\n\t\t\t/**\n\t\t\t * Trying to add a converter to an unknown dispatchers group.\n\t\t\t *\n\t\t\t * @error conversion-for-unknown-group\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'conversion-for-unknown-group', this );\n\t\t}\n\n\t\treturn this._helpers.get( groupName );\n\t}\n\n\t/**\n\t * Sets up converters between the model and the view that convert a model element to a view element (and vice versa).\n\t * For example, the model `<paragraph>Foo</paragraph>` is `<p>Foo</p>` in the view.\n\t *\n\t *\t\t// A simple conversion from the `paragraph` model element to the `<p>` view element (and vice versa).\n\t *\t\teditor.conversion.elementToElement( { model: 'paragraph', view: 'p' } );\n\t *\n\t *\t\t// Override other converters by specifying a converter definition with a higher priority.\n\t *\t\teditor.conversion.elementToElement( { model: 'paragraph', view: 'div', converterPriority: 'high' } );\n\t *\n\t *\t\t// View specified as an object instead of a string.\n\t *\t\teditor.conversion.elementToElement( {\n\t *\t\t\tmodel: 'fancyParagraph',\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'p',\n\t *\t\t\t\tclasses: 'fancy'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Use `upcastAlso` to define other view elements that should also be converted to a `paragraph` element.\n\t *\t\teditor.conversion.elementToElement( {\n\t *\t\t\tmodel: 'paragraph',\n\t *\t\t\tview: 'p',\n\t *\t\t\tupcastAlso: [\n\t *\t\t\t\t'div',\n\t *\t\t\t\t{\n\t *\t\t\t\t\t// Any element with the `display: block` style.\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\tdisplay: 'block'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t *\t\t// `upcastAlso` set as callback enables a conversion of a wide range of different view elements.\n\t *\t\teditor.conversion.elementToElement( {\n\t *\t\t\tmodel: 'heading',\n\t *\t\t\tview: 'h2',\n\t *\t\t\t// Convert \"headling-like\" paragraphs to headings.\n\t *\t\t\tupcastAlso: viewElement => {\n\t *\t\t\t\tconst fontSize = viewElement.getStyle( 'font-size' );\n\t *\n\t *\t\t\t\tif ( !fontSize ) {\n\t *\t\t\t\t\treturn null;\n\t *\t\t\t\t}\n\t *\n\t *\t\t\t\tconst match = fontSize.match( /(\\d+)\\s*px/ );\n\t *\n\t *\t\t\t\tif ( !match ) {\n\t *\t\t\t\t\treturn null;\n\t *\t\t\t\t}\n\t *\n\t *\t\t\t\tconst size = Number( match[ 1 ] );\n\t *\n\t *\t\t\t\tif ( size > 26 ) {\n\t *\t\t\t\t\t// Returned value can be an object with the matched properties.\n\t *\t\t\t\t\t// These properties will be \"consumed\" during the conversion.\n\t *\t\t\t\t\t// See `engine.view.Matcher~MatcherPattern` and `engine.view.Matcher#match` for more details.\n\t *\n\t *\t\t\t\t\treturn { name: true, styles: [ 'font-size' ] };\n\t *\t\t\t\t}\n\t *\n\t *\t\t\t\treturn null;\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * `definition.model` is a `String` with a model element name to convert from or to.\n\t * See {@link module:engine/conversion/conversion~ConverterDefinition} to learn about other parameters.\n\t *\n\t * @param {module:engine/conversion/conversion~ConverterDefinition} definition The converter definition.\n\t */\n\telementToElement( definition ) {\n\t\t// Set up downcast converter.\n\t\tthis.for( 'downcast' ).elementToElement( definition );\n\n\t\t// Set up upcast converter.\n\t\tfor ( const { model, view } of _getAllUpcastDefinitions( definition ) ) {\n\t\t\tthis.for( 'upcast' )\n\t\t\t\t.elementToElement( {\n\t\t\t\t\tmodel,\n\t\t\t\t\tview,\n\t\t\t\t\tconverterPriority: definition.converterPriority\n\t\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Sets up converters between the model and the view that convert a model attribute to a view element (and vice versa).\n\t * For example, a model text node with `\"Foo\"` as data and the `bold` attribute is `<strong>Foo</strong>` in the view.\n\t *\n\t *\t\t// A simple conversion from the `bold=true` attribute to the `<strong>` view element (and vice versa).\n\t *\t\teditor.conversion.attributeToElement( { model: 'bold', view: 'strong' } );\n\t *\n\t *\t\t// Override other converters by specifying a converter definition with a higher priority.\n\t *\t\teditor.conversion.attributeToElement( { model: 'bold', view: 'b', converterPriority: 'high' } );\n\t *\n\t *\t\t// View specified as an object instead of a string.\n\t *\t\teditor.conversion.attributeToElement( {\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tclasses: 'bold'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Use `config.model.name` to define the conversion only from a given node type, `$text` in this case.\n\t *\t\t// The same attribute on different elements may then be handled by a different converter.\n\t *\t\teditor.conversion.attributeToElement( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'textDecoration',\n\t *\t\t\t\tvalues: [ 'underline', 'lineThrough' ],\n\t *\t\t\t\tname: '$text'\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\tunderline: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'text-decoration': 'underline'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t},\n\t *\t\t\t\tlineThrough: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'text-decoration': 'line-through'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Use `upcastAlso` to define other view elements that should also be converted to the `bold` attribute.\n\t *\t\teditor.conversion.attributeToElement( {\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tview: 'strong',\n\t *\t\t\tupcastAlso: [\n\t *\t\t\t\t'b',\n\t *\t\t\t\t{\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tclasses: 'bold'\n\t *\t\t\t\t},\n\t *\t\t\t\t{\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'font-weight': 'bold'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t},\n\t *\t\t\t\tviewElement => {\n\t *\t\t\t\t\tconst fontWeight = viewElement.getStyle( 'font-weight' );\n\t *\n\t *\t\t\t\t\tif ( viewElement.is( 'element', 'span' ) && fontWeight && /\\d+/.test() && Number( fontWeight ) > 500 ) {\n\t *\t\t\t\t\t\t// Returned value can be an object with the matched properties.\n\t *\t\t\t\t\t\t// These properties will be \"consumed\" during the conversion.\n\t *\t\t\t\t\t\t// See `engine.view.Matcher~MatcherPattern` and `engine.view.Matcher#match` for more details.\n\t *\n\t *\t\t\t\t\t\treturn {\n\t *\t\t\t\t\t\t\tname: true,\n\t *\t\t\t\t\t\t\tstyles: [ 'font-weight' ]\n\t *\t\t\t\t\t\t};\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t *\t\t// Conversion from and to a model attribute key whose value is an enum (`fontSize=big|small`).\n\t *\t\t// `upcastAlso` set as callback enables a conversion of a wide range of different view elements.\n\t *\t\teditor.conversion.attributeToElement( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'fontSize',\n\t *\t\t\t\tvalues: [ 'big', 'small' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\tbig: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'font-size': '1.2em'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t},\n\t *\t\t\t\tsmall: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'font-size': '0.8em'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tupcastAlso: {\n\t *\t\t\t\tbig: viewElement => {\n\t *\t\t\t\t\tconst fontSize = viewElement.getStyle( 'font-size' );\n\t *\n\t *\t\t\t\t\tif ( !fontSize ) {\n\t *\t\t\t\t\t\treturn null;\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\tconst match = fontSize.match( /(\\d+)\\s*px/ );\n\t *\n\t *\t\t\t\t\tif ( !match ) {\n\t *\t\t\t\t\t\treturn null;\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\tconst size = Number( match[ 1 ] );\n\t *\n\t *\t\t\t\t\tif ( viewElement.is( 'element', 'span' ) && size > 10 ) {\n\t *\t\t\t\t\t\t// Returned value can be an object with the matched properties.\n\t *\t\t\t\t\t\t// These properties will be \"consumed\" during the conversion.\n\t *\t\t\t\t\t\t// See `engine.view.Matcher~MatcherPattern` and `engine.view.Matcher#match` for more details.\n\t *\n\t *\t\t\t\t\t\treturn { name: true, styles: [ 'font-size' ] };\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\treturn null;\n\t *\t\t\t\t},\n\t *\t\t\t\tsmall: viewElement => {\n\t *\t\t\t\t\tconst fontSize = viewElement.getStyle( 'font-size' );\n\t *\n\t *\t\t\t\t\tif ( !fontSize ) {\n\t *\t\t\t\t\t\treturn null;\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\tconst match = fontSize.match( /(\\d+)\\s*px/ );\n\t *\n\t *\t\t\t\t\tif ( !match ) {\n\t *\t\t\t\t\t\treturn null;\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\tconst size = Number( match[ 1 ] );\n\t *\n\t *\t\t\t\t\tif ( viewElement.is( 'element', 'span' ) && size < 10 ) {\n\t *\t\t\t\t\t\t// Returned value can be an object with the matched properties.\n\t *\t\t\t\t\t\t// These properties will be \"consumed\" during the conversion.\n\t *\t\t\t\t\t\t// See `engine.view.Matcher~MatcherPattern` and `engine.view.Matcher#match` for more details.\n\t *\n\t *\t\t\t\t\t\treturn { name: true, styles: [ 'font-size' ] };\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\treturn null;\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * The `definition.model` parameter specifies which model attribute should be converted from or to. It can be a `{ key, value }` object\n\t * describing the attribute key and value to convert or a `String` specifying just the attribute key (then `value` is set to `true`).\n\t * See {@link module:engine/conversion/conversion~ConverterDefinition} to learn about other parameters.\n\t *\n\t * @param {module:engine/conversion/conversion~ConverterDefinition} definition The converter definition.\n\t */\n\tattributeToElement( definition ) {\n\t\t// Set up downcast converter.\n\t\tthis.for( 'downcast' ).attributeToElement( definition );\n\n\t\t// Set up upcast converter.\n\t\tfor ( const { model, view } of _getAllUpcastDefinitions( definition ) ) {\n\t\t\tthis.for( 'upcast' )\n\t\t\t\t.elementToAttribute( {\n\t\t\t\t\tview,\n\t\t\t\t\tmodel,\n\t\t\t\t\tconverterPriority: definition.converterPriority\n\t\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Sets up converters between the model and the view that convert a model attribute to a view attribute (and vice versa).\n\t * For example, `<image src='foo.jpg'></image>` is converted to `<img src='foo.jpg'></img>` (the same attribute key and value).\n\t * This type of converters is intended to be used with {@link module:engine/model/element~Element model element} nodes.\n\t * To convert text attributes {@link module:engine/conversion/conversion~Conversion#attributeToElement `attributeToElement converter`}\n\t * should be set up.\n\t *\n\t *\t\t// A simple conversion from the `source` model attribute to the `src` view attribute (and vice versa).\n\t *\t\teditor.conversion.attributeToAttribute( { model: 'source', view: 'src' } );\n\t *\n\t *\t\t// Attribute values are strictly specified.\n\t *\t\teditor.conversion.attributeToAttribute( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tname: 'image',\n\t *\t\t\t\tkey: 'aside',\n\t *\t\t\t\tvalues: [ 'aside' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\taside: {\n\t *\t\t\t\t\tname: 'img',\n\t *\t\t\t\t\tkey: 'class',\n\t *\t\t\t\t\tvalue: [ 'aside', 'half-size' ]\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Set the style attribute.\n\t *\t\teditor.conversion.attributeToAttribute( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tname: 'image',\n\t *\t\t\t\tkey: 'aside',\n\t *\t\t\t\tvalues: [ 'aside' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\taside: {\n\t *\t\t\t\t\tname: 'img',\n\t *\t\t\t\t\tkey: 'style',\n\t *\t\t\t\t\tvalue: {\n\t *\t\t\t\t\t\tfloat: 'right',\n\t *\t\t\t\t\t\twidth: '50%',\n\t *\t\t\t\t\t\tmargin: '5px'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Conversion from and to a model attribute key whose value is an enum (`align=right|center`).\n\t *\t\t// Use `upcastAlso` to define other view elements that should also be converted to the `align=right` attribute.\n\t *\t\teditor.conversion.attributeToAttribute( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'align',\n\t *\t\t\t\tvalues: [ 'right', 'center' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\tright: {\n\t *\t\t\t\t\tkey: 'class',\n\t *\t\t\t\t\tvalue: 'align-right'\n\t *\t\t\t\t},\n\t *\t\t\t\tcenter: {\n\t *\t\t\t\t\tkey: 'class',\n\t *\t\t\t\t\tvalue: 'align-center'\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tupcastAlso: {\n\t *\t\t\t\tright: {\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'text-align': 'right'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t},\n\t *\t\t\t\tcenter: {\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'text-align': 'center'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * The `definition.model` parameter specifies which model attribute should be converted from and to.\n\t * It can be a `{ key, [ values ], [ name ] }` object or a `String`, which will be treated like `{ key: definition.model }`.\n\t * The `key` property is the model attribute key to convert from and to.\n\t * The `values` are the possible model attribute values. If `values` is not set, the model attribute value will be the same as the\n\t * view attribute value.\n\t * If `name` is set, the conversion will be set up only for model elements with the given name.\n\t *\n\t * The `definition.view` parameter specifies which view attribute should be converted from and to.\n\t * It can be a `{ key, value, [ name ] }` object or a `String`, which will be treated like `{ key: definition.view }`.\n\t * The `key` property is the view attribute key to convert from and to.\n\t * The `value` is the view attribute value to convert from and to. If `definition.value` is not set, the view attribute value will be\n\t * the same as the model attribute value.\n\t * If `key` is `'class'`, `value` can be a `String` or an array of `String`s.\n\t * If `key` is `'style'`, `value` is an object with key-value pairs.\n\t * In other cases, `value` is a `String`.\n\t * If `name` is set, the conversion will be set up only for model elements with the given name.\n\t * If `definition.model.values` is set, `definition.view` is an object that assigns values from `definition.model.values`\n\t * to `{ key, value, [ name ] }` objects.\n\t *\n\t * `definition.upcastAlso` specifies which other matching view elements should also be upcast to the given model configuration.\n\t * If `definition.model.values` is set, `definition.upcastAlso` should be an object assigning values from `definition.model.values`\n\t * to {@link module:engine/view/matcher~MatcherPattern}s or arrays of {@link module:engine/view/matcher~MatcherPattern}s.\n\t *\n\t * **Note:** `definition.model` and `definition.view` form should be mirrored, so the same types of parameters should\n\t * be given in both parameters.\n\t *\n\t * @param {Object} definition The converter definition.\n\t * @param {String|Object} definition.model The model attribute to convert from and to.\n\t * @param {String|Object} definition.view The view attribute to convert from and to.\n\t * @param {module:engine/view/matcher~MatcherPattern|Array.<module:engine/view/matcher~MatcherPattern>} [definition.upcastAlso]\n\t * Any view element matching `definition.upcastAlso` will also be converted to the given model attribute. `definition.upcastAlso`\n\t * is used only if `config.model.values` is specified.\n\t */\n\tattributeToAttribute( definition ) {\n\t\t// Set up downcast converter.\n\t\tthis.for( 'downcast' ).attributeToAttribute( definition );\n\n\t\t// Set up upcast converter.\n\t\tfor ( const { model, view } of _getAllUpcastDefinitions( definition ) ) {\n\t\t\tthis.for( 'upcast' )\n\t\t\t\t.attributeToAttribute( {\n\t\t\t\t\tview,\n\t\t\t\t\tmodel\n\t\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Creates and caches conversion helpers for given dispatchers group.\n\t *\n\t * @private\n\t * @param {Object} options\n\t * @param {String} options.name Group name.\n\t * @param {Array.<module:engine/conversion/downcastdispatcher~DowncastDispatcher|\n\t * module:engine/conversion/upcastdispatcher~UpcastDispatcher>} options.dispatchers\n\t * @param {Boolean} options.isDowncast\n\t */\n\t_createConversionHelpers( { name, dispatchers, isDowncast } ) {\n\t\tif ( this._helpers.has( name ) ) {\n\t\t\t/**\n\t\t\t * Trying to register a group name that has already been registered.\n\t\t\t *\n\t\t\t * @error conversion-group-exists\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'conversion-group-exists', this );\n\t\t}\n\n\t\tconst helpers = isDowncast ? new DowncastHelpers( dispatchers ) : new UpcastHelpers( dispatchers );\n\n\t\tthis._helpers.set( name, helpers );\n\t}\n}\n\n/**\n * Defines how the model should be converted from and to the view.\n *\n * @typedef {Object} module:engine/conversion/conversion~ConverterDefinition\n *\n * @property {*} [model] The model conversion definition. Describes the model element or model attribute to convert. This parameter differs\n * for different functions that accept `ConverterDefinition`. See the description of the function to learn how to set it.\n * @property {module:engine/view/elementdefinition~ElementDefinition|Object} view The definition of the view element to convert from and\n * to. If `model` describes multiple values, `view` is an object that assigns these values (`view` object keys) to view element definitions\n * (`view` object values).\n * @property {module:engine/view/matcher~MatcherPattern|Array.<module:engine/view/matcher~MatcherPattern>} [upcastAlso]\n * Any view element matching `upcastAlso` will also be converted to the model. If `model` describes multiple values, `upcastAlso`\n * is an object that assigns these values (`upcastAlso` object keys) to {@link module:engine/view/matcher~MatcherPattern}s\n * (`upcastAlso` object values).\n * @property {module:utils/priorities~PriorityString} [converterPriority] The converter priority.\n */\n\n// Helper function that creates a joint array out of an item passed in `definition.view` and items passed in\n// `definition.upcastAlso`.\n//\n// @param {module:engine/conversion/conversion~ConverterDefinition} definition\n// @returns {Array} Array containing view definitions.\nfunction* _getAllUpcastDefinitions( definition ) {\n\tif ( definition.model.values ) {\n\t\tfor ( const value of definition.model.values ) {\n\t\t\tconst model = { key: definition.model.key, value };\n\t\t\tconst view = definition.view[ value ];\n\t\t\tconst upcastAlso = definition.upcastAlso ? definition.upcastAlso[ value ] : undefined;\n\n\t\t\tyield* _getUpcastDefinition( model, view, upcastAlso );\n\t\t}\n\t} else {\n\t\tyield* _getUpcastDefinition( definition.model, definition.view, definition.upcastAlso );\n\t}\n}\n\nfunction* _getUpcastDefinition( model, view, upcastAlso ) {\n\tyield { model, view };\n\n\tif ( upcastAlso ) {\n\t\tfor ( const upcastAlsoItem of toArray( upcastAlso ) ) {\n\t\t\tyield { model, view: upcastAlsoItem };\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/batch\n */\n\n/**\n * A batch instance groups model changes ({@link module:engine/model/operation/operation~Operation operations}). All operations\n * grouped in a single batch can be reverted together, so you can also think about a batch as of a single undo step. If you want\n * to extend a given undo step, you can add more changes to the batch using {@link module:engine/model/model~Model#enqueueChange}:\n *\n *\t\tmodel.enqueueChange( batch, writer => {\n *\t\t\twriter.insertText( 'foo', paragraph, 'end' );\n *\t\t} );\n *\n * @see module:engine/model/model~Model#enqueueChange\n * @see module:engine/model/model~Model#change\n */\nexport default class Batch {\n\t/**\n\t * Creates a batch instance.\n\t *\n\t * @see module:engine/model/model~Model#enqueueChange\n\t * @see module:engine/model/model~Model#change\n\t * @param {'transparent'|'default'} [type='default'] The type of the batch.\n\t */\n\tconstructor( type = 'default' ) {\n\t\t/**\n\t\t * An array of operations that compose this batch.\n\t\t *\n\t\t * @readonly\n\t\t * @type {Array.<module:engine/model/operation/operation~Operation>}\n\t\t */\n\t\tthis.operations = [];\n\n\t\t/**\n\t\t * The type of the batch.\n\t\t *\n\t\t * It can be one of the following values:\n\t\t * * `'default'` &ndash; All \"normal\" batches. This is the most commonly used type.\n\t\t * * `'transparent'` &ndash; A batch that should be ignored by other features, i.e. an initial batch or collaborative editing\n\t\t * changes.\n\t\t *\n\t\t * @readonly\n\t\t * @type {'transparent'|'default'}\n\t\t */\n\t\tthis.type = type;\n\t}\n\n\t/**\n\t * Returns the base version of this batch, which is equal to the base version of the first operation in the batch.\n\t * If there are no operations in the batch or neither operation has the base version set, it returns `null`.\n\t *\n\t * @readonly\n\t * @type {Number|null}\n\t */\n\tget baseVersion() {\n\t\tfor ( const op of this.operations ) {\n\t\t\tif ( op.baseVersion !== null ) {\n\t\t\t\treturn op.baseVersion;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Adds an operation to the batch instance.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation An operation to add.\n\t * @returns {module:engine/model/operation/operation~Operation} The added operation.\n\t */\n\taddOperation( operation ) {\n\t\toperation.batch = this;\n\t\tthis.operations.push( operation );\n\n\t\treturn operation;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/operation\n */\n\n/**\n * Abstract base operation class.\n *\n * @abstract\n */\nexport default class Operation {\n\t/**\n\t * Base operation constructor.\n\t *\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( baseVersion ) {\n\t\t/**\n\t\t * {@link module:engine/model/document~Document#version} on which operation can be applied. If you try to\n\t\t * {@link module:engine/model/model~Model#applyOperation apply} operation with different base version than the\n\t\t * {@link module:engine/model/document~Document#version document version} the\n\t\t * {@link module:utils/ckeditorerror~CKEditorError model-document-applyOperation-wrong-version} error is thrown.\n\t\t *\n\t\t * @member {Number}\n\t\t */\n\t\tthis.baseVersion = baseVersion;\n\n\t\t/**\n\t\t * Defines whether operation is executed on attached or detached {@link module:engine/model/item~Item items}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} #isDocumentOperation\n\t\t */\n\t\tthis.isDocumentOperation = this.baseVersion !== null;\n\n\t\t/**\n\t\t * {@link module:engine/model/batch~Batch Batch} to which the operation is added or `null` if the operation is not\n\t\t * added to any batch yet.\n\t\t *\n\t\t * @member {module:engine/model/batch~Batch|null} #batch\n\t\t */\n\t\tthis.batch = null;\n\n\t\t/**\n\t\t * Operation type.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} #type\n\t\t */\n\n\t\t/**\n\t\t * Creates and returns an operation that has the same parameters as this operation.\n\t\t *\n\t\t * @method #clone\n\t\t * @returns {module:engine/model/operation/operation~Operation} Clone of this operation.\n\t\t */\n\n\t\t/**\n\t\t * Creates and returns a reverse operation. Reverse operation when executed right after\n\t\t * the original operation will bring back tree model state to the point before the original\n\t\t * operation execution. In other words, it reverses changes done by the original operation.\n\t\t *\n\t\t * Keep in mind that tree model state may change since executing the original operation,\n\t\t * so reverse operation will be \"outdated\". In that case you will need to transform it by\n\t\t * all operations that were executed after the original operation.\n\t\t *\n\t\t * @method #getReversed\n\t\t * @returns {module:engine/model/operation/operation~Operation} Reversed operation.\n\t\t */\n\n\t\t/**\n\t\t * Executes the operation - modifications described by the operation properties will be applied to the model tree.\n\t\t *\n\t\t * @protected\n\t\t * @method #_execute\n\t\t */\n\t}\n\n\t/**\n\t * Checks whether the operation's parameters are correct and the operation can be correctly executed. Throws\n\t * an error if operation is not valid.\n\t *\n\t * @protected\n\t * @method #_validate\n\t */\n\t_validate() {\n\t}\n\n\t/**\n\t * Custom toJSON method to solve child-parent circular dependencies.\n\t *\n\t * @method #toJSON\n\t * @returns {Object} Clone of this object with the operation property replaced with string.\n\t */\n\ttoJSON() {\n\t\t// This method creates only a shallow copy, all nested objects should be defined separately.\n\t\t// See https://github.com/ckeditor/ckeditor5-engine/issues/1477.\n\t\tconst json = Object.assign( {}, this );\n\n\t\tjson.__className = this.constructor.className;\n\n\t\t// Remove reference to the parent `Batch` to avoid circular dependencies.\n\t\tdelete json.batch;\n\n\t\t// Only document operations are shared with other clients so it is not necessary to keep this information.\n\t\tdelete json.isDocumentOperation;\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Name of the operation class used for serialization.\n\t *\n\t * @type {String}\n\t */\n\tstatic get className() {\n\t\treturn 'Operation';\n\t}\n\n\t/**\n\t * Creates Operation object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} doc Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/operation~Operation}\n\t */\n\tstatic fromJSON( json ) {\n\t\treturn new this( json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( this.toString() );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module module:engine/model/documentfragment\n */\n\nimport NodeList from './nodelist';\nimport Element from './element';\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\n\n// @if CK_DEBUG_ENGINE // const { stringifyMap } = require( '../dev-utils/utils' );\n\n/**\n * DocumentFragment represents a part of model which does not have a common root but it's top-level nodes\n * can be seen as siblings. In other words, it is a detached part of model tree, without a root.\n *\n * DocumentFragment has own {@link module:engine/model/markercollection~MarkerCollection}. Markers from this collection\n * will be set to the {@link module:engine/model/model~Model#markers model markers} by a\n * {@link module:engine/model/writer~Writer#insert} function.\n */\nexport default class DocumentFragment {\n\t/**\n\t * Creates an empty `DocumentFragment`.\n\t *\n\t * **Note:** Constructor of this class shouldn't be used directly in the code.\n\t * Use the {@link module:engine/model/writer~Writer#createDocumentFragment} method instead.\n\t *\n\t * @protected\n\t * @param {module:engine/model/node~Node|Iterable.<module:engine/model/node~Node>} [children]\n\t * Nodes to be contained inside the `DocumentFragment`.\n\t */\n\tconstructor( children ) {\n\t\t/**\n\t\t * DocumentFragment static markers map. This is a list of names and {@link module:engine/model/range~Range ranges}\n\t\t * which will be set as Markers to {@link module:engine/model/model~Model#markers model markers collection}\n\t\t * when DocumentFragment will be inserted to the document.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Map<String,module:engine/model/range~Range>} module:engine/model/documentfragment~DocumentFragment#markers\n\t\t */\n\t\tthis.markers = new Map();\n\n\t\t/**\n\t\t * List of nodes contained inside the document fragment.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/nodelist~NodeList} module:engine/model/documentfragment~DocumentFragment#_children\n\t\t */\n\t\tthis._children = new NodeList();\n\n\t\tif ( children ) {\n\t\t\tthis._insertChild( 0, children );\n\t\t}\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all nodes contained inside this document fragment.\n\t *\n\t * @returns {Iterable.<module:engine/model/node~Node>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this.getChildren();\n\t}\n\n\t/**\n\t * Number of this document fragment's children.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget childCount() {\n\t\treturn this._children.length;\n\t}\n\n\t/**\n\t * Sum of {@link module:engine/model/node~Node#offsetSize offset sizes} of all of this document fragment's children.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget maxOffset() {\n\t\treturn this._children.maxOffset;\n\t}\n\n\t/**\n\t * Is `true` if there are no nodes inside this document fragment, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isEmpty() {\n\t\treturn this.childCount === 0;\n\t}\n\n\t/**\n\t * Artificial root of `DocumentFragment`. Returns itself. Added for compatibility reasons.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Artificial parent of `DocumentFragment`. Returns `null`. Added for compatibility reasons.\n\t *\n\t * @readonly\n\t * @type {null}\n\t */\n\tget parent() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tdocFrag.is( 'documentFragment' ); // -> true\n\t *\t\tdocFrag.is( 'model:documentFragment' ); // -> true\n\t *\n\t *\t\tdocFrag.is( 'view:documentFragment' ); // -> false\n\t *\t\tdocFrag.is( 'element' ); // -> false\n\t *\t\tdocFrag.is( 'node' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'documentFragment' || type === 'model:documentFragment';\n\t}\n\n\t/**\n\t * Gets the child at the given index. Returns `null` if incorrect index was passed.\n\t *\n\t * @param {Number} index Index of child.\n\t * @returns {module:engine/model/node~Node|null} Child node.\n\t */\n\tgetChild( index ) {\n\t\treturn this._children.getNode( index );\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all of this document fragment's children.\n\t *\n\t * @returns {Iterable.<module:engine/model/node~Node>}\n\t */\n\tgetChildren() {\n\t\treturn this._children[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Returns an index of the given child node. Returns `null` if given node is not a child of this document fragment.\n\t *\n\t * @param {module:engine/model/node~Node} node Child node to look for.\n\t * @returns {Number|null} Child node's index.\n\t */\n\tgetChildIndex( node ) {\n\t\treturn this._children.getNodeIndex( node );\n\t}\n\n\t/**\n\t * Returns the starting offset of given child. Starting offset is equal to the sum of\n\t * {@link module:engine/model/node~Node#offsetSize offset sizes} of all node's siblings that are before it. Returns `null` if\n\t * given node is not a child of this document fragment.\n\t *\n\t * @param {module:engine/model/node~Node} node Child node to look for.\n\t * @returns {Number|null} Child node's starting offset.\n\t */\n\tgetChildStartOffset( node ) {\n\t\treturn this._children.getNodeStartOffset( node );\n\t}\n\n\t/**\n\t * Returns path to a `DocumentFragment`, which is an empty array. Added for compatibility reasons.\n\t *\n\t * @returns {Array}\n\t */\n\tgetPath() {\n\t\treturn [];\n\t}\n\n\t/**\n\t * Returns a descendant node by its path relative to this element.\n\t *\n\t *\t\t// <this>a<b>c</b></this>\n\t *\t\tthis.getNodeByPath( [ 0 ] );     // -> \"a\"\n\t *\t\tthis.getNodeByPath( [ 1 ] );     // -> <b>\n\t *\t\tthis.getNodeByPath( [ 1, 0 ] );  // -> \"c\"\n\t *\n\t * @param {Array.<Number>} relativePath Path of the node to find, relative to this element.\n\t * @returns {module:engine/model/node~Node|module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tgetNodeByPath( relativePath ) {\n\t\tlet node = this; // eslint-disable-line consistent-this\n\n\t\tfor ( const index of relativePath ) {\n\t\t\tnode = node.getChild( node.offsetToIndex( index ) );\n\t\t}\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Converts offset \"position\" to index \"position\".\n\t *\n\t * Returns index of a node that occupies given offset. If given offset is too low, returns `0`. If given offset is\n\t * too high, returns index after last child}.\n\t *\n\t *\t\tconst textNode = new Text( 'foo' );\n\t *\t\tconst pElement = new Element( 'p' );\n\t *\t\tconst docFrag = new DocumentFragment( [ textNode, pElement ] );\n\t *\t\tdocFrag.offsetToIndex( -1 ); // Returns 0, because offset is too low.\n\t *\t\tdocFrag.offsetToIndex( 0 ); // Returns 0, because offset 0 is taken by `textNode` which is at index 0.\n\t *\t\tdocFrag.offsetToIndex( 1 ); // Returns 0, because `textNode` has `offsetSize` equal to 3, so it occupies offset 1 too.\n\t *\t\tdocFrag.offsetToIndex( 2 ); // Returns 0.\n\t *\t\tdocFrag.offsetToIndex( 3 ); // Returns 1.\n\t *\t\tdocFrag.offsetToIndex( 4 ); // Returns 2. There are no nodes at offset 4, so last available index is returned.\n\t *\n\t * @param {Number} offset Offset to look for.\n\t * @returns {Number} Index of a node that occupies given offset.\n\t */\n\toffsetToIndex( offset ) {\n\t\treturn this._children.offsetToIndex( offset );\n\t}\n\n\t/**\n\t * Converts `DocumentFragment` instance to plain object and returns it.\n\t * Takes care of converting all of this document fragment's children.\n\t *\n\t * @returns {Object} `DocumentFragment` instance converted to plain object.\n\t */\n\ttoJSON() {\n\t\tconst json = [];\n\n\t\tfor ( const node of this._children ) {\n\t\t\tjson.push( node.toJSON() );\n\t\t}\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Creates a `DocumentFragment` instance from given plain object (i.e. parsed JSON string).\n\t * Converts `DocumentFragment` children to proper nodes.\n\t *\n\t * @param {Object} json Plain object to be converted to `DocumentFragment`.\n\t * @returns {module:engine/model/documentfragment~DocumentFragment} `DocumentFragment` instance created using given plain object.\n\t */\n\tstatic fromJSON( json ) {\n\t\tconst children = [];\n\n\t\tfor ( const child of json ) {\n\t\t\tif ( child.name ) {\n\t\t\t\t// If child has name property, it is an Element.\n\t\t\t\tchildren.push( Element.fromJSON( child ) );\n\t\t\t} else {\n\t\t\t\t// Otherwise, it is a Text node.\n\t\t\t\tchildren.push( Text.fromJSON( child ) );\n\t\t\t}\n\t\t}\n\n\t\treturn new DocumentFragment( children );\n\t}\n\n\t/**\n\t * {@link #_insertChild Inserts} one or more nodes at the end of this document fragment.\n\t *\n\t * @protected\n\t * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} items Items to be inserted.\n\t */\n\t_appendChild( items ) {\n\t\tthis._insertChild( this.childCount, items );\n\t}\n\n\t/**\n\t * Inserts one or more nodes at the given index and sets {@link module:engine/model/node~Node#parent parent} of these nodes\n\t * to this document fragment.\n\t *\n\t * @protected\n\t * @param {Number} index Index at which nodes should be inserted.\n\t * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} items Items to be inserted.\n\t */\n\t_insertChild( index, items ) {\n\t\tconst nodes = normalize( items );\n\n\t\tfor ( const node of nodes ) {\n\t\t\t// If node that is being added to this element is already inside another element, first remove it from the old parent.\n\t\t\tif ( node.parent !== null ) {\n\t\t\t\tnode._remove();\n\t\t\t}\n\n\t\t\tnode.parent = this;\n\t\t}\n\n\t\tthis._children._insertNodes( index, nodes );\n\t}\n\n\t/**\n\t * Removes one or more nodes starting at the given index\n\t * and sets {@link module:engine/model/node~Node#parent parent} of these nodes to `null`.\n\t *\n\t * @protected\n\t * @param {Number} index Index of the first node to remove.\n\t * @param {Number} [howMany=1] Number of nodes to remove.\n\t * @returns {Array.<module:engine/model/node~Node>} Array containing removed nodes.\n\t */\n\t_removeChildren( index, howMany = 1 ) {\n\t\tconst nodes = this._children._removeNodes( index, howMany );\n\n\t\tfor ( const node of nodes ) {\n\t\t\tnode.parent = null;\n\t\t}\n\n\t\treturn nodes;\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn 'documentFragment';\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelDocumentFragment: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // printTree() {\n\t// @if CK_DEBUG_ENGINE //\tlet string = 'ModelDocumentFragment: [';\n\n\t// @if CK_DEBUG_ENGINE //\tfor ( const child of this.getChildren() ) {\n\t// @if CK_DEBUG_ENGINE //\t\tstring += '\\n';\n\n\t// @if CK_DEBUG_ENGINE //\t\tif ( child.is( '$text' ) ) {\n\t// @if CK_DEBUG_ENGINE //\t\t\tconst textAttrs = stringifyMap( child._attrs );\n\n\t// @if CK_DEBUG_ENGINE //\t\t\tstring += '\\t'.repeat( 1 );\n\n\t// @if CK_DEBUG_ENGINE //\t\t\tif ( textAttrs !== '' ) {\n\t// @if CK_DEBUG_ENGINE //\t\t\t\tstring += `<$text${ textAttrs }>` + child.data + '</$text>';\n\t// @if CK_DEBUG_ENGINE //\t\t\t} else {\n\t// @if CK_DEBUG_ENGINE //\t\t\t\tstring += child.data;\n\t// @if CK_DEBUG_ENGINE //\t\t\t}\n\t// @if CK_DEBUG_ENGINE //\t\t} else {\n\t// @if CK_DEBUG_ENGINE //\t\t\tstring += child.printTree( 1 );\n\t// @if CK_DEBUG_ENGINE //\t\t}\n\t// @if CK_DEBUG_ENGINE //\t}\n\n\t// @if CK_DEBUG_ENGINE //\tstring += '\\n]';\n\n\t// @if CK_DEBUG_ENGINE //\treturn string;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logTree() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( this.printTree() );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\n// Converts strings to Text and non-iterables to arrays.\n//\n// @param {String|module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>}\n// @returns {Iterable.<module:engine/model/node~Node>}\nfunction normalize( nodes ) {\n\t// Separate condition because string is iterable.\n\tif ( typeof nodes == 'string' ) {\n\t\treturn [ new Text( nodes ) ];\n\t}\n\n\tif ( !isIterable( nodes ) ) {\n\t\tnodes = [ nodes ];\n\t}\n\n\t// Array.from to enable .map() on non-arrays.\n\treturn Array.from( nodes )\n\t\t.map( node => {\n\t\t\tif ( typeof node == 'string' ) {\n\t\t\t\treturn new Text( node );\n\t\t\t}\n\n\t\t\tif ( node instanceof TextProxy ) {\n\t\t\t\treturn new Text( node.data, node.getAttributes() );\n\t\t\t}\n\n\t\t\treturn node;\n\t\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/utils\n */\n\nimport Node from '../node';\nimport Text from '../text';\nimport TextProxy from '../textproxy';\nimport Range from '../range';\nimport DocumentFragment from '../documentfragment';\nimport NodeList from '../nodelist';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Contains functions used for composing model tree by {@link module:engine/model/operation/operation~Operation operations}.\n * Those functions are built on top of {@link module:engine/model/node~Node node}, and it's child classes', APIs.\n *\n * @protected\n * @namespace utils\n */\n\n/**\n * Inserts given nodes at given position.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils.insert\n * @param {module:engine/model/position~Position} position Position at which nodes should be inserted.\n * @param {module:engine/model/node~NodeSet} nodes Nodes to insert.\n * @returns {module:engine/model/range~Range} Range spanning over inserted elements.\n */\nexport function _insert( position, nodes ) {\n\tnodes = _normalizeNodes( nodes );\n\n\t// We have to count offset before inserting nodes because they can get merged and we would get wrong offsets.\n\tconst offset = nodes.reduce( ( sum, node ) => sum + node.offsetSize, 0 );\n\tconst parent = position.parent;\n\n\t// Insertion might be in a text node, we should split it if that's the case.\n\t_splitNodeAtPosition( position );\n\tconst index = position.index;\n\n\t// Insert nodes at given index. After splitting we have a proper index and insertion is between nodes,\n\t// using basic `Element` API.\n\tparent._insertChild( index, nodes );\n\n\t// Merge text nodes, if possible. Merging is needed only at points where inserted nodes \"touch\" \"old\" nodes.\n\t_mergeNodesAtIndex( parent, index + nodes.length );\n\t_mergeNodesAtIndex( parent, index );\n\n\treturn new Range( position, position.getShiftedBy( offset ) );\n}\n\n/**\n * Removed nodes in given range. Only {@link module:engine/model/range~Range#isFlat flat} ranges are accepted.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils._remove\n * @param {module:engine/model/range~Range} range Range containing nodes to remove.\n * @returns {Array.<module:engine/model/node~Node>}\n */\nexport function _remove( range ) {\n\tif ( !range.isFlat ) {\n\t\t/**\n\t\t * Trying to remove a range which starts and ends in different element.\n\t\t *\n\t\t * @error operation-utils-remove-range-not-flat\n\t\t */\n\t\tthrow new CKEditorError(\n\t\t\t'operation-utils-remove-range-not-flat',\n\t\t\tthis\n\t\t);\n\t}\n\n\tconst parent = range.start.parent;\n\n\t// Range may be inside text nodes, we have to split them if that's the case.\n\t_splitNodeAtPosition( range.start );\n\t_splitNodeAtPosition( range.end );\n\n\t// Remove the text nodes using basic `Element` API.\n\tconst removed = parent._removeChildren( range.start.index, range.end.index - range.start.index );\n\n\t// Merge text nodes, if possible. After some nodes were removed, node before and after removed range will be\n\t// touching at the position equal to the removed range beginning. We check merging possibility there.\n\t_mergeNodesAtIndex( parent, range.start.index );\n\n\treturn removed;\n}\n\n/**\n * Moves nodes in given range to given target position. Only {@link module:engine/model/range~Range#isFlat flat} ranges are accepted.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils.move\n * @param {module:engine/model/range~Range} sourceRange Range containing nodes to move.\n * @param {module:engine/model/position~Position} targetPosition Position to which nodes should be moved.\n * @returns {module:engine/model/range~Range} Range containing moved nodes.\n */\nexport function _move( sourceRange, targetPosition ) {\n\tif ( !sourceRange.isFlat ) {\n\t\t/**\n\t\t * Trying to move a range which starts and ends in different element.\n\t\t *\n\t\t * @error operation-utils-move-range-not-flat\n\t\t */\n\t\tthrow new CKEditorError(\n\t\t\t'operation-utils-move-range-not-flat',\n\t\t\tthis\n\t\t);\n\t}\n\n\tconst nodes = _remove( sourceRange );\n\n\t// We have to fix `targetPosition` because model changed after nodes from `sourceRange` got removed and\n\t// that change might have an impact on `targetPosition`.\n\ttargetPosition = targetPosition._getTransformedByDeletion( sourceRange.start, sourceRange.end.offset - sourceRange.start.offset );\n\n\treturn _insert( targetPosition, nodes );\n}\n\n/**\n * Sets given attribute on nodes in given range. The attributes are only set on top-level nodes of the range, not on its children.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils._setAttribute\n * @param {module:engine/model/range~Range} range Range containing nodes that should have the attribute set. Must be a flat range.\n * @param {String} key Key of attribute to set.\n * @param {*} value Attribute value.\n */\nexport function _setAttribute( range, key, value ) {\n\t// Range might start or end in text nodes, so we have to split them.\n\t_splitNodeAtPosition( range.start );\n\t_splitNodeAtPosition( range.end );\n\n\t// Iterate over all items in the range.\n\tfor ( const item of range.getItems( { shallow: true } ) ) {\n\t\t// Iterator will return `TextProxy` instances but we know that those text proxies will\n\t\t// always represent full text nodes (this is guaranteed thanks to splitting we did before).\n\t\t// So, we can operate on those text proxies' text nodes.\n\t\tconst node = item.is( '$textProxy' ) ? item.textNode : item;\n\n\t\tif ( value !== null ) {\n\t\t\tnode._setAttribute( key, value );\n\t\t} else {\n\t\t\tnode._removeAttribute( key );\n\t\t}\n\n\t\t// After attributes changing it may happen that some text nodes can be merged. Try to merge with previous node.\n\t\t_mergeNodesAtIndex( node.parent, node.index );\n\t}\n\n\t// Try to merge last changed node with it's previous sibling (not covered by the loop above).\n\t_mergeNodesAtIndex( range.end.parent, range.end.index );\n}\n\n/**\n * Normalizes given object or an array of objects to an array of {@link module:engine/model/node~Node nodes}. See\n * {@link module:engine/model/node~NodeSet NodeSet} for details on how normalization is performed.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils.normalizeNodes\n * @param {module:engine/model/node~NodeSet} nodes Objects to normalize.\n * @returns {Array.<module:engine/model/node~Node>} Normalized nodes.\n */\nexport function _normalizeNodes( nodes ) {\n\tconst normalized = [];\n\n\tif ( !( nodes instanceof Array ) ) {\n\t\tnodes = [ nodes ];\n\t}\n\n\t// Convert instances of classes other than Node.\n\tfor ( let i = 0; i < nodes.length; i++ ) {\n\t\tif ( typeof nodes[ i ] == 'string' ) {\n\t\t\tnormalized.push( new Text( nodes[ i ] ) );\n\t\t} else if ( nodes[ i ] instanceof TextProxy ) {\n\t\t\tnormalized.push( new Text( nodes[ i ].data, nodes[ i ].getAttributes() ) );\n\t\t} else if ( nodes[ i ] instanceof DocumentFragment || nodes[ i ] instanceof NodeList ) {\n\t\t\tfor ( const child of nodes[ i ] ) {\n\t\t\t\tnormalized.push( child );\n\t\t\t}\n\t\t} else if ( nodes[ i ] instanceof Node ) {\n\t\t\tnormalized.push( nodes[ i ] );\n\t\t}\n\t\t// Skip unrecognized type.\n\t}\n\n\t// Merge text nodes.\n\tfor ( let i = 1; i < normalized.length; i++ ) {\n\t\tconst node = normalized[ i ];\n\t\tconst prev = normalized[ i - 1 ];\n\n\t\tif ( node instanceof Text && prev instanceof Text && _haveSameAttributes( node, prev ) ) {\n\t\t\t// Doing this instead changing `prev.data` because `data` is readonly.\n\t\t\tnormalized.splice( i - 1, 2, new Text( prev.data + node.data, prev.getAttributes() ) );\n\t\t\ti--;\n\t\t}\n\t}\n\n\treturn normalized;\n}\n\n// Checks if nodes before and after given index in given element are {@link module:engine/model/text~Text text nodes} and\n// merges them into one node if they have same attributes.\n//\n// Merging is done by removing two text nodes and inserting a new text node containing data from both merged text nodes.\n//\n// @private\n// @param {module:engine/model/element~Element} element Parent element of nodes to merge.\n// @param {Number} index Index between nodes to merge.\nfunction _mergeNodesAtIndex( element, index ) {\n\tconst nodeBefore = element.getChild( index - 1 );\n\tconst nodeAfter = element.getChild( index );\n\n\t// Check if both of those nodes are text objects with same attributes.\n\tif ( nodeBefore && nodeAfter && nodeBefore.is( '$text' ) && nodeAfter.is( '$text' ) && _haveSameAttributes( nodeBefore, nodeAfter ) ) {\n\t\t// Append text of text node after index to the before one.\n\t\tconst mergedNode = new Text( nodeBefore.data + nodeAfter.data, nodeBefore.getAttributes() );\n\n\t\t// Remove separate text nodes.\n\t\telement._removeChildren( index - 1, 2 );\n\n\t\t// Insert merged text node.\n\t\telement._insertChild( index - 1, mergedNode );\n\t}\n}\n\n// Checks if given position is in a text node, and if so, splits the text node in two text nodes, each of them\n// containing a part of original text node.\n//\n// @private\n// @param {module:engine/model/position~Position} position Position at which node should be split.\nfunction _splitNodeAtPosition( position ) {\n\tconst textNode = position.textNode;\n\tconst element = position.parent;\n\n\tif ( textNode ) {\n\t\tconst offsetDiff = position.offset - textNode.startOffset;\n\t\tconst index = textNode.index;\n\n\t\telement._removeChildren( index, 1 );\n\n\t\tconst firstPart = new Text( textNode.data.substr( 0, offsetDiff ), textNode.getAttributes() );\n\t\tconst secondPart = new Text( textNode.data.substr( offsetDiff ), textNode.getAttributes() );\n\n\t\telement._insertChild( index, [ firstPart, secondPart ] );\n\t}\n}\n\n// Checks whether two given nodes have same attributes.\n//\n// @private\n// @param {module:engine/model/node~Node} nodeA Node to check.\n// @param {module:engine/model/node~Node} nodeB Node to check.\n// @returns {Boolean} `true` if nodes have same attributes, `false` otherwise.\nfunction _haveSameAttributes( nodeA, nodeB ) {\n\tconst iteratorA = nodeA.getAttributes();\n\tconst iteratorB = nodeB.getAttributes();\n\n\tfor ( const attr of iteratorA ) {\n\t\tif ( attr[ 1 ] !== nodeB.getAttribute( attr[ 0 ] ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\titeratorB.next();\n\t}\n\n\treturn iteratorB.next().done;\n}\n\n/**\n * Value that can be normalized to an array of {@link module:engine/model/node~Node nodes}.\n *\n * Non-arrays are normalized as follows:\n * * {@link module:engine/model/node~Node Node} is left as is,\n * * {@link module:engine/model/textproxy~TextProxy TextProxy} and `String` are normalized to {@link module:engine/model/text~Text Text},\n * * {@link module:engine/model/nodelist~NodeList NodeList} is normalized to an array containing all nodes that are in that node list,\n * * {@link module:engine/model/documentfragment~DocumentFragment DocumentFragment} is normalized to an array containing all of it's\n * * children.\n *\n * Arrays are processed item by item like non-array values and flattened to one array. Normalization always results in\n * a flat array of {@link module:engine/model/node~Node nodes}. Consecutive text nodes (or items normalized to text nodes) will be\n * merged if they have same attributes.\n *\n * @typedef {module:engine/model/node~Node|module:engine/model/textproxy~TextProxy|String|\n * module:engine/model/nodelist~NodeList|module:engine/model/documentfragment~DocumentFragment|Iterable}\n * module:engine/model/node~NodeSet\n */\n","import baseIsEqual from './_baseIsEqual.js';\n\n/**\n * Performs a deep comparison between two values to determine if they are\n * equivalent.\n *\n * **Note:** This method supports comparing arrays, array buffers, booleans,\n * date objects, error objects, maps, numbers, `Object` objects, regexes,\n * sets, strings, symbols, and typed arrays. `Object` objects are compared\n * by their own, not inherited, enumerable properties. Functions and DOM\n * nodes are compared by strict equality, i.e. `===`.\n *\n * @static\n * @memberOf _\n * @since 0.1.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 * _.isEqual(object, other);\n * // => true\n *\n * object === other;\n * // => false\n */\nfunction isEqual(value, other) {\n  return baseIsEqual(value, other);\n}\n\nexport default isEqual;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/attributeoperation\n */\n\nimport Operation from './operation';\nimport Range from '../range';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport { _setAttribute } from './utils';\nimport { isEqual } from 'lodash-es';\n\n/**\n * Operation to change nodes' attribute.\n *\n * Using this class you can add, remove or change value of the attribute.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class AttributeOperation extends Operation {\n\t/**\n\t * Creates an operation that changes, removes or adds attributes.\n\t *\n\t * If only `newValue` is set, attribute will be added on a node. Note that all nodes in operation's range must not\n\t * have an attribute with the same key as the added attribute.\n\t *\n\t * If only `oldValue` is set, then attribute with given key will be removed. Note that all nodes in operation's range\n\t * must have an attribute with that key added.\n\t *\n\t * If both `newValue` and `oldValue` are set, then the operation will change the attribute value. Note that all nodes in\n\t * operation's ranges must already have an attribute with given key and `oldValue` as value\n\t *\n\t * @param {module:engine/model/range~Range} range Range on which the operation should be applied. Must be a flat range.\n\t * @param {String} key Key of an attribute to change or remove.\n\t * @param {*} oldValue Old value of the attribute with given key or `null`, if attribute was not set before.\n\t * @param {*} newValue New value of the attribute with given key or `null`, if operation should remove attribute.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( range, key, oldValue, newValue, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Range on which operation should be applied.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/range~Range}\n\t\t */\n\t\tthis.range = range.clone();\n\n\t\t/**\n\t\t * Key of an attribute to change or remove.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.key = key;\n\n\t\t/**\n\t\t * Old value of the attribute with given key or `null`, if attribute was not set before.\n\t\t *\n\t\t * @readonly\n\t\t * @member {*}\n\t\t */\n\t\tthis.oldValue = oldValue === undefined ? null : oldValue;\n\n\t\t/**\n\t\t * New value of the attribute with given key or `null`, if operation should remove attribute.\n\t\t *\n\t\t * @readonly\n\t\t * @member {*}\n\t\t */\n\t\tthis.newValue = newValue === undefined ? null : newValue;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\tif ( this.oldValue === null ) {\n\t\t\treturn 'addAttribute';\n\t\t} else if ( this.newValue === null ) {\n\t\t\treturn 'removeAttribute';\n\t\t} else {\n\t\t\treturn 'changeAttribute';\n\t\t}\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/attributeoperation~AttributeOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new AttributeOperation( this.range, this.key, this.oldValue, this.newValue, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/attributeoperation~AttributeOperation}\n\t */\n\tgetReversed() {\n\t\treturn new AttributeOperation( this.range, this.key, this.newValue, this.oldValue, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.range = this.range.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tif ( !this.range.isFlat ) {\n\t\t\t/**\n\t\t\t * The range to change is not flat.\n\t\t\t *\n\t\t\t * @error attribute-operation-range-not-flat\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'attribute-operation-range-not-flat', this );\n\t\t}\n\n\t\tfor ( const item of this.range.getItems( { shallow: true } ) ) {\n\t\t\tif ( this.oldValue !== null && !isEqual( item.getAttribute( this.key ), this.oldValue ) ) {\n\t\t\t\t/**\n\t\t\t\t * Changed node has different attribute value than operation's old attribute value.\n\t\t\t\t *\n\t\t\t\t * @error attribute-operation-wrong-old-value\n\t\t\t\t * @param {module:engine/model/item~Item} item\n\t\t\t\t * @param {String} key\n\t\t\t\t * @param {*} value\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'attribute-operation-wrong-old-value',\n\t\t\t\t\tthis,\n\t\t\t\t\t{ item, key: this.key, value: this.oldValue }\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif ( this.oldValue === null && this.newValue !== null && item.hasAttribute( this.key ) ) {\n\t\t\t\t/**\n\t\t\t\t * The attribute with given key already exists for the given node.\n\t\t\t\t *\n\t\t\t\t * @error attribute-operation-attribute-exists\n\t\t\t\t * @param {module:engine/model/node~Node} node\n\t\t\t\t * @param {String} key\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'attribute-operation-attribute-exists',\n\t\t\t\t\tthis,\n\t\t\t\t\t{ node: item, key: this.key }\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\t// If value to set is same as old value, don't do anything.\n\t\tif ( !isEqual( this.oldValue, this.newValue ) ) {\n\t\t\t// Execution.\n\t\t\t_setAttribute( this.range, this.key, this.newValue );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'AttributeOperation';\n\t}\n\n\t/**\n\t * Creates `AttributeOperation` object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/attributeoperation~AttributeOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\treturn new AttributeOperation( Range.fromJSON( json.range, document ), json.key, json.oldValue, json.newValue, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `AttributeOperation( ${ this.baseVersion } ): ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`\"${ this.key }\": ${ JSON.stringify( this.oldValue ) }` +\n\t// @if CK_DEBUG_ENGINE //\t\t` -> ${ JSON.stringify( this.newValue ) }, ${ this.range }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/detachoperation\n */\n\nimport Operation from './operation';\nimport Range from '../range';\nimport { _remove } from './utils';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n// @if CK_DEBUG_ENGINE // const ModelRange = require( '../range' ).default;\n\n/**\n * Operation to permanently remove node from detached root.\n * Note this operation is only a local operation and won't be send to the other clients.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class DetachOperation extends Operation {\n\t/**\n\t * Creates an insert operation.\n\t *\n\t * @param {module:engine/model/position~Position} sourcePosition\n\t * Position before the first {@link module:engine/model/item~Item model item} to move.\n\t * @param {Number} howMany Offset size of moved range. Moved range will start from `sourcePosition` and end at\n\t * `sourcePosition` with offset shifted by `howMany`.\n\t */\n\tconstructor( sourcePosition, howMany ) {\n\t\tsuper( null );\n\n\t\t/**\n\t\t * Position before the first {@link module:engine/model/item~Item model item} to detach.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} #sourcePosition\n\t\t */\n\t\tthis.sourcePosition = sourcePosition.clone();\n\n\t\t/**\n\t\t * Offset size of moved range.\n\t\t *\n\t\t * @member {Number} #howMany\n\t\t */\n\t\tthis.howMany = howMany;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'detach';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.sourcePosition = this.sourcePosition.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tif ( this.sourcePosition.root.document ) {\n\t\t\t/**\n\t\t\t * Cannot detach document node.\n\t\t\t *\n\t\t\t * @error detach-operation-on-document-node\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'detach-operation-on-document-node', this );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\t_remove( Range._createFromPositionAndShift( this.sourcePosition, this.howMany ) );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'DetachOperation';\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // const range = ModelRange._createFromPositionAndShift( this.sourcePosition, this.howMany );\n\t// @if CK_DEBUG_ENGINE //\tconst nodes = Array.from( range.getItems() );\n\t// @if CK_DEBUG_ENGINE //\tconst nodeString = nodes.length > 1 ? `[ ${ nodes.length } ]` : nodes[ 0 ];\n\n\t// @if CK_DEBUG_ENGINE //\treturn `DetachOperation( ${ this.baseVersion } ): ${ nodeString } -> ${ range }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/moveoperation\n */\n\nimport Operation from './operation';\nimport Position from '../position';\nimport Range from '../range';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\nimport { _move } from './utils';\n\n// @if CK_DEBUG_ENGINE // const ModelRange = require( '../range' ).default;\n\n/**\n * Operation to move a range of {@link module:engine/model/item~Item model items}\n * to given {@link module:engine/model/position~Position target position}.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class MoveOperation extends Operation {\n\t/**\n\t * Creates a move operation.\n\t *\n\t * @param {module:engine/model/position~Position} sourcePosition\n\t * Position before the first {@link module:engine/model/item~Item model item} to move.\n\t * @param {Number} howMany Offset size of moved range. Moved range will start from `sourcePosition` and end at\n\t * `sourcePosition` with offset shifted by `howMany`.\n\t * @param {module:engine/model/position~Position} targetPosition Position at which moved nodes will be inserted.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( sourcePosition, howMany, targetPosition, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Position before the first {@link module:engine/model/item~Item model item} to move.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/moveoperation~MoveOperation#sourcePosition\n\t\t */\n\t\tthis.sourcePosition = sourcePosition.clone();\n\t\t// `'toNext'` because `sourcePosition` is a bit like a start of the moved range.\n\t\tthis.sourcePosition.stickiness = 'toNext';\n\n\t\t/**\n\t\t * Offset size of moved range.\n\t\t *\n\t\t * @member {Number} module:engine/model/operation/moveoperation~MoveOperation#howMany\n\t\t */\n\t\tthis.howMany = howMany;\n\n\t\t/**\n\t\t * Position at which moved nodes will be inserted.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/moveoperation~MoveOperation#targetPosition\n\t\t */\n\t\tthis.targetPosition = targetPosition.clone();\n\t\tthis.targetPosition.stickiness = 'toNone';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\tif ( this.targetPosition.root.rootName == '$graveyard' ) {\n\t\t\treturn 'remove';\n\t\t} else if ( this.sourcePosition.root.rootName == '$graveyard' ) {\n\t\t\treturn 'reinsert';\n\t\t}\n\n\t\treturn 'move';\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/moveoperation~MoveOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new this.constructor( this.sourcePosition, this.howMany, this.targetPosition, this.baseVersion );\n\t}\n\n\t/**\n\t * Returns the start position of the moved range after it got moved. This may be different than\n\t * {@link module:engine/model/operation/moveoperation~MoveOperation#targetPosition} in some cases, i.e. when a range is moved\n\t * inside the same parent but {@link module:engine/model/operation/moveoperation~MoveOperation#targetPosition targetPosition}\n\t * is after {@link module:engine/model/operation/moveoperation~MoveOperation#sourcePosition sourcePosition}.\n\t *\n\t *\t\t vv              vv\n\t *\t\tabcdefg ===> adefbcg\n\t *\t\t     ^          ^\n\t *\t\t     targetPos\tmovedRangeStart\n\t *\t\t     offset 6\toffset 4\n\t *\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tgetMovedRangeStart() {\n\t\treturn this.targetPosition._getTransformedByDeletion( this.sourcePosition, this.howMany );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/moveoperation~MoveOperation}\n\t */\n\tgetReversed() {\n\t\tconst newTargetPosition = this.sourcePosition._getTransformedByInsertion( this.targetPosition, this.howMany );\n\n\t\treturn new this.constructor( this.getMovedRangeStart(), this.howMany, newTargetPosition, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tconst sourceElement = this.sourcePosition.parent;\n\t\tconst targetElement = this.targetPosition.parent;\n\t\tconst sourceOffset = this.sourcePosition.offset;\n\t\tconst targetOffset = this.targetPosition.offset;\n\n\t\t// Validate whether move operation has correct parameters.\n\t\t// Validation is pretty complex but move operation is one of the core ways to manipulate the document state.\n\t\t// We expect that many errors might be connected with one of scenarios described below.\n\t\tif ( sourceOffset + this.howMany > sourceElement.maxOffset ) {\n\t\t\t/**\n\t\t\t * The nodes which should be moved do not exist.\n\t\t\t *\n\t\t\t * @error move-operation-nodes-do-not-exist\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'move-operation-nodes-do-not-exist', this\n\t\t\t);\n\t\t} else if ( sourceElement === targetElement && sourceOffset < targetOffset && targetOffset < sourceOffset + this.howMany ) {\n\t\t\t/**\n\t\t\t * Trying to move a range of nodes into the middle of that range.\n\t\t\t *\n\t\t\t * @error move-operation-range-into-itself\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'move-operation-range-into-itself', this\n\t\t\t);\n\t\t} else if ( this.sourcePosition.root == this.targetPosition.root ) {\n\t\t\tif ( compareArrays( this.sourcePosition.getParentPath(), this.targetPosition.getParentPath() ) == 'prefix' ) {\n\t\t\t\tconst i = this.sourcePosition.path.length - 1;\n\n\t\t\t\tif ( this.targetPosition.path[ i ] >= sourceOffset && this.targetPosition.path[ i ] < sourceOffset + this.howMany ) {\n\t\t\t\t\t/**\n\t\t\t\t\t * Trying to move a range of nodes into one of nodes from that range.\n\t\t\t\t\t *\n\t\t\t\t\t * @error move-operation-node-into-itself\n\t\t\t\t\t */\n\t\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t\t'move-operation-node-into-itself', this\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\t_move( Range._createFromPositionAndShift( this.sourcePosition, this.howMany ), this.targetPosition );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.sourcePosition = this.sourcePosition.toJSON();\n\t\tjson.targetPosition = this.targetPosition.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'MoveOperation';\n\t}\n\n\t/**\n\t * Creates `MoveOperation` object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/moveoperation~MoveOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\tconst sourcePosition = Position.fromJSON( json.sourcePosition, document );\n\t\tconst targetPosition = Position.fromJSON( json.targetPosition, document );\n\n\t\treturn new this( sourcePosition, json.howMany, targetPosition, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \tconst range = ModelRange._createFromPositionAndShift( this.sourcePosition, this.howMany );\n\n\t// @if CK_DEBUG_ENGINE //\treturn `MoveOperation( ${ this.baseVersion } ): ${ range } -> ${ this.targetPosition }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/insertoperation\n */\n\nimport Operation from './operation';\nimport Position from '../position';\nimport NodeList from '../nodelist';\nimport MoveOperation from './moveoperation';\nimport { _insert, _normalizeNodes } from './utils';\nimport Text from '../text';\nimport Element from '../element';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Operation to insert one or more nodes at given position in the model.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class InsertOperation extends Operation {\n\t/**\n\t * Creates an insert operation.\n\t *\n\t * @param {module:engine/model/position~Position} position Position of insertion.\n\t * @param {module:engine/model/node~NodeSet} nodes The list of nodes to be inserted.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( position, nodes, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Position of insertion.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/insertoperation~InsertOperation#position\n\t\t */\n\t\tthis.position = position.clone();\n\t\tthis.position.stickiness = 'toNone';\n\n\t\t/**\n\t\t * List of nodes to insert.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/nodelist~NodeList} module:engine/model/operation/insertoperation~InsertOperation#nodeList\n\t\t */\n\t\tthis.nodes = new NodeList( _normalizeNodes( nodes ) );\n\n\t\t/**\n\t\t * Flag deciding how the operation should be transformed. If set to `true`, nodes might get additional attributes\n\t\t * during operational transformation. This happens when the operation insertion position is inside of a range\n\t\t * where attributes have changed.\n\t\t *\n\t\t * @member {Boolean} module:engine/model/operation/insertoperation~InsertOperation#shouldReceiveAttributes\n\t\t */\n\t\tthis.shouldReceiveAttributes = false;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'insert';\n\t}\n\n\t/**\n\t * Total offset size of inserted nodes.\n\t *\n\t * @returns {Number}\n\t */\n\tget howMany() {\n\t\treturn this.nodes.maxOffset;\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/insertoperation~InsertOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\tconst nodes = new NodeList( [ ...this.nodes ].map( node => node._clone( true ) ) );\n\t\tconst insert = new InsertOperation( this.position, nodes, this.baseVersion );\n\n\t\tinsert.shouldReceiveAttributes = this.shouldReceiveAttributes;\n\n\t\treturn insert;\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/moveoperation~MoveOperation}\n\t */\n\tgetReversed() {\n\t\tconst graveyard = this.position.root.document.graveyard;\n\t\tconst gyPosition = new Position( graveyard, [ 0 ] );\n\n\t\treturn new MoveOperation( this.position, this.nodes.maxOffset, gyPosition, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tconst targetElement = this.position.parent;\n\n\t\tif ( !targetElement || targetElement.maxOffset < this.position.offset ) {\n\t\t\t/**\n\t\t\t * Insertion position is invalid.\n\t\t\t *\n\t\t\t * @error insert-operation-position-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'insert-operation-position-invalid',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\t// What happens here is that we want original nodes be passed to writer because we want original nodes\n\t\t// to be inserted to the model. But in InsertOperation, we want to keep those nodes as they were added\n\t\t// to the operation, not modified. For example, text nodes can get merged or cropped while Elements can\n\t\t// get children. It is important that InsertOperation has the copy of original nodes in intact state.\n\t\tconst originalNodes = this.nodes;\n\t\tthis.nodes = new NodeList( [ ...originalNodes ].map( node => node._clone( true ) ) );\n\n\t\t_insert( this.position, originalNodes );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.position = this.position.toJSON();\n\t\tjson.nodes = this.nodes.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'InsertOperation';\n\t}\n\n\t/**\n\t * Creates `InsertOperation` object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/insertoperation~InsertOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\tconst children = [];\n\n\t\tfor ( const child of json.nodes ) {\n\t\t\tif ( child.name ) {\n\t\t\t\t// If child has name property, it is an Element.\n\t\t\t\tchildren.push( Element.fromJSON( child ) );\n\t\t\t} else {\n\t\t\t\t// Otherwise, it is a Text node.\n\t\t\t\tchildren.push( Text.fromJSON( child ) );\n\t\t\t}\n\t\t}\n\n\t\tconst insert = new InsertOperation( Position.fromJSON( json.position, document ), children, json.baseVersion );\n\t\tinsert.shouldReceiveAttributes = json.shouldReceiveAttributes;\n\n\t\treturn insert;\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \tconst nodeString = this.nodes.length > 1 ? `[ ${ this.nodes.length } ]` : this.nodes.getNode( 0 );\n\n\t// @if CK_DEBUG_ENGINE //\treturn `InsertOperation( ${ this.baseVersion } ): ${ nodeString } -> ${ this.position }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/markeroperation\n */\n\nimport Operation from './operation';\nimport Range from '../range';\n\n/**\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class MarkerOperation extends Operation {\n\t/**\n\t * @param {String} name Marker name.\n\t * @param {module:engine/model/range~Range} oldRange Marker range before the change.\n\t * @param {module:engine/model/range~Range} newRange Marker range after the change.\n\t * @param {module:engine/model/markercollection~MarkerCollection} markers Marker collection on which change should be executed.\n\t * @param {Boolean} affectsData Specifies whether the marker operation affects the data produced by the data pipeline\n\t * (is persisted in the editor's data).\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( name, oldRange, newRange, markers, affectsData, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Marker name.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.name = name;\n\n\t\t/**\n\t\t * Marker range before the change.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/range~Range}\n\t\t */\n\t\tthis.oldRange = oldRange ? oldRange.clone() : null;\n\n\t\t/**\n\t\t * Marker range after the change.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/range~Range}\n\t\t */\n\t\tthis.newRange = newRange ? newRange.clone() : null;\n\n\t\t/**\n\t\t * Specifies whether the marker operation affects the data produced by the data pipeline\n\t\t * (is persisted in the editor's data).\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis.affectsData = affectsData;\n\n\t\t/**\n\t\t * Marker collection on which change should be executed.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/markercollection~MarkerCollection}\n\t\t */\n\t\tthis._markers = markers;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'marker';\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/markeroperation~MarkerOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new MarkerOperation( this.name, this.oldRange, this.newRange, this._markers, this.affectsData, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/markeroperation~MarkerOperation}\n\t */\n\tgetReversed() {\n\t\treturn new MarkerOperation( this.name, this.newRange, this.oldRange, this._markers, this.affectsData, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\tconst type = this.newRange ? '_set' : '_remove';\n\n\t\tthis._markers[ type ]( this.name, this.newRange, true, this.affectsData );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tif ( this.oldRange ) {\n\t\t\tjson.oldRange = this.oldRange.toJSON();\n\t\t}\n\n\t\tif ( this.newRange ) {\n\t\t\tjson.newRange = this.newRange.toJSON();\n\t\t}\n\n\t\tdelete json._markers;\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'MarkerOperation';\n\t}\n\n\t/**\n\t * Creates `MarkerOperation` object from deserialized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/markeroperation~MarkerOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\treturn new MarkerOperation(\n\t\t\tjson.name,\n\t\t\tjson.oldRange ? Range.fromJSON( json.oldRange, document ) : null,\n\t\t\tjson.newRange ? Range.fromJSON( json.newRange, document ) : null,\n\t\t\tdocument.model.markers,\n\t\t\tjson.affectsData,\n\t\t\tjson.baseVersion\n\t\t);\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `MarkerOperation( ${ this.baseVersion } ): ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`\"${ this.name }\": ${ this.oldRange } -> ${ this.newRange }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/renameoperation\n */\n\nimport Operation from './operation';\nimport Element from '../element';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport Position from '../position';\n\n/**\n * Operation to change element's name.\n *\n * Using this class you can change element's name.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class RenameOperation extends Operation {\n\t/**\n\t * Creates an operation that changes element's name.\n\t *\n\t * @param {module:engine/model/position~Position} position Position before an element to change.\n\t * @param {String} oldName Current name of the element.\n\t * @param {String} newName New name for the element.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( position, oldName, newName, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Position before an element to change.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/renameoperation~RenameOperation#position\n\t\t */\n\t\tthis.position = position;\n\t\t// This position sticks to the next node because it is a position before the node that we want to change.\n\t\tthis.position.stickiness = 'toNext';\n\n\t\t/**\n\t\t * Current name of the element.\n\t\t *\n\t\t * @member {String} module:engine/model/operation/renameoperation~RenameOperation#oldName\n\t\t */\n\t\tthis.oldName = oldName;\n\n\t\t/**\n\t\t * New name for the element.\n\t\t *\n\t\t * @member {String} module:engine/model/operation/renameoperation~RenameOperation#newName\n\t\t */\n\t\tthis.newName = newName;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'rename';\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/renameoperation~RenameOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new RenameOperation( this.position.clone(), this.oldName, this.newName, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/renameoperation~RenameOperation}\n\t */\n\tgetReversed() {\n\t\treturn new RenameOperation( this.position.clone(), this.newName, this.oldName, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tconst element = this.position.nodeAfter;\n\n\t\tif ( !( element instanceof Element ) ) {\n\t\t\t/**\n\t\t\t * Given position is invalid or node after it is not instance of Element.\n\t\t\t *\n\t\t\t * @error rename-operation-wrong-position\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rename-operation-wrong-position',\n\t\t\t\tthis\n\t\t\t);\n\t\t} else if ( element.name !== this.oldName ) {\n\t\t\t/**\n\t\t\t * Element to change has different name than operation's old name.\n\t\t\t *\n\t\t\t * @error rename-operation-wrong-name\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rename-operation-wrong-name',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\tconst element = this.position.nodeAfter;\n\n\t\telement.name = this.newName;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.position = this.position.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'RenameOperation';\n\t}\n\n\t/**\n\t * Creates `RenameOperation` object from deserialized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/attributeoperation~AttributeOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\treturn new RenameOperation( Position.fromJSON( json.position, document ), json.oldName, json.newName, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `RenameOperation( ${ this.baseVersion } ): ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`${ this.position }: \"${ this.oldName }\" -> \"${ this.newName }\"`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/rootattributeoperation\n */\n\nimport Operation from './operation';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Operation to change root element's attribute. Using this class you can add, remove or change value of the attribute.\n *\n * This operation is needed, because root elements can't be changed through\n * @link module:engine/model/operation/attributeoperation~AttributeOperation}.\n * It is because {@link module:engine/model/operation/attributeoperation~AttributeOperation}\n * requires a range to change and root element can't\n * be a part of range because every {@link module:engine/model/position~Position} has to be inside a root.\n * {@link module:engine/model/position~Position} can't be created before a root element.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class RootAttributeOperation extends Operation {\n\t/**\n\t * Creates an operation that changes, removes or adds attributes on root element.\n\t *\n\t * @see module:engine/model/operation/attributeoperation~AttributeOperation\n\t * @param {module:engine/model/rootelement~RootElement} root Root element to change.\n\t * @param {String} key Key of an attribute to change or remove.\n\t * @param {*} oldValue Old value of the attribute with given key or `null` if adding a new attribute.\n\t * @param {*} newValue New value to set for the attribute. If `null`, then the operation just removes the attribute.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( root, key, oldValue, newValue, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Root element to change.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/rootelement~RootElement}\n\t\t */\n\t\tthis.root = root;\n\n\t\t/**\n\t\t * Key of an attribute to change or remove.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.key = key;\n\n\t\t/**\n\t\t * Old value of the attribute with given key or `null` if adding a new attribute.\n\t\t *\n\t\t * @readonly\n\t\t * @member {*}\n\t\t */\n\t\tthis.oldValue = oldValue;\n\n\t\t/**\n\t\t * New value to set for the attribute. If `null`, then the operation just removes the attribute.\n\t\t *\n\t\t * @readonly\n\t\t * @member {*}\n\t\t */\n\t\tthis.newValue = newValue;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\tif ( this.oldValue === null ) {\n\t\t\treturn 'addRootAttribute';\n\t\t} else if ( this.newValue === null ) {\n\t\t\treturn 'removeRootAttribute';\n\t\t} else {\n\t\t\treturn 'changeRootAttribute';\n\t\t}\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/rootattributeoperation~RootAttributeOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new RootAttributeOperation( this.root, this.key, this.oldValue, this.newValue, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/rootattributeoperation~RootAttributeOperation}\n\t */\n\tgetReversed() {\n\t\treturn new RootAttributeOperation( this.root, this.key, this.newValue, this.oldValue, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tif ( this.root != this.root.root || this.root.is( 'documentFragment' ) ) {\n\t\t\t/**\n\t\t\t * The element to change is not a root element.\n\t\t\t *\n\t\t\t * @error rootattribute-operation-not-a-root\n\t\t\t * @param {module:engine/model/rootelement~RootElement} root\n\t\t\t * @param {String} key\n\t\t\t * @param {*} value\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rootattribute-operation-not-a-root',\n\t\t\t\tthis,\n\t\t\t\t{ root: this.root, key: this.key }\n\t\t\t);\n\t\t}\n\n\t\tif ( this.oldValue !== null && this.root.getAttribute( this.key ) !== this.oldValue ) {\n\t\t\t/**\n\t\t\t * The attribute which should be removed does not exists for the given node.\n\t\t\t *\n\t\t\t * @error rootattribute-operation-wrong-old-value\n\t\t\t * @param {module:engine/model/rootelement~RootElement} root\n\t\t\t * @param {String} key\n\t\t\t * @param {*} value\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rootattribute-operation-wrong-old-value',\n\t\t\t\tthis,\n\t\t\t\t{ root: this.root, key: this.key }\n\t\t\t);\n\t\t}\n\n\t\tif ( this.oldValue === null && this.newValue !== null && this.root.hasAttribute( this.key ) ) {\n\t\t\t/**\n\t\t\t * The attribute with given key already exists for the given node.\n\t\t\t *\n\t\t\t * @error rootattribute-operation-attribute-exists\n\t\t\t * @param {module:engine/model/rootelement~RootElement} root\n\t\t\t * @param {String} key\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rootattribute-operation-attribute-exists',\n\t\t\t\tthis,\n\t\t\t\t{ root: this.root, key: this.key }\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\tif ( this.newValue !== null ) {\n\t\t\tthis.root._setAttribute( this.key, this.newValue );\n\t\t} else {\n\t\t\tthis.root._removeAttribute( this.key );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.root = this.root.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'RootAttributeOperation';\n\t}\n\n\t/**\n\t * Creates RootAttributeOperation object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/rootattributeoperation~RootAttributeOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\tif ( !document.getRoot( json.root ) ) {\n\t\t\t/**\n\t\t\t * Cannot create RootAttributeOperation for document. Root with specified name does not exist.\n\t\t\t *\n\t\t\t * @error rootattribute-operation-fromjson-no-root\n\t\t\t * @param {String} rootName\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'rootattribute-operation-fromjson-no-root', this, { rootName: json.root } );\n\t\t}\n\n\t\treturn new RootAttributeOperation( document.getRoot( json.root ), json.key, json.oldValue, json.newValue, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `RootAttributeOperation( ${ this.baseVersion } ): ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`\"${ this.key }\": ${ JSON.stringify( this.oldValue ) }` +\n\t// @if CK_DEBUG_ENGINE //\t\t` -> ${ JSON.stringify( this.newValue ) }, ${ this.root.rootName }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/mergeoperation\n */\n\nimport Operation from './operation';\nimport SplitOperation from './splitoperation';\nimport Position from '../position';\nimport Range from '../range';\nimport { _move } from './utils';\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Operation to merge two {@link module:engine/model/element~Element elements}.\n *\n * The merged element is the parent of {@link ~MergeOperation#sourcePosition} and it is merged into the parent of\n * {@link ~MergeOperation#targetPosition}. All nodes from the merged element are moved to {@link ~MergeOperation#targetPosition}.\n *\n * The merged element is moved to the graveyard at {@link ~MergeOperation#graveyardPosition}.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class MergeOperation extends Operation {\n\t/**\n\t * Creates a merge operation.\n\t *\n\t * @param {module:engine/model/position~Position} sourcePosition Position inside the merged element. All nodes from that\n\t * element after that position will be moved to {@link ~#targetPosition}.\n\t * @param {Number} howMany Summary offset size of nodes which will be moved from the merged element to the new parent.\n\t * @param {module:engine/model/position~Position} targetPosition Position which the nodes from the merged elements will be moved to.\n\t * @param {module:engine/model/position~Position} graveyardPosition Position in graveyard to which the merged element will be moved.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( sourcePosition, howMany, targetPosition, graveyardPosition, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Position inside the merged element. All nodes from that element after that position will be moved to {@link ~#targetPosition}.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/mergeoperation~MergeOperation#sourcePosition\n\t\t */\n\t\tthis.sourcePosition = sourcePosition.clone();\n\t\t// This is, and should always remain, the first position in its parent.\n\t\tthis.sourcePosition.stickiness = 'toPrevious';\n\n\t\t/**\n\t\t * Summary offset size of nodes which will be moved from the merged element to the new parent.\n\t\t *\n\t\t * @member {Number} module:engine/model/operation/mergeoperation~MergeOperation#howMany\n\t\t */\n\t\tthis.howMany = howMany;\n\n\t\t/**\n\t\t * Position which the nodes from the merged elements will be moved to.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/mergeoperation~MergeOperation#targetPosition\n\t\t */\n\t\tthis.targetPosition = targetPosition.clone();\n\t\t// Except of a rare scenario in `MergeOperation` x `MergeOperation` transformation,\n\t\t// this is, and should always remain, the last position in its parent.\n\t\tthis.targetPosition.stickiness = 'toNext';\n\n\t\t/**\n\t\t * Position in graveyard to which the merged element will be moved.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/mergeoperation~MergeOperation#graveyardPosition\n\t\t */\n\t\tthis.graveyardPosition = graveyardPosition.clone();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'merge';\n\t}\n\n\t/**\n\t * Position before the merged element (which will be deleted).\n\t *\n\t * @readonly\n\t * @type {module:engine/model/position~Position}\n\t */\n\tget deletionPosition() {\n\t\treturn new Position( this.sourcePosition.root, this.sourcePosition.path.slice( 0, -1 ) );\n\t}\n\n\t/**\n\t * Artificial range that contains all the nodes from the merged element that will be moved to {@link ~MergeOperation#sourcePosition}.\n\t * The range starts at {@link ~MergeOperation#sourcePosition} and ends in the same parent, at `POSITIVE_INFINITY` offset.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/range~Range}\n\t */\n\tget movedRange() {\n\t\tconst end = this.sourcePosition.getShiftedBy( Number.POSITIVE_INFINITY );\n\n\t\treturn new Range( this.sourcePosition, end );\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/mergeoperation~MergeOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new this.constructor( this.sourcePosition, this.howMany, this.targetPosition, this.graveyardPosition, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/splitoperation~SplitOperation}\n\t */\n\tgetReversed() {\n\t\t// Positions in this method are transformed by this merge operation because the split operation bases on\n\t\t// the context after this merge operation happened (because split operation reverses it).\n\t\t// So we need to acknowledge that the merge operation happened and those positions changed a little.\n\t\tconst targetPosition = this.targetPosition._getTransformedByMergeOperation( this );\n\n\t\tconst path = this.sourcePosition.path.slice( 0, -1 );\n\t\tconst insertionPosition = new Position( this.sourcePosition.root, path )._getTransformedByMergeOperation( this );\n\n\t\tconst split = new SplitOperation( targetPosition, this.howMany, this.graveyardPosition, this.baseVersion + 1 );\n\t\tsplit.insertionPosition = insertionPosition;\n\n\t\treturn split;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tconst sourceElement = this.sourcePosition.parent;\n\t\tconst targetElement = this.targetPosition.parent;\n\n\t\t// Validate whether merge operation has correct parameters.\n\t\tif ( !sourceElement.parent ) {\n\t\t\t/**\n\t\t\t * Merge source position is invalid. The element to be merged must have a parent node.\n\t\t\t *\n\t\t\t * @error merge-operation-source-position-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'merge-operation-source-position-invalid', this );\n\t\t} else if ( !targetElement.parent ) {\n\t\t\t/**\n\t\t\t * Merge target position is invalid. The element to be merged must have a parent node.\n\t\t\t *\n\t\t\t * @error merge-operation-target-position-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'merge-operation-target-position-invalid', this );\n\t\t} else if ( this.howMany != sourceElement.maxOffset ) {\n\t\t\t/**\n\t\t\t * Merge operation specifies wrong number of nodes to move.\n\t\t\t *\n\t\t\t * @error merge-operation-how-many-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'merge-operation-how-many-invalid', this );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\tconst mergedElement = this.sourcePosition.parent;\n\t\tconst sourceRange = Range._createIn( mergedElement );\n\n\t\t_move( sourceRange, this.targetPosition );\n\t\t_move( Range._createOn( mergedElement ), this.graveyardPosition );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.sourcePosition = json.sourcePosition.toJSON();\n\t\tjson.targetPosition = json.targetPosition.toJSON();\n\t\tjson.graveyardPosition = json.graveyardPosition.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'MergeOperation';\n\t}\n\n\t/**\n\t * Creates `MergeOperation` object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/mergeoperation~MergeOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\tconst sourcePosition = Position.fromJSON( json.sourcePosition, document );\n\t\tconst targetPosition = Position.fromJSON( json.targetPosition, document );\n\t\tconst graveyardPosition = Position.fromJSON( json.graveyardPosition, document );\n\n\t\treturn new this( sourcePosition, json.howMany, targetPosition, graveyardPosition, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `MergeOperation( ${ this.baseVersion } ): ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`${ this.sourcePosition } -> ${ this.targetPosition }` +\n\t// @if CK_DEBUG_ENGINE //\t\t` ( ${ this.howMany } ), ${ this.graveyardPosition }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/splitoperation\n */\n\nimport Operation from './operation';\nimport MergeOperation from './mergeoperation';\nimport Position from '../position';\nimport Range from '../range';\nimport { _insert, _move } from './utils';\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Operation to split {@link module:engine/model/element~Element an element} at given\n * {@link module:engine/model/operation/splitoperation~SplitOperation#splitPosition split position} into two elements,\n * both containing a part of the element's original content.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class SplitOperation extends Operation {\n\t/**\n\t * Creates a split operation.\n\t *\n\t * @param {module:engine/model/position~Position} splitPosition Position at which an element should be split.\n\t * @param {Number} howMany Total offset size of elements that are in the split element after `position`.\n\t * @param {module:engine/model/position~Position|null} graveyardPosition Position in the graveyard root before the element which\n\t * should be used as a parent of the nodes after `position`. If it is not set, a copy of the the `position` parent will be used.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( splitPosition, howMany, graveyardPosition, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Position at which an element should be split.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/splitoperation~SplitOperation#splitPosition\n\t\t */\n\t\tthis.splitPosition = splitPosition.clone();\n\t\t// Keep position sticking to the next node. This way any new content added at the place where the element is split\n\t\t// will be left in the original element.\n\t\tthis.splitPosition.stickiness = 'toNext';\n\n\t\t/**\n\t\t * Total offset size of elements that are in the split element after `position`.\n\t\t *\n\t\t * @member {Number} module:engine/model/operation/splitoperation~SplitOperation#howMany\n\t\t */\n\t\tthis.howMany = howMany;\n\n\t\t/**\n\t\t * Position at which the clone of split element (or element from graveyard) will be inserted.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/splitoperation~SplitOperation#insertionPosition\n\t\t */\n\t\tthis.insertionPosition = SplitOperation.getInsertionPosition( splitPosition );\n\t\tthis.insertionPosition.stickiness = 'toNone';\n\n\t\t/**\n\t\t * Position in the graveyard root before the element which should be used as a parent of the nodes after `position`.\n\t\t * If it is not set, a copy of the the `position` parent will be used.\n\t\t *\n\t\t * The default behavior is to clone the split element. Element from graveyard is used during undo.\n\t\t *\n\t\t * @member {module:engine/model/position~Position|null} #graveyardPosition\n\t\t */\n\t\tthis.graveyardPosition = graveyardPosition ? graveyardPosition.clone() : null;\n\n\t\tif ( this.graveyardPosition ) {\n\t\t\tthis.graveyardPosition.stickiness = 'toNext';\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'split';\n\t}\n\n\t/**\n\t * Position inside the new clone of a split element.\n\t *\n\t * This is a position where nodes that are after the split position will be moved to.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/position~Position}\n\t */\n\tget moveTargetPosition() {\n\t\tconst path = this.insertionPosition.path.slice();\n\t\tpath.push( 0 );\n\n\t\treturn new Position( this.insertionPosition.root, path );\n\t}\n\n\t/**\n\t * Artificial range that contains all the nodes from the split element that will be moved to the new element.\n\t * The range starts at {@link ~#splitPosition} and ends in the same parent, at `POSITIVE_INFINITY` offset.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/range~Range}\n\t */\n\tget movedRange() {\n\t\tconst end = this.splitPosition.getShiftedBy( Number.POSITIVE_INFINITY );\n\n\t\treturn new Range( this.splitPosition, end );\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/splitoperation~SplitOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\tconst split = new this.constructor( this.splitPosition, this.howMany, this.graveyardPosition, this.baseVersion );\n\t\tsplit.insertionPosition = this.insertionPosition;\n\n\t\treturn split;\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/mergeoperation~MergeOperation}\n\t */\n\tgetReversed() {\n\t\tconst graveyard = this.splitPosition.root.document.graveyard;\n\t\tconst graveyardPosition = new Position( graveyard, [ 0 ] );\n\n\t\treturn new MergeOperation( this.moveTargetPosition, this.howMany, this.splitPosition, graveyardPosition, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tconst element = this.splitPosition.parent;\n\t\tconst offset = this.splitPosition.offset;\n\n\t\t// Validate whether split operation has correct parameters.\n\t\tif ( !element || element.maxOffset < offset ) {\n\t\t\t/**\n\t\t\t * Split position is invalid.\n\t\t\t *\n\t\t\t * @error split-operation-position-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'split-operation-position-invalid', this );\n\t\t} else if ( !element.parent ) {\n\t\t\t/**\n\t\t\t * Cannot split root element.\n\t\t\t *\n\t\t\t * @error split-operation-split-in-root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'split-operation-split-in-root', this );\n\t\t} else if ( this.howMany != element.maxOffset - this.splitPosition.offset ) {\n\t\t\t/**\n\t\t\t * Split operation specifies wrong number of nodes to move.\n\t\t\t *\n\t\t\t * @error split-operation-how-many-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'split-operation-how-many-invalid', this );\n\t\t} else if ( this.graveyardPosition && !this.graveyardPosition.nodeAfter ) {\n\t\t\t/**\n\t\t\t * Graveyard position invalid.\n\t\t\t *\n\t\t\t * @error split-operation-graveyard-position-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'split-operation-graveyard-position-invalid', this );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\tconst splitElement = this.splitPosition.parent;\n\n\t\tif ( this.graveyardPosition ) {\n\t\t\t_move( Range._createFromPositionAndShift( this.graveyardPosition, 1 ), this.insertionPosition );\n\t\t} else {\n\t\t\tconst newElement = splitElement._clone();\n\n\t\t\t_insert( this.insertionPosition, newElement );\n\t\t}\n\n\t\tconst sourceRange = new Range(\n\t\t\tPosition._createAt( splitElement, this.splitPosition.offset ),\n\t\t\tPosition._createAt( splitElement, splitElement.maxOffset )\n\t\t);\n\n\t\t_move( sourceRange, this.moveTargetPosition );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.splitPosition = this.splitPosition.toJSON();\n\t\tjson.insertionPosition = this.insertionPosition.toJSON();\n\n\t\tif ( this.graveyardPosition ) {\n\t\t\tjson.graveyardPosition = this.graveyardPosition.toJSON();\n\t\t}\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'SplitOperation';\n\t}\n\n\t/**\n\t * Helper function that returns a default insertion position basing on given `splitPosition`. The default insertion\n\t * position is after the split element.\n\t *\n\t * @param {module:engine/model/position~Position} splitPosition\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tstatic getInsertionPosition( splitPosition ) {\n\t\tconst path = splitPosition.path.slice( 0, -1 );\n\t\tpath[ path.length - 1 ]++;\n\n\t\treturn new Position( splitPosition.root, path );\n\t}\n\n\t/**\n\t * Creates `SplitOperation` object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/splitoperation~SplitOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\tconst splitPosition = Position.fromJSON( json.splitPosition, document );\n\t\tconst insertionPosition = Position.fromJSON( json.insertionPosition, document );\n\t\tconst graveyardPosition = json.graveyardPosition ? Position.fromJSON( json.graveyardPosition, document ) : null;\n\n\t\tconst split = new this( splitPosition, json.howMany, graveyardPosition, json.baseVersion );\n\t\tsplit.insertionPosition = insertionPosition;\n\n\t\treturn split;\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `SplitOperation( ${ this.baseVersion } ): ${ this.splitPosition } ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`( ${ this.howMany } ) -> ${ this.insertionPosition }` +\n\t// @if CK_DEBUG_ENGINE //\t\t`${ this.graveyardPosition ? ' with ' + this.graveyardPosition : '' }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/rootelement\n */\n\nimport Element from './element';\n\n/**\n * Type of {@link module:engine/model/element~Element} that is a root of a model tree.\n * @extends module:engine/model/element~Element\n */\nexport default class RootElement extends Element {\n\t/**\n\t * Creates root element.\n\t *\n\t * @param {module:engine/model/document~Document} document Document that is an owner of this root.\n\t * @param {String} name Node name.\n\t * @param {String} [rootName='main'] Unique root name used to identify this root\n\t * element by {@link module:engine/model/document~Document}.\n\t */\n\tconstructor( document, name, rootName = 'main' ) {\n\t\tsuper( name );\n\n\t\t/**\n\t\t * Document that is an owner of this root.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/document~Document}\n\t\t */\n\t\tthis._document = document;\n\n\t\t/**\n\t\t * Unique root name used to identify this root element by {@link module:engine/model/document~Document}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.rootName = rootName;\n\t}\n\n\t/**\n\t * {@link module:engine/model/document~Document Document} that owns this root element.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/document~Document|null}\n\t */\n\tget document() {\n\t\treturn this._document;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\trootElement.is( 'rootElement' ); // -> true\n\t *\t\trootElement.is( 'element' ); // -> true\n\t *\t\trootElement.is( 'node' ); // -> true\n\t *\t\trootElement.is( 'model:rootElement' ); // -> true\n\t *\t\trootElement.is( 'model:element' ); // -> true\n\t *\t\trootElement.is( 'model:node' ); // -> true\n\t *\n\t *\t\trootElement.is( 'view:element' ); // -> false\n\t *\t\trootElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is an element, you can also check its\n\t * {@link module:engine/model/element~Element#name name}:\n\t *\n\t *\t\trootElement.is( 'rootElement', '$root' ); // -> same as above\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'rootElement' || type === 'model:rootElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'element' || type === 'model:element' ||\n\t\t\t\ttype === 'node' || type === 'model:node';\n\t\t}\n\n\t\treturn name === this.name && (\n\t\t\ttype === 'rootElement' || type === 'model:rootElement' ||\n\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\ttype === 'element' || type === 'model:element'\n\t\t);\n\t}\n\n\t/**\n\t * Converts `RootElement` instance to `String` containing it's name.\n\t *\n\t * @returns {String} `RootElement` instance converted to `String`.\n\t */\n\ttoJSON() {\n\t\treturn this.rootName;\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn this.rootName;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelRootElement: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/writer\n */\n\nimport AttributeOperation from './operation/attributeoperation';\nimport DetachOperation from './operation/detachoperation';\nimport InsertOperation from './operation/insertoperation';\nimport MarkerOperation from './operation/markeroperation';\nimport MoveOperation from './operation/moveoperation';\nimport RenameOperation from './operation/renameoperation';\nimport RootAttributeOperation from './operation/rootattributeoperation';\nimport SplitOperation from './operation/splitoperation';\nimport MergeOperation from './operation/mergeoperation';\n\nimport DocumentFragment from './documentfragment';\nimport Text from './text';\nimport Element from './element';\nimport RootElement from './rootelement';\nimport Position from './position';\nimport Range from './range.js';\nimport DocumentSelection from './documentselection';\n\nimport toMap from '@ckeditor/ckeditor5-utils/src/tomap';\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * The model can only be modified by using the writer. It should be used whenever you want to create a node, modify\n * child nodes, attributes or text, set the selection's position and its attributes.\n *\n * The instance of the writer is only available in the {@link module:engine/model/model~Model#change `change()`} or\n * {@link module:engine/model/model~Model#enqueueChange `enqueueChange()`}.\n *\n *\t\tmodel.change( writer => {\n *\t\t\twriter.insertText( 'foo', paragraph, 'end' );\n *\t\t} );\n *\n * Note that the writer should never be stored and used outside of the `change()` and\n * `enqueueChange()` blocks.\n *\n * Note that writer's methods do not check the {@link module:engine/model/schema~Schema}. It is possible\n * to create incorrect model structures by using the writer. Read more about in\n * {@glink framework/guides/deep-dive/schema#who-checks-the-schema \"Who checks the schema?\"}.\n *\n * @see module:engine/model/model~Model#change\n * @see module:engine/model/model~Model#enqueueChange\n */\nexport default class Writer {\n\t/**\n\t * Creates a writer instance.\n\t *\n\t * **Note:** It is not recommended to use it directly. Use {@link module:engine/model/model~Model#change `Model#change()`} or\n\t * {@link module:engine/model/model~Model#enqueueChange `Model#enqueueChange()`} instead.\n\t *\n\t * @protected\n\t * @param {module:engine/model/model~Model} model\n\t * @param {module:engine/model/batch~Batch} batch\n\t */\n\tconstructor( model, batch ) {\n\t\t/**\n\t\t * Instance of the model on which this writer operates.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/model/model~Model}\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * The batch to which this writer will add changes.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/model/batch~Batch}\n\t\t */\n\t\tthis.batch = batch;\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/model/text~Text text node}.\n\t *\n\t *\t\twriter.createText( 'foo' );\n\t *\t\twriter.createText( 'foo', { bold: true } );\n\t *\n\t * @param {String} data Text data.\n\t * @param {Object} [attributes] Text attributes.\n\t * @returns {module:engine/model/text~Text} Created text node.\n\t */\n\tcreateText( data, attributes ) {\n\t\treturn new Text( data, attributes );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/model/element~Element element}.\n\t *\n\t *\t\twriter.createElement( 'paragraph' );\n\t *\t\twriter.createElement( 'paragraph', { alignment: 'center' } );\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @returns {module:engine/model/element~Element} Created element.\n\t */\n\tcreateElement( name, attributes ) {\n\t\treturn new Element( name, attributes );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/model/documentfragment~DocumentFragment document fragment}.\n\t *\n\t * @returns {module:engine/model/documentfragment~DocumentFragment} Created document fragment.\n\t */\n\tcreateDocumentFragment() {\n\t\treturn new DocumentFragment();\n\t}\n\n\t/**\n\t * Creates a copy of the element and returns it. Created element has the same name and attributes as the original element.\n\t * If clone is deep, the original element's children are also cloned. If not, then empty element is returned.\n\t *\n\t * @param {module:engine/model/element~Element} element The element to clone.\n\t * @param {Boolean} [deep=true] If set to `true` clones element and all its children recursively. When set to `false`,\n\t * element will be cloned without any child.\n\t */\n\tcloneElement( element, deep = true ) {\n\t\treturn element._clone( deep );\n\t}\n\n\t/**\n\t * Inserts item on given position.\n\t *\n\t *\t\tconst paragraph = writer.createElement( 'paragraph' );\n\t *\t\twriter.insert( paragraph, position );\n\t *\n\t * Instead of using position you can use parent and offset:\n\t *\n\t *\t\tconst text = writer.createText( 'foo' );\n\t *\t\twriter.insert( text, paragraph, 5 );\n\t *\n\t * You can also use `end` instead of the offset to insert at the end:\n\t *\n\t *\t\tconst text = writer.createText( 'foo' );\n\t *\t\twriter.insert( text, paragraph, 'end' );\n\t *\n\t * Or insert before or after another element:\n\t *\n\t *\t\tconst paragraph = writer.createElement( 'paragraph' );\n\t *\t\twriter.insert( paragraph, anotherParagraph, 'after' );\n\t *\n\t * These parameters works the same way as {@link #createPositionAt `writer.createPositionAt()`}.\n\t *\n\t * Note that if the item already has parent it will be removed from the previous parent.\n\t *\n\t * Note that you cannot re-insert a node from a document to a different document or a document fragment. In this case,\n\t * `model-writer-insert-forbidden-move` is thrown.\n\t *\n\t * If you want to move {@link module:engine/model/range~Range range} instead of an\n\t * {@link module:engine/model/item~Item item} use {@link module:engine/model/writer~Writer#move `Writer#move()`}.\n\t *\n\t * **Note:** For a paste-like content insertion mechanism see\n\t * {@link module:engine/model/model~Model#insertContent `model.insertContent()`}.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/documentfragment~DocumentFragment} item Item or document\n\t * fragment to insert.\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * second parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\tinsert( item, itemOrPosition, offset = 0 ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( item instanceof Text && item.data == '' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst position = Position._createAt( itemOrPosition, offset );\n\n\t\t// If item has a parent already.\n\t\tif ( item.parent ) {\n\t\t\t// We need to check if item is going to be inserted within the same document.\n\t\t\tif ( isSameTree( item.root, position.root ) ) {\n\t\t\t\t// If it's we just need to move it.\n\t\t\t\tthis.move( Range._createOn( item ), position );\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// If it isn't the same root.\n\t\t\telse {\n\t\t\t\tif ( item.root.document ) {\n\t\t\t\t\t/**\n\t\t\t\t\t * Cannot move a node from a document to a different tree.\n\t\t\t\t\t * It is forbidden to move a node that was already in a document outside of it.\n\t\t\t\t\t *\n\t\t\t\t\t * @error model-writer-insert-forbidden-move\n\t\t\t\t\t */\n\t\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t\t'model-writer-insert-forbidden-move',\n\t\t\t\t\t\tthis\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\t// Move between two different document fragments or from document fragment to a document is possible.\n\t\t\t\t\t// In that case, remove the item from it's original parent.\n\t\t\t\t\tthis.remove( item );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst version = position.root.document ? position.root.document.version : null;\n\n\t\tconst insert = new InsertOperation( position, item, version );\n\n\t\tif ( item instanceof Text ) {\n\t\t\tinsert.shouldReceiveAttributes = true;\n\t\t}\n\n\t\tthis.batch.addOperation( insert );\n\t\tthis.model.applyOperation( insert );\n\n\t\t// When element is a DocumentFragment we need to move its markers to Document#markers.\n\t\tif ( item instanceof DocumentFragment ) {\n\t\t\tfor ( const [ markerName, markerRange ] of item.markers ) {\n\t\t\t\t// We need to migrate marker range from DocumentFragment to Document.\n\t\t\t\tconst rangeRootPosition = Position._createAt( markerRange.root, 0 );\n\t\t\t\tconst range = new Range(\n\t\t\t\t\tmarkerRange.start._getCombined( rangeRootPosition, position ),\n\t\t\t\t\tmarkerRange.end._getCombined( rangeRootPosition, position )\n\t\t\t\t);\n\n\t\t\t\tconst options = { range, usingOperation: true, affectsData: true };\n\n\t\t\t\tif ( this.model.markers.has( markerName ) ) {\n\t\t\t\t\tthis.updateMarker( markerName, options );\n\t\t\t\t} else {\n\t\t\t\t\tthis.addMarker( markerName, options );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates and inserts text on given position. You can optionally set text attributes:\n\t *\n\t *\t\twriter.insertText( 'foo', position );\n\t *\t\twriter.insertText( 'foo', { bold: true }, position );\n\t *\n\t * Instead of using position you can use parent and offset or define that text should be inserted at the end\n\t * or before or after other node:\n\t *\n\t *\t\t// Inserts 'foo' in paragraph, at offset 5:\n\t *\t\twriter.insertText( 'foo', paragraph, 5 );\n\t *\t\t// Inserts 'foo' at the end of a paragraph:\n\t *\t\twriter.insertText( 'foo', paragraph, 'end' );\n\t *\t\t// Inserts 'foo' after an image:\n\t *\t\twriter.insertText( 'foo', image, 'after' );\n\t *\n\t * These parameters work in the same way as {@link #createPositionAt `writer.createPositionAt()`}.\n\t *\n\t * @param {String} data Text data.\n\t * @param {Object} [attributes] Text attributes.\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * third parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\tinsertText( text, attributes, itemOrPosition, offset ) {\n\t\tif ( attributes instanceof DocumentFragment || attributes instanceof Element || attributes instanceof Position ) {\n\t\t\tthis.insert( this.createText( text ), attributes, itemOrPosition );\n\t\t} else {\n\t\t\tthis.insert( this.createText( text, attributes ), itemOrPosition, offset );\n\t\t}\n\t}\n\n\t/**\n\t * Creates and inserts element on given position. You can optionally set attributes:\n\t *\n\t *\t\twriter.insertElement( 'paragraph', position );\n\t *\t\twriter.insertElement( 'paragraph', { alignment: 'center' }, position );\n\t *\n\t * Instead of using position you can use parent and offset or define that text should be inserted at the end\n\t * or before or after other node:\n\t *\n\t *\t\t// Inserts paragraph in the root at offset 5:\n\t *\t\twriter.insertElement( 'paragraph', root, 5 );\n\t *\t\t// Inserts paragraph at the end of a blockquote:\n\t *\t\twriter.insertElement( 'paragraph', blockquote, 'end' );\n\t *\t\t// Inserts after an image:\n\t *\t\twriter.insertElement( 'paragraph', image, 'after' );\n\t *\n\t * These parameters works the same way as {@link #createPositionAt `writer.createPositionAt()`}.\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * third parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\tinsertElement( name, attributes, itemOrPosition, offset ) {\n\t\tif ( attributes instanceof DocumentFragment || attributes instanceof Element || attributes instanceof Position ) {\n\t\t\tthis.insert( this.createElement( name ), attributes, itemOrPosition );\n\t\t} else {\n\t\t\tthis.insert( this.createElement( name, attributes ), itemOrPosition, offset );\n\t\t}\n\t}\n\n\t/**\n\t * Inserts item at the end of the given parent.\n\t *\n\t *\t\tconst paragraph = writer.createElement( 'paragraph' );\n\t *\t\twriter.append( paragraph, root );\n\t *\n\t * Note that if the item already has parent it will be removed from the previous parent.\n\t *\n\t * If you want to move {@link module:engine/model/range~Range range} instead of an\n\t * {@link module:engine/model/item~Item item} use {@link module:engine/model/writer~Writer#move `Writer#move()`}.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/documentfragment~DocumentFragment}\n\t * item Item or document fragment to insert.\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} parent\n\t */\n\tappend( item, parent ) {\n\t\tthis.insert( item, parent, 'end' );\n\t}\n\n\t/**\n\t * Creates text node and inserts it at the end of the parent. You can optionally set text attributes:\n\t *\n\t *\t\twriter.appendText( 'foo', paragraph );\n\t *\t\twriter.appendText( 'foo', { bold: true }, paragraph );\n\t *\n\t * @param {String} text Text data.\n\t * @param {Object} [attributes] Text attributes.\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} parent\n\t */\n\tappendText( text, attributes, parent ) {\n\t\tif ( attributes instanceof DocumentFragment || attributes instanceof Element ) {\n\t\t\tthis.insert( this.createText( text ), attributes, 'end' );\n\t\t} else {\n\t\t\tthis.insert( this.createText( text, attributes ), parent, 'end' );\n\t\t}\n\t}\n\n\t/**\n\t * Creates element and inserts it at the end of the parent. You can optionally set attributes:\n\t *\n\t *\t\twriter.appendElement( 'paragraph', root );\n\t *\t\twriter.appendElement( 'paragraph', { alignment: 'center' }, root );\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} parent\n\t */\n\tappendElement( name, attributes, parent ) {\n\t\tif ( attributes instanceof DocumentFragment || attributes instanceof Element ) {\n\t\t\tthis.insert( this.createElement( name ), attributes, 'end' );\n\t\t} else {\n\t\t\tthis.insert( this.createElement( name, attributes ), parent, 'end' );\n\t\t}\n\t}\n\n\t/**\n\t * Sets value of the attribute with given key on a {@link module:engine/model/item~Item model item}\n\t * or on a {@link module:engine/model/range~Range range}.\n\t *\n\t * @param {String} key Attribute key.\n\t * @param {*} value Attribute new value.\n\t * @param {module:engine/model/item~Item|module:engine/model/range~Range} itemOrRange\n\t * Model item or range on which the attribute will be set.\n\t */\n\tsetAttribute( key, value, itemOrRange ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( itemOrRange instanceof Range ) {\n\t\t\tconst ranges = itemOrRange.getMinimalFlatRanges();\n\n\t\t\tfor ( const range of ranges ) {\n\t\t\t\tsetAttributeOnRange( this, key, value, range );\n\t\t\t}\n\t\t} else {\n\t\t\tsetAttributeOnItem( this, key, value, itemOrRange );\n\t\t}\n\t}\n\n\t/**\n\t * Sets values of attributes on a {@link module:engine/model/item~Item model item}\n\t * or on a {@link module:engine/model/range~Range range}.\n\t *\n\t *\t\twriter.setAttributes( {\n\t *\t\t\tbold: true,\n\t *\t\t\titalic: true\n\t *\t\t}, range );\n\t *\n\t * @param {Object} attributes Attributes keys and values.\n\t * @param {module:engine/model/item~Item|module:engine/model/range~Range} itemOrRange\n\t * Model item or range on which the attributes will be set.\n\t */\n\tsetAttributes( attributes, itemOrRange ) {\n\t\tfor ( const [ key, val ] of toMap( attributes ) ) {\n\t\t\tthis.setAttribute( key, val, itemOrRange );\n\t\t}\n\t}\n\n\t/**\n\t * Removes an attribute with given key from a {@link module:engine/model/item~Item model item}\n\t * or from a {@link module:engine/model/range~Range range}.\n\t *\n\t * @param {String} key Attribute key.\n\t * @param {module:engine/model/item~Item|module:engine/model/range~Range} itemOrRange\n\t * Model item or range from which the attribute will be removed.\n\t */\n\tremoveAttribute( key, itemOrRange ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( itemOrRange instanceof Range ) {\n\t\t\tconst ranges = itemOrRange.getMinimalFlatRanges();\n\n\t\t\tfor ( const range of ranges ) {\n\t\t\t\tsetAttributeOnRange( this, key, null, range );\n\t\t\t}\n\t\t} else {\n\t\t\tsetAttributeOnItem( this, key, null, itemOrRange );\n\t\t}\n\t}\n\n\t/**\n\t * Removes all attributes from all elements in the range or from the given item.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/range~Range} itemOrRange\n\t * Model item or range from which all attributes will be removed.\n\t */\n\tclearAttributes( itemOrRange ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tconst removeAttributesFromItem = item => {\n\t\t\tfor ( const attribute of item.getAttributeKeys() ) {\n\t\t\t\tthis.removeAttribute( attribute, item );\n\t\t\t}\n\t\t};\n\n\t\tif ( !( itemOrRange instanceof Range ) ) {\n\t\t\tremoveAttributesFromItem( itemOrRange );\n\t\t} else {\n\t\t\tfor ( const item of itemOrRange.getItems() ) {\n\t\t\t\tremoveAttributesFromItem( item );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Moves all items in the source range to the target position.\n\t *\n\t *\t\twriter.move( sourceRange, targetPosition );\n\t *\n\t * Instead of the target position you can use parent and offset or define that range should be moved to the end\n\t * or before or after chosen item:\n\t *\n\t *\t\t// Moves all items in the range to the paragraph at offset 5:\n\t *\t\twriter.move( sourceRange, paragraph, 5 );\n\t *\t\t// Moves all items in the range to the end of a blockquote:\n\t *\t\twriter.move( sourceRange, blockquote, 'end' );\n\t *\t\t// Moves all items in the range to a position after an image:\n\t *\t\twriter.move( sourceRange, image, 'after' );\n\t *\n\t * These parameters works the same way as {@link #createPositionAt `writer.createPositionAt()`}.\n\t *\n\t * Note that items can be moved only within the same tree. It means that you can move items within the same root\n\t * (element or document fragment) or between {@link module:engine/model/document~Document#roots documents roots},\n\t * but you can not move items from document fragment to the document or from one detached element to another. Use\n\t * {@link module:engine/model/writer~Writer#insert} in such cases.\n\t *\n\t * @param {module:engine/model/range~Range} range Source range.\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * second parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\tmove( range, itemOrPosition, offset ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( !( range instanceof Range ) ) {\n\t\t\t/**\n\t\t\t * Invalid range to move.\n\t\t\t *\n\t\t\t * @error writer-move-invalid-range\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-move-invalid-range', this );\n\t\t}\n\n\t\tif ( !range.isFlat ) {\n\t\t\t/**\n\t\t\t * Range to move is not flat.\n\t\t\t *\n\t\t\t * @error writer-move-range-not-flat\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-move-range-not-flat', this );\n\t\t}\n\n\t\tconst position = Position._createAt( itemOrPosition, offset );\n\n\t\t// Do not move anything if the move target is same as moved range start.\n\t\tif ( position.isEqual( range.start ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If part of the marker is removed, create additional marker operation for undo purposes.\n\t\tthis._addOperationForAffectedMarkers( 'move', range );\n\n\t\tif ( !isSameTree( range.root, position.root ) ) {\n\t\t\t/**\n\t\t\t * Range is going to be moved within not the same document. Please use\n\t\t\t * {@link module:engine/model/writer~Writer#insert insert} instead.\n\t\t\t *\n\t\t\t * @error writer-move-different-document\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-move-different-document', this );\n\t\t}\n\n\t\tconst version = range.root.document ? range.root.document.version : null;\n\t\tconst operation = new MoveOperation( range.start, range.end.offset - range.start.offset, position, version );\n\n\t\tthis.batch.addOperation( operation );\n\t\tthis.model.applyOperation( operation );\n\t}\n\n\t/**\n\t * Removes given model {@link module:engine/model/item~Item item} or {@link module:engine/model/range~Range range}.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/range~Range} itemOrRange Model item or range to remove.\n\t */\n\tremove( itemOrRange ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tconst rangeToRemove = itemOrRange instanceof Range ? itemOrRange : Range._createOn( itemOrRange );\n\t\tconst ranges = rangeToRemove.getMinimalFlatRanges().reverse();\n\n\t\tfor ( const flat of ranges ) {\n\t\t\t// If part of the marker is removed, create additional marker operation for undo purposes.\n\t\t\tthis._addOperationForAffectedMarkers( 'move', flat );\n\n\t\t\tapplyRemoveOperation( flat.start, flat.end.offset - flat.start.offset, this.batch, this.model );\n\t\t}\n\t}\n\n\t/**\n\t * Merges two siblings at the given position.\n\t *\n\t * Node before and after the position have to be an element. Otherwise `writer-merge-no-element-before` or\n\t * `writer-merge-no-element-after` error will be thrown.\n\t *\n\t * @param {module:engine/model/position~Position} position Position between merged elements.\n\t */\n\tmerge( position ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tconst nodeBefore = position.nodeBefore;\n\t\tconst nodeAfter = position.nodeAfter;\n\n\t\t// If part of the marker is removed, create additional marker operation for undo purposes.\n\t\tthis._addOperationForAffectedMarkers( 'merge', position );\n\n\t\tif ( !( nodeBefore instanceof Element ) ) {\n\t\t\t/**\n\t\t\t * Node before merge position must be an element.\n\t\t\t *\n\t\t\t * @error writer-merge-no-element-before\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-merge-no-element-before', this );\n\t\t}\n\n\t\tif ( !( nodeAfter instanceof Element ) ) {\n\t\t\t/**\n\t\t\t * Node after merge position must be an element.\n\t\t\t *\n\t\t\t * @error writer-merge-no-element-after\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-merge-no-element-after', this );\n\t\t}\n\n\t\tif ( !position.root.document ) {\n\t\t\tthis._mergeDetached( position );\n\t\t} else {\n\t\t\tthis._merge( position );\n\t\t}\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createPositionFromPath `Model#createPositionFromPath()`}.\n\t *\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} root Root of the position.\n\t * @param {Array.<Number>} path Position path. See {@link module:engine/model/position~Position#path}.\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone'] Position stickiness.\n\t * See {@link module:engine/model/position~PositionStickiness}.\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tcreatePositionFromPath( root, path, stickiness ) {\n\t\treturn this.model.createPositionFromPath( root, path, stickiness );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createPositionAt `Model#createPositionAt()`}.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/model/item~Item model item}.\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tcreatePositionAt( itemOrPosition, offset ) {\n\t\treturn this.model.createPositionAt( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createPositionAfter `Model#createPositionAfter()`}.\n\t *\n\t * @param {module:engine/model/item~Item} item Item after which the position should be placed.\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tcreatePositionAfter( item ) {\n\t\treturn this.model.createPositionAfter( item );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createPositionBefore `Model#createPositionBefore()`}.\n\t *\n\t * @param {module:engine/model/item~Item} item Item after which the position should be placed.\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tcreatePositionBefore( item ) {\n\t\treturn this.model.createPositionBefore( item );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createRange `Model#createRange()`}.\n\t *\n\t * @param {module:engine/model/position~Position} start Start position.\n\t * @param {module:engine/model/position~Position} [end] End position. If not set, range will be collapsed at `start` position.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tcreateRange( start, end ) {\n\t\treturn this.model.createRange( start, end );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createRangeIn `Model#createRangeIn()`}.\n\t *\n\t * @param {module:engine/model/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tcreateRangeIn( element ) {\n\t\treturn this.model.createRangeIn( element );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createRangeOn `Model#createRangeOn()`}.\n\t *\n\t * @param {module:engine/model/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tcreateRangeOn( element ) {\n\t\treturn this.model.createRangeOn( element );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createSelection `Model#createSelection()`}.\n\t *\n\t * @param {module:engine/model/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @returns {module:engine/model/selection~Selection}\n\t */\n\tcreateSelection( selectable, placeOrOffset, options ) {\n\t\treturn this.model.createSelection( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Performs merge action in a detached tree.\n\t *\n\t * @private\n\t * @param {module:engine/model/position~Position} position Position between merged elements.\n\t */\n\t_mergeDetached( position ) {\n\t\tconst nodeBefore = position.nodeBefore;\n\t\tconst nodeAfter = position.nodeAfter;\n\n\t\tthis.move( Range._createIn( nodeAfter ), Position._createAt( nodeBefore, 'end' ) );\n\t\tthis.remove( nodeAfter );\n\t}\n\n\t/**\n\t * Performs merge action in a non-detached tree.\n\t *\n\t * @private\n\t * @param {module:engine/model/position~Position} position Position between merged elements.\n\t */\n\t_merge( position ) {\n\t\tconst targetPosition = Position._createAt( position.nodeBefore, 'end' );\n\t\tconst sourcePosition = Position._createAt( position.nodeAfter, 0 );\n\n\t\tconst graveyard = position.root.document.graveyard;\n\t\tconst graveyardPosition = new Position( graveyard, [ 0 ] );\n\n\t\tconst version = position.root.document.version;\n\n\t\tconst merge = new MergeOperation( sourcePosition, position.nodeAfter.maxOffset, targetPosition, graveyardPosition, version );\n\n\t\tthis.batch.addOperation( merge );\n\t\tthis.model.applyOperation( merge );\n\t}\n\n\t/**\n\t * Renames the given element.\n\t *\n\t * @param {module:engine/model/element~Element} element The element to rename.\n\t * @param {String} newName New element name.\n\t */\n\trename( element, newName ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( !( element instanceof Element ) ) {\n\t\t\t/**\n\t\t\t * Trying to rename an object which is not an instance of Element.\n\t\t\t *\n\t\t\t * @error writer-rename-not-element-instance\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'writer-rename-not-element-instance',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tconst version = element.root.document ? element.root.document.version : null;\n\t\tconst renameOperation = new RenameOperation( Position._createBefore( element ), element.name, newName, version );\n\n\t\tthis.batch.addOperation( renameOperation );\n\t\tthis.model.applyOperation( renameOperation );\n\t}\n\n\t/**\n\t * Splits elements starting from the given position and going to the top of the model tree as long as given\n\t * `limitElement` is reached. When `limitElement` is not defined then only the parent of the given position will be split.\n\t *\n\t * The element needs to have a parent. It cannot be a root element nor a document fragment.\n\t * The `writer-split-element-no-parent` error will be thrown if you try to split an element with no parent.\n\t *\n\t * @param {module:engine/model/position~Position} position Position of split.\n\t * @param {module:engine/model/node~Node} [limitElement] Stop splitting when this element will be reached.\n\t * @returns {Object} result Split result.\n\t * @returns {module:engine/model/position~Position} result.position Position between split elements.\n\t * @returns {module:engine/model/range~Range} result.range Range that stars from the end of the first split element and ends\n\t * at the beginning of the first copy element.\n\t */\n\tsplit( position, limitElement ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tlet splitElement = position.parent;\n\n\t\tif ( !splitElement.parent ) {\n\t\t\t/**\n\t\t\t * Element with no parent can not be split.\n\t\t\t *\n\t\t\t * @error writer-split-element-no-parent\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-split-element-no-parent', this );\n\t\t}\n\n\t\t// When limit element is not defined lets set splitElement parent as limit.\n\t\tif ( !limitElement ) {\n\t\t\tlimitElement = splitElement.parent;\n\t\t}\n\n\t\tif ( !position.parent.getAncestors( { includeSelf: true } ).includes( limitElement ) ) {\n\t\t\t/**\n\t\t\t * Limit element is not a position ancestor.\n\t\t\t *\n\t\t\t * @error writer-split-invalid-limit-element\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-split-invalid-limit-element', this );\n\t\t}\n\n\t\t// We need to cache elements that will be created as a result of the first split because\n\t\t// we need to create a range from the end of the first split element to the beginning of the\n\t\t// first copy element. This should be handled by LiveRange but it doesn't work on detached nodes.\n\t\tlet firstSplitElement, firstCopyElement;\n\n\t\tdo {\n\t\t\tconst version = splitElement.root.document ? splitElement.root.document.version : null;\n\t\t\tconst howMany = splitElement.maxOffset - position.offset;\n\t\t\tconst split = new SplitOperation( position, howMany, null, version );\n\n\t\t\tthis.batch.addOperation( split );\n\t\t\tthis.model.applyOperation( split );\n\n\t\t\t// Cache result of the first split.\n\t\t\tif ( !firstSplitElement && !firstCopyElement ) {\n\t\t\t\tfirstSplitElement = splitElement;\n\t\t\t\tfirstCopyElement = position.parent.nextSibling;\n\t\t\t}\n\n\t\t\tposition = this.createPositionAfter( position.parent );\n\t\t\tsplitElement = position.parent;\n\t\t} while ( splitElement !== limitElement );\n\n\t\treturn {\n\t\t\tposition,\n\t\t\trange: new Range( Position._createAt( firstSplitElement, 'end' ), Position._createAt( firstCopyElement, 0 ) )\n\t\t};\n\t}\n\n\t/**\n\t * Wraps the given range with the given element or with a new element (if a string was passed).\n\t *\n\t * **Note:** range to wrap should be a \"flat range\" (see {@link module:engine/model/range~Range#isFlat `Range#isFlat`}).\n\t * If not, an error will be thrown.\n\t *\n\t * @param {module:engine/model/range~Range} range Range to wrap.\n\t * @param {module:engine/model/element~Element|String} elementOrString Element or name of element to wrap the range with.\n\t */\n\twrap( range, elementOrString ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( !range.isFlat ) {\n\t\t\t/**\n\t\t\t * Range to wrap is not flat.\n\t\t\t *\n\t\t\t * @error writer-wrap-range-not-flat\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-wrap-range-not-flat', this );\n\t\t}\n\n\t\tconst element = elementOrString instanceof Element ? elementOrString : new Element( elementOrString );\n\n\t\tif ( element.childCount > 0 ) {\n\t\t\t/**\n\t\t\t * Element to wrap with is not empty.\n\t\t\t *\n\t\t\t * @error writer-wrap-element-not-empty\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-wrap-element-not-empty', this );\n\t\t}\n\n\t\tif ( element.parent !== null ) {\n\t\t\t/**\n\t\t\t * Element to wrap with is already attached to a tree model.\n\t\t\t *\n\t\t\t * @error writer-wrap-element-attached\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-wrap-element-attached', this );\n\t\t}\n\n\t\tthis.insert( element, range.start );\n\n\t\t// Shift the range-to-wrap because we just inserted an element before that range.\n\t\tconst shiftedRange = new Range( range.start.getShiftedBy( 1 ), range.end.getShiftedBy( 1 ) );\n\n\t\tthis.move( shiftedRange, Position._createAt( element, 0 ) );\n\t}\n\n\t/**\n\t * Unwraps children of the given element – all its children are moved before it and then the element is removed.\n\t * Throws error if you try to unwrap an element which does not have a parent.\n\t *\n\t * @param {module:engine/model/element~Element} element Element to unwrap.\n\t */\n\tunwrap( element ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( element.parent === null ) {\n\t\t\t/**\n\t\t\t * Trying to unwrap an element which has no parent.\n\t\t\t *\n\t\t\t * @error writer-unwrap-element-no-parent\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-unwrap-element-no-parent', this );\n\t\t}\n\n\t\tthis.move( Range._createIn( element ), this.createPositionAfter( element ) );\n\t\tthis.remove( element );\n\t}\n\n\t/**\n\t * Adds a {@link module:engine/model/markercollection~Marker marker}. Marker is a named range, which tracks\n\t * changes in the document and updates its range automatically, when model tree changes.\n\t *\n\t * As the first parameter you can set marker name.\n\t *\n\t * The required `options.usingOperation` parameter lets you decide if the marker should be managed by operations or not. See\n\t * {@link module:engine/model/markercollection~Marker marker class description} to learn about the difference between\n\t * markers managed by operations and not-managed by operations.\n\t *\n\t * The `options.affectsData` parameter, which defaults to `false`, allows you to define if a marker affects the data. It should be\n\t * `true` when the marker change changes the data returned by the\n\t * {@link module:core/editor/utils/dataapimixin~DataApi#getData `editor.getData()`} method.\n\t * When set to `true` it fires the {@link module:engine/model/document~Document#event:change:data `change:data`} event.\n\t * When set to `false` it fires the {@link module:engine/model/document~Document#event:change `change`} event.\n\t *\n\t * Create marker directly base on marker's name:\n\t *\n\t *\t\taddMarker( markerName, { range, usingOperation: false } );\n\t *\n\t * Create marker using operation:\n\t *\n\t *\t\taddMarker( markerName, { range, usingOperation: true } );\n\t *\n\t * Create marker that affects the editor data:\n\t *\n\t *\t\taddMarker( markerName, { range, usingOperation: false, affectsData: true } );\n\t *\n\t * Note: For efficiency reasons, it's best to create and keep as little markers as possible.\n\t *\n\t * @see module:engine/model/markercollection~Marker\n\t * @param {String} name Name of a marker to create - must be unique.\n\t * @param {Object} options\n\t * @param {Boolean} options.usingOperation Flag indicating that the marker should be added by MarkerOperation.\n\t * See {@link module:engine/model/markercollection~Marker#managedUsingOperations}.\n\t * @param {module:engine/model/range~Range} options.range Marker range.\n\t * @param {Boolean} [options.affectsData=false] Flag indicating that the marker changes the editor data.\n\t * @returns {module:engine/model/markercollection~Marker} Marker that was set.\n\t */\n\taddMarker( name, options ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( !options || typeof options.usingOperation != 'boolean' ) {\n\t\t\t/**\n\t\t\t * The `options.usingOperation` parameter is required when adding a new marker.\n\t\t\t *\n\t\t\t * @error writer-addmarker-no-usingoperation\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-addmarker-no-usingoperation', this );\n\t\t}\n\n\t\tconst usingOperation = options.usingOperation;\n\t\tconst range = options.range;\n\t\tconst affectsData = options.affectsData === undefined ? false : options.affectsData;\n\n\t\tif ( this.model.markers.has( name ) ) {\n\t\t\t/**\n\t\t\t * Marker with provided name already exists.\n\t\t\t *\n\t\t\t * @error writer-addmarker-marker-exists\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-addmarker-marker-exists', this );\n\t\t}\n\n\t\tif ( !range ) {\n\t\t\t/**\n\t\t\t * Range parameter is required when adding a new marker.\n\t\t\t *\n\t\t\t * @error writer-addmarker-no-range\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-addmarker-no-range', this );\n\t\t}\n\n\t\tif ( !usingOperation ) {\n\t\t\treturn this.model.markers._set( name, range, usingOperation, affectsData );\n\t\t}\n\n\t\tapplyMarkerOperation( this, name, null, range, affectsData );\n\n\t\treturn this.model.markers.get( name );\n\t}\n\n\t/**\n\t * Adds, updates or refreshes a {@link module:engine/model/markercollection~Marker marker}. Marker is a named range, which tracks\n\t * changes in the document and updates its range automatically, when model tree changes. Still, it is possible to change the\n\t * marker's range directly using this method.\n\t *\n\t * As the first parameter you can set marker name or instance. If none of them is provided, new marker, with a unique\n\t * name is created and returned.\n\t *\n\t * As the second parameter you can set the new marker data or leave this parameter as empty which will just refresh\n\t * the marker by triggering downcast conversion for it. Refreshing the marker is useful when you want to change\n\t * the marker {@link module:engine/view/element~Element view element} without changing any marker data.\n\t *\n\t * \t\tlet isCommentActive = false;\n\t *\n\t * \t\tmodel.conversion.markerToHighlight( {\n\t * \t\t\tmodel: 'comment',\n\t *\t\t\tview: data => {\n\t *\t\t\t\tconst classes = [ 'comment-marker' ];\n\t *\n\t *\t\t\t\tif ( isCommentActive ) {\n\t *\t\t\t\t\tclasses.push( 'comment-marker--active' );\n\t *\t\t\t\t}\n\t *\n\t *\t\t\t\treturn { classes };\n\t *\t\t\t}\n\t * \t\t} );\n\t *\n\t * \t\t// Change the property that indicates if marker is displayed as active or not.\n\t * \t\tisCommentActive = true;\n\t *\n\t * \t\t// And refresh the marker to convert it with additional class.\n\t * \t\tmodel.change( writer => writer.updateMarker( 'comment' ) );\n\t *\n\t * The `options.usingOperation` parameter lets you change if the marker should be managed by operations or not. See\n\t * {@link module:engine/model/markercollection~Marker marker class description} to learn about the difference between\n\t * markers managed by operations and not-managed by operations. It is possible to change this option for an existing marker.\n\t *\n\t * The `options.affectsData` parameter, which defaults to `false`, allows you to define if a marker affects the data. It should be\n\t * `true` when the marker change changes the data returned by\n\t * the {@link module:core/editor/utils/dataapimixin~DataApi#getData `editor.getData()`} method.\n\t * When set to `true` it fires the {@link module:engine/model/document~Document#event:change:data `change:data`} event.\n\t * When set to `false` it fires the {@link module:engine/model/document~Document#event:change `change`} event.\n\t *\n\t * Update marker directly base on marker's name:\n\t *\n\t *\t\tupdateMarker( markerName, { range } );\n\t *\n\t * Update marker using operation:\n\t *\n\t *\t\tupdateMarker( marker, { range, usingOperation: true } );\n\t *\t\tupdateMarker( markerName, { range, usingOperation: true } );\n\t *\n\t * Change marker's option (start using operations to manage it):\n\t *\n\t *\t\tupdateMarker( marker, { usingOperation: true } );\n\t *\n\t * Change marker's option (inform the engine, that the marker does not affect the data anymore):\n\t *\n\t *\t\tupdateMarker( markerName, { affectsData: false } );\n\t *\n\t * @see module:engine/model/markercollection~Marker\n\t * @param {String|module:engine/model/markercollection~Marker} markerOrName Name of a marker to update, or a marker instance.\n\t * @param {Object} [options] If options object is not defined then marker will be refreshed by triggering\n\t * downcast conversion for this marker with the same data.\n\t * @param {module:engine/model/range~Range} [options.range] Marker range to update.\n\t * @param {Boolean} [options.usingOperation] Flag indicated whether the marker should be added by MarkerOperation.\n\t * See {@link module:engine/model/markercollection~Marker#managedUsingOperations}.\n\t * @param {Boolean} [options.affectsData] Flag indicating that the marker changes the editor data.\n\t */\n\tupdateMarker( markerOrName, options ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tconst markerName = typeof markerOrName == 'string' ? markerOrName : markerOrName.name;\n\t\tconst currentMarker = this.model.markers.get( markerName );\n\n\t\tif ( !currentMarker ) {\n\t\t\t/**\n\t\t\t * Marker with provided name does not exists.\n\t\t\t *\n\t\t\t * @error writer-updatemarker-marker-not-exists\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-updatemarker-marker-not-exists', this );\n\t\t}\n\n\t\tif ( !options ) {\n\t\t\tthis.model.markers._refresh( currentMarker );\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst hasUsingOperationDefined = typeof options.usingOperation == 'boolean';\n\t\tconst affectsDataDefined = typeof options.affectsData == 'boolean';\n\n\t\t// Use previously defined marker's affectsData if the property is not provided.\n\t\tconst affectsData = affectsDataDefined ? options.affectsData : currentMarker.affectsData;\n\n\t\tif ( !hasUsingOperationDefined && !options.range && !affectsDataDefined ) {\n\t\t\t/**\n\t\t\t * One of the options is required - provide range, usingOperations or affectsData.\n\t\t\t *\n\t\t\t * @error writer-updatemarker-wrong-options\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-updatemarker-wrong-options', this );\n\t\t}\n\n\t\tconst currentRange = currentMarker.getRange();\n\t\tconst updatedRange = options.range ? options.range : currentRange;\n\n\t\tif ( hasUsingOperationDefined && options.usingOperation !== currentMarker.managedUsingOperations ) {\n\t\t\t// The marker type is changed so it's necessary to create proper operations.\n\t\t\tif ( options.usingOperation ) {\n\t\t\t\t// If marker changes to a managed one treat this as synchronizing existing marker.\n\t\t\t\t// Create `MarkerOperation` with `oldRange` set to `null`, so reverse operation will remove the marker.\n\t\t\t\tapplyMarkerOperation( this, markerName, null, updatedRange, affectsData );\n\t\t\t} else {\n\t\t\t\t// If marker changes to a marker that do not use operations then we need to create additional operation\n\t\t\t\t// that removes that marker first.\n\t\t\t\tapplyMarkerOperation( this, markerName, currentRange, null, affectsData );\n\n\t\t\t\t// Although not managed the marker itself should stay in model and its range should be preserver or changed to passed range.\n\t\t\t\tthis.model.markers._set( markerName, updatedRange, undefined, affectsData );\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Marker's type doesn't change so update it accordingly.\n\t\tif ( currentMarker.managedUsingOperations ) {\n\t\t\tapplyMarkerOperation( this, markerName, currentRange, updatedRange, affectsData );\n\t\t} else {\n\t\t\tthis.model.markers._set( markerName, updatedRange, undefined, affectsData );\n\t\t}\n\t}\n\n\t/**\n\t * Removes given {@link module:engine/model/markercollection~Marker marker} or marker with given name.\n\t * The marker is removed accordingly to how it has been created, so if the marker was created using operation,\n\t * it will be destroyed using operation.\n\t *\n\t * @param {module:engine/model/markercollection~Marker|String} markerOrName Marker or marker name to remove.\n\t */\n\tremoveMarker( markerOrName ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tconst name = typeof markerOrName == 'string' ? markerOrName : markerOrName.name;\n\n\t\tif ( !this.model.markers.has( name ) ) {\n\t\t\t/**\n\t\t\t * Trying to remove marker which does not exist.\n\t\t\t *\n\t\t\t * @error writer-removemarker-no-marker\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-removemarker-no-marker', this );\n\t\t}\n\n\t\tconst marker = this.model.markers.get( name );\n\n\t\tif ( !marker.managedUsingOperations ) {\n\t\t\tthis.model.markers._remove( name );\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst oldRange = marker.getRange();\n\n\t\tapplyMarkerOperation( this, name, oldRange, null, marker.affectsData );\n\t}\n\n\t/**\n\t * Sets the document's selection (ranges and direction) to the specified location based on the given\n\t * {@link module:engine/model/selection~Selectable selectable} or creates an empty selection if no arguments were passed.\n\t *\n\t *\t\t// Sets selection to the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\twriter.setSelection( range );\n\t *\n\t *\t\t// Sets selection to given ranges.\n\t *\t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\twriter.setSelection( ranges );\n\t *\n\t *\t\t// Sets selection to other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\twriter.setSelection( otherSelection );\n\t *\n\t *\t\t// Sets selection to the given document selection.\n\t *\t\tconst documentSelection = model.document.selection;\n\t *\t\twriter.setSelection( documentSelection );\n\t *\n\t *\t\t// Sets collapsed selection at the given position.\n\t *\t\tconst position = writer.createPosition( root, path );\n\t *\t\twriter.setSelection( position );\n\t *\n\t *\t\t// Sets collapsed selection at the position of the given node and an offset.\n\t *\t\twriter.setSelection( paragraph, offset );\n\t *\n\t * Creates a range inside an {@link module:engine/model/element~Element element} which starts before the first child of\n \t * that element and ends after the last child of that element.\n\t *\n\t *\t\twriter.setSelection( paragraph, 'in' );\n\t *\n\t * Creates a range on an {@link module:engine/model/item~Item item} which starts before the item and ends just after the item.\n\t *\n\t *\t\twriter.setSelection( paragraph, 'on' );\n\t *\n\t *\t\t// Removes all selection's ranges.\n\t *\t\twriter.setSelection( null );\n\t *\n\t * `Writer#setSelection()` allow passing additional options (`backward`) as the last argument.\n\t *\n\t *\t\t// Sets selection as backward.\n\t *\t\twriter.setSelection( range, { backward: true } );\n\t *\n\t * Throws `writer-incorrect-use` error when the writer is used outside the `change()` block.\n\t *\n\t * @param {module:engine/model/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t */\n\tsetSelection( selectable, placeOrOffset, options ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tthis.model.document.selection._setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Moves {@link module:engine/model/documentselection~DocumentSelection#focus} to the specified location.\n\t *\n\t * The location can be specified in the same form as\n\t * {@link #createPositionAt `writer.createPositionAt()`} parameters.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset=0] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\tsetSelectionFocus( itemOrPosition, offset ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tthis.model.document.selection._setFocus( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Sets attribute(s) on the selection. If attribute with the same key already is set, it's value is overwritten.\n\t *\n\t * Using key and value pair:\n\t *\n\t * \twriter.setSelectionAttribute( 'italic', true );\n\t *\n\t * Using key-value object:\n\t *\n\t * \twriter.setSelectionAttribute( { italic: true, bold: false } );\n\t *\n\t * Using iterable object:\n\t *\n\t * \twriter.setSelectionAttribute( new Map( [ [ 'italic', true ] ] ) );\n\t *\n\t * @param {String|Object|Iterable.<*>} keyOrObjectOrIterable Key of the attribute to set\n\t * or object / iterable of key => value attribute pairs.\n\t * @param {*} [value] Attribute value.\n\t */\n\tsetSelectionAttribute( keyOrObjectOrIterable, value ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( typeof keyOrObjectOrIterable === 'string' ) {\n\t\t\tthis._setSelectionAttribute( keyOrObjectOrIterable, value );\n\t\t} else {\n\t\t\tfor ( const [ key, value ] of toMap( keyOrObjectOrIterable ) ) {\n\t\t\t\tthis._setSelectionAttribute( key, value );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Removes attribute(s) with given key(s) from the selection.\n\t *\n\t * Remove one attribute:\n\t *\n\t *\t\twriter.removeSelectionAttribute( 'italic' );\n\t *\n\t * Remove multiple attributes:\n\t *\n\t *\t\twriter.removeSelectionAttribute( [ 'italic', 'bold' ] );\n\t *\n\t * @param {String|Iterable.<String>} keyOrIterableOfKeys Key of the attribute to remove or an iterable of attribute keys to remove.\n\t */\n\tremoveSelectionAttribute( keyOrIterableOfKeys ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( typeof keyOrIterableOfKeys === 'string' ) {\n\t\t\tthis._removeSelectionAttribute( keyOrIterableOfKeys );\n\t\t} else {\n\t\t\tfor ( const key of keyOrIterableOfKeys ) {\n\t\t\t\tthis._removeSelectionAttribute( key );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Temporarily changes the {@link module:engine/model/documentselection~DocumentSelection#isGravityOverridden gravity}\n\t * of the selection from left to right.\n\t *\n\t * The gravity defines from which direction the selection inherits its attributes. If it's the default left gravity,\n\t * then the selection (after being moved by the user) inherits attributes from its left-hand side.\n\t * This method allows to temporarily override this behavior by forcing the gravity to the right.\n\t *\n\t * For the following model fragment:\n\t *\n\t *\t\t<$text bold=\"true\" linkHref=\"url\">bar[]</$text><$text bold=\"true\">biz</$text>\n\t *\n\t * * Default gravity: selection will have the `bold` and `linkHref` attributes.\n\t * * Overridden gravity: selection will have `bold` attribute.\n\t *\n\t * **Note**: It returns an unique identifier which is required to restore the gravity. It guarantees the symmetry\n\t * of the process.\n\t *\n\t * @returns {String} The unique id which allows restoring the gravity.\n\t */\n\toverrideSelectionGravity() {\n\t\treturn this.model.document.selection._overrideGravity();\n\t}\n\n\t/**\n\t * Restores {@link ~Writer#overrideSelectionGravity} gravity to default.\n\t *\n\t * Restoring the gravity is only possible using the unique identifier returned by\n\t * {@link ~Writer#overrideSelectionGravity}. Note that the gravity remains overridden as long as won't be restored\n\t * the same number of times it was overridden.\n\t *\n\t * @param {String} uid The unique id returned by {@link ~Writer#overrideSelectionGravity}.\n\t */\n\trestoreSelectionGravity( uid ) {\n\t\tthis.model.document.selection._restoreGravity( uid );\n\t}\n\n\t/**\n\t * @private\n\t * @param {String} key Key of the attribute to remove.\n\t * @param {*} value Attribute value.\n\t */\n\t_setSelectionAttribute( key, value ) {\n\t\tconst selection = this.model.document.selection;\n\n\t\t// Store attribute in parent element if the selection is collapsed in an empty node.\n\t\tif ( selection.isCollapsed && selection.anchor.parent.isEmpty ) {\n\t\t\tconst storeKey = DocumentSelection._getStoreAttributeKey( key );\n\n\t\t\tthis.setAttribute( storeKey, value, selection.anchor.parent );\n\t\t}\n\n\t\tselection._setAttribute( key, value );\n\t}\n\n\t/**\n\t * @private\n\t * @param {String} key Key of the attribute to remove.\n\t */\n\t_removeSelectionAttribute( key ) {\n\t\tconst selection = this.model.document.selection;\n\n\t\t// Remove stored attribute from parent element if the selection is collapsed in an empty node.\n\t\tif ( selection.isCollapsed && selection.anchor.parent.isEmpty ) {\n\t\t\tconst storeKey = DocumentSelection._getStoreAttributeKey( key );\n\n\t\t\tthis.removeAttribute( storeKey, selection.anchor.parent );\n\t\t}\n\n\t\tselection._removeAttribute( key );\n\t}\n\n\t/**\n\t * Throws `writer-detached-writer-tries-to-modify-model` error when the writer is used outside of the `change()` block.\n\t *\n\t * @private\n\t */\n\t_assertWriterUsedCorrectly() {\n\t\t/**\n\t\t * Trying to use a writer outside a {@link module:engine/model/model~Model#change `change()`} or\n\t\t * {@link module:engine/model/model~Model#enqueueChange `enqueueChange()`} blocks.\n\t\t *\n\t\t * The writer can only be used inside these blocks which ensures that the model\n\t\t * can only be changed during such \"sessions\".\n\t\t *\n\t\t * @error writer-incorrect-use\n\t\t */\n\t\tif ( this.model._currentWriter !== this ) {\n\t\t\tthrow new CKEditorError( 'writer-incorrect-use', this );\n\t\t}\n\t}\n\n\t/**\n\t * For given action `type` and `positionOrRange` where the action happens, this function finds all affected markers\n\t * and applies a marker operation with the new marker range equal to the current range. Thanks to this, the marker range\n\t * can be later correctly processed during undo.\n\t *\n\t * @private\n\t * @param {'move'|'merge'} type Writer action type.\n\t * @param {module:engine/model/position~Position|module:engine/model/range~Range} positionOrRange Position or range\n\t * where the writer action happens.\n\t */\n\t_addOperationForAffectedMarkers( type, positionOrRange ) {\n\t\tfor ( const marker of this.model.markers ) {\n\t\t\tif ( !marker.managedUsingOperations ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst markerRange = marker.getRange();\n\t\t\tlet isAffected = false;\n\n\t\t\tif ( type === 'move' ) {\n\t\t\t\tisAffected =\n\t\t\t\t\tpositionOrRange.containsPosition( markerRange.start ) ||\n\t\t\t\t\tpositionOrRange.start.isEqual( markerRange.start ) ||\n\t\t\t\t\tpositionOrRange.containsPosition( markerRange.end ) ||\n\t\t\t\t\tpositionOrRange.end.isEqual( markerRange.end );\n\t\t\t} else {\n\t\t\t\t// if type === 'merge'.\n\t\t\t\tconst elementBefore = positionOrRange.nodeBefore;\n\t\t\t\tconst elementAfter = positionOrRange.nodeAfter;\n\n\t\t\t\t//               Start:  <p>Foo[</p><p>Bar]</p>\n\t\t\t\t//         After merge:  <p>Foo[Bar]</p>\n\t\t\t\t// After undoing split:  <p>Foo</p><p>[Bar]</p>     <-- incorrect, needs remembering for undo.\n\t\t\t\t//\n\t\t\t\tconst affectedInLeftElement = markerRange.start.parent == elementBefore && markerRange.start.isAtEnd;\n\n\t\t\t\t//               Start:  <p>[Foo</p><p>]Bar</p>\n\t\t\t\t//         After merge:  <p>[Foo]Bar</p>\n\t\t\t\t// After undoing split:  <p>[Foo]</p><p>Bar</p>     <-- incorrect, needs remembering for undo.\n\t\t\t\t//\n\t\t\t\tconst affectedInRightElement = markerRange.end.parent == elementAfter && markerRange.end.offset == 0;\n\n\t\t\t\t//               Start:  <p>[Foo</p>]<p>Bar</p>\n\t\t\t\t//         After merge:  <p>[Foo]Bar</p>\n\t\t\t\t// After undoing split:  <p>[Foo]</p><p>Bar</p>     <-- incorrect, needs remembering for undo.\n\t\t\t\t//\n\t\t\t\tconst affectedAfterLeftElement = markerRange.end.nodeAfter == elementAfter;\n\n\t\t\t\t//               Start:  <p>Foo</p>[<p>Bar]</p>\n\t\t\t\t//         After merge:  <p>Foo[Bar]</p>\n\t\t\t\t// After undoing split:  <p>Foo</p><p>[Bar]</p>     <-- incorrect, needs remembering for undo.\n\t\t\t\t//\n\t\t\t\tconst affectedBeforeRightElement = markerRange.start.nodeAfter == elementAfter;\n\n\t\t\t\tisAffected = affectedInLeftElement || affectedInRightElement || affectedAfterLeftElement || affectedBeforeRightElement;\n\t\t\t}\n\n\t\t\tif ( isAffected ) {\n\t\t\t\tthis.updateMarker( marker.name, { range: markerRange } );\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Sets given attribute to each node in given range. When attribute value is null then attribute will be removed.\n//\n// Because attribute operation needs to have the same attribute value on the whole range, this function splits\n// the range into smaller parts.\n//\n// Given `range` must be flat.\n//\n// @private\n// @param {module:engine/model/writer~Writer} writer\n// @param {String} key Attribute key.\n// @param {*} value Attribute new value.\n// @param {module:engine/model/range~Range} range Model range on which the attribute will be set.\nfunction setAttributeOnRange( writer, key, value, range ) {\n\tconst model = writer.model;\n\tconst doc = model.document;\n\n\t// Position of the last split, the beginning of the new range.\n\tlet lastSplitPosition = range.start;\n\n\t// Currently position in the scanning range. Because we need value after the position, it is not a current\n\t// position of the iterator but the previous one (we need to iterate one more time to get the value after).\n\tlet position;\n\n\t// Value before the currently position.\n\tlet valueBefore;\n\n\t// Value after the currently position.\n\tlet valueAfter;\n\n\tfor ( const val of range.getWalker( { shallow: true } ) ) {\n\t\tvalueAfter = val.item.getAttribute( key );\n\n\t\t// At the first run of the iterator the position in undefined. We also do not have a valueBefore, but\n\t\t// because valueAfter may be null, valueBefore may be equal valueAfter ( undefined == null ).\n\t\tif ( position && valueBefore != valueAfter ) {\n\t\t\t// if valueBefore == value there is nothing to change, so we add operation only if these values are different.\n\t\t\tif ( valueBefore != value ) {\n\t\t\t\taddOperation();\n\t\t\t}\n\n\t\t\tlastSplitPosition = position;\n\t\t}\n\n\t\tposition = val.nextPosition;\n\t\tvalueBefore = valueAfter;\n\t}\n\n\t// Because position in the loop is not the iterator position (see let position comment), the last position in\n\t// the while loop will be last but one position in the range. We need to check the last position manually.\n\tif ( position instanceof Position && position != lastSplitPosition && valueBefore != value ) {\n\t\taddOperation();\n\t}\n\n\tfunction addOperation() {\n\t\tconst range = new Range( lastSplitPosition, position );\n\t\tconst version = range.root.document ? doc.version : null;\n\t\tconst operation = new AttributeOperation( range, key, valueBefore, value, version );\n\n\t\twriter.batch.addOperation( operation );\n\t\tmodel.applyOperation( operation );\n\t}\n}\n\n// Sets given attribute to the given node. When attribute value is null then attribute will be removed.\n//\n// @private\n// @param {module:engine/model/writer~Writer} writer\n// @param {String} key Attribute key.\n// @param {*} value Attribute new value.\n// @param {module:engine/model/item~Item} item Model item on which the attribute will be set.\nfunction setAttributeOnItem( writer, key, value, item ) {\n\tconst model = writer.model;\n\tconst doc = model.document;\n\tconst previousValue = item.getAttribute( key );\n\tlet range, operation;\n\n\tif ( previousValue != value ) {\n\t\tconst isRootChanged = item.root === item;\n\n\t\tif ( isRootChanged ) {\n\t\t\t// If we change attributes of root element, we have to use `RootAttributeOperation`.\n\t\t\tconst version = item.document ? doc.version : null;\n\n\t\t\toperation = new RootAttributeOperation( item, key, previousValue, value, version );\n\t\t} else {\n\t\t\trange = new Range( Position._createBefore( item ), writer.createPositionAfter( item ) );\n\n\t\t\tconst version = range.root.document ? doc.version : null;\n\n\t\t\toperation = new AttributeOperation( range, key, previousValue, value, version );\n\t\t}\n\n\t\twriter.batch.addOperation( operation );\n\t\tmodel.applyOperation( operation );\n\t}\n}\n\n// Creates and applies marker operation to {@link module:engine/model/operation/operation~Operation operation}.\n//\n// @private\n// @param {module:engine/model/writer~Writer} writer\n// @param {String} name Marker name.\n// @param {module:engine/model/range~Range} oldRange Marker range before the change.\n// @param {module:engine/model/range~Range} newRange Marker range after the change.\n// @param {Boolean} affectsData\nfunction applyMarkerOperation( writer, name, oldRange, newRange, affectsData ) {\n\tconst model = writer.model;\n\tconst doc = model.document;\n\n\tconst operation = new MarkerOperation( name, oldRange, newRange, model.markers, affectsData, doc.version );\n\n\twriter.batch.addOperation( operation );\n\tmodel.applyOperation( operation );\n}\n\n// Creates `MoveOperation` or `DetachOperation` that removes `howMany` nodes starting from `position`.\n// The operation will be applied on given model instance and added to given operation instance.\n//\n// @private\n// @param {module:engine/model/position~Position} position Position from which nodes are removed.\n// @param {Number} howMany Number of nodes to remove.\n// @param {Batch} batch Batch to which the operation will be added.\n// @param {module:engine/model/model~Model} model Model instance on which operation will be applied.\nfunction applyRemoveOperation( position, howMany, batch, model ) {\n\tlet operation;\n\n\tif ( position.root.document ) {\n\t\tconst doc = model.document;\n\t\tconst graveyardPosition = new Position( doc.graveyard, [ 0 ] );\n\n\t\toperation = new MoveOperation( position, howMany, graveyardPosition, doc.version );\n\t} else {\n\t\toperation = new DetachOperation( position, howMany );\n\t}\n\n\tbatch.addOperation( operation );\n\tmodel.applyOperation( operation );\n}\n\n// Returns `true` if both root elements are the same element or both are documents root elements.\n//\n// Elements in the same tree can be moved (for instance you can move element form one documents root to another, or\n// within the same document fragment), but when element supposed to be moved from document fragment to the document, or\n// to another document it should be removed and inserted to avoid problems with OT. This is because features like undo or\n// collaboration may track changes on the document but ignore changes on detached fragments and should not get\n// unexpected `move` operation.\nfunction isSameTree( rootA, rootB ) {\n\t// If it is the same root this is the same tree.\n\tif ( rootA === rootB ) {\n\t\treturn true;\n\t}\n\n\t// If both roots are documents root it is operation within the document what we still treat as the same tree.\n\tif ( rootA instanceof RootElement && rootB instanceof RootElement ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/differ\n */\n\nimport Position from './position';\nimport Range from './range';\n\n/**\n * Calculates the difference between two model states.\n *\n * Receives operations that are to be applied on the model document. Marks parts of the model document tree which\n * are changed and saves the state of these elements before the change. Then, it compares saved elements with the\n * changed elements, after all changes are applied on the model document. Calculates the diff between saved\n * elements and new ones and returns a change set.\n */\nexport default class Differ {\n\t/**\n\t * Creates a `Differ` instance.\n\t *\n\t * @param {module:engine/model/markercollection~MarkerCollection} markerCollection Model's marker collection.\n\t */\n\tconstructor( markerCollection ) {\n\t\t/**\n\t\t * Reference to the model's marker collection.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/model/markercollection~MarkerCollection}\n\t\t */\n\t\tthis._markerCollection = markerCollection;\n\n\t\t/**\n\t\t * A map that stores changes that happened in a given element.\n\t\t *\n\t\t * The keys of the map are references to the model elements.\n\t\t * The values of the map are arrays with changes that were done on this element.\n\t\t *\n\t\t * @private\n\t\t * @type {Map}\n\t\t */\n\t\tthis._changesInElement = new Map();\n\n\t\t/**\n\t\t * A map that stores \"element's children snapshots\". A snapshot is representing children of a given element before\n\t\t * the first change was applied on that element. Snapshot items are objects with two properties: `name`,\n\t\t * containing the element name (or `'$text'` for a text node) and `attributes` which is a map of the node's attributes.\n\t\t *\n\t\t * @private\n\t\t * @type {Map}\n\t\t */\n\t\tthis._elementSnapshots = new Map();\n\n\t\t/**\n\t\t * A map that stores all changed markers.\n\t\t *\n\t\t * The keys of the map are marker names.\n\t\t * The values of the map are objects with the `oldRange` and `newRange` properties. They store the marker range\n\t\t * state before and after the change.\n\t\t *\n\t\t * @private\n\t\t * @type {Map}\n\t\t */\n\t\tthis._changedMarkers = new Map();\n\n\t\t/**\n\t\t * Stores the number of changes that were processed. Used to order the changes chronologically. It is important\n\t\t * when changes are sorted.\n\t\t *\n\t\t * @private\n\t\t * @type {Number}\n\t\t */\n\t\tthis._changeCount = 0;\n\n\t\t/**\n\t\t * For efficiency purposes, `Differ` stores the change set returned by the differ after {@link #getChanges} call.\n\t\t * Cache is reset each time a new operation is buffered. If the cache has not been reset, {@link #getChanges} will\n\t\t * return the cached value instead of calculating it again.\n\t\t *\n\t\t * This property stores those changes that did not take place in graveyard root.\n\t\t *\n\t\t * @private\n\t\t * @type {Array.<Object>|null}\n\t\t */\n\t\tthis._cachedChanges = null;\n\n\t\t/**\n\t\t * For efficiency purposes, `Differ` stores the change set returned by the differ after the {@link #getChanges} call.\n\t\t * The cache is reset each time a new operation is buffered. If the cache has not been reset, {@link #getChanges} will\n\t\t * return the cached value instead of calculating it again.\n\t\t *\n\t\t * This property stores all changes evaluated by `Differ`, including those that took place in the graveyard.\n\t\t *\n\t\t * @private\n\t\t * @type {Array.<Object>|null}\n\t\t */\n\t\tthis._cachedChangesWithGraveyard = null;\n\t}\n\n\t/**\n\t * Informs whether there are any changes buffered in `Differ`.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isEmpty() {\n\t\treturn this._changesInElement.size == 0 && this._changedMarkers.size == 0;\n\t}\n\n\t/**\n\t * Marks given `item` in differ to be \"refreshed\". It means that the item will be marked as removed and inserted in the differ changes\n\t * set, so it will be effectively re-converted when differ changes will be handled by a dispatcher.\n\t *\n\t * @param {module:engine/model/item~Item} item Item to refresh.\n\t */\n\trefreshItem( item ) {\n\t\tif ( this._isInInsertedElement( item.parent ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._markRemove( item.parent, item.startOffset, item.offsetSize );\n\t\tthis._markInsert( item.parent, item.startOffset, item.offsetSize );\n\n\t\tconst range = Range._createOn( item );\n\n\t\tfor ( const marker of this._markerCollection.getMarkersIntersectingRange( range ) ) {\n\t\t\tconst markerRange = marker.getRange();\n\n\t\t\tthis.bufferMarkerChange( marker.name, markerRange, markerRange, marker.affectsData );\n\t\t}\n\n\t\t// Clear cache after each buffered operation as it is no longer valid.\n\t\tthis._cachedChanges = null;\n\t}\n\n\t/**\n\t * Buffers the given operation. An operation has to be buffered before it is executed.\n\t *\n\t * Operation type is checked and it is checked which nodes it will affect. These nodes are then stored in `Differ`\n\t * in the state before the operation is executed.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation An operation to buffer.\n\t */\n\tbufferOperation( operation ) {\n\t\t// Below we take an operation, check its type, then use its parameters in marking (private) methods.\n\t\t// The general rule is to not mark elements inside inserted element. All inserted elements are re-rendered.\n\t\t// Marking changes in them would cause a \"double\" changing then.\n\t\t//\n\t\tswitch ( operation.type ) {\n\t\t\tcase 'insert': {\n\t\t\t\tif ( this._isInInsertedElement( operation.position.parent ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._markInsert( operation.position.parent, operation.position.offset, operation.nodes.maxOffset );\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'addAttribute':\n\t\t\tcase 'removeAttribute':\n\t\t\tcase 'changeAttribute': {\n\t\t\t\tfor ( const item of operation.range.getItems( { shallow: true } ) ) {\n\t\t\t\t\tif ( this._isInInsertedElement( item.parent ) ) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._markAttribute( item );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'remove':\n\t\t\tcase 'move':\n\t\t\tcase 'reinsert': {\n\t\t\t\t// When range is moved to the same position then not mark it as a change.\n\t\t\t\t// See: https://github.com/ckeditor/ckeditor5-engine/issues/1664.\n\t\t\t\tif (\n\t\t\t\t\toperation.sourcePosition.isEqual( operation.targetPosition ) ||\n\t\t\t\t\toperation.sourcePosition.getShiftedBy( operation.howMany ).isEqual( operation.targetPosition )\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst sourceParentInserted = this._isInInsertedElement( operation.sourcePosition.parent );\n\t\t\t\tconst targetParentInserted = this._isInInsertedElement( operation.targetPosition.parent );\n\n\t\t\t\tif ( !sourceParentInserted ) {\n\t\t\t\t\tthis._markRemove( operation.sourcePosition.parent, operation.sourcePosition.offset, operation.howMany );\n\t\t\t\t}\n\n\t\t\t\tif ( !targetParentInserted ) {\n\t\t\t\t\tthis._markInsert( operation.targetPosition.parent, operation.getMovedRangeStart().offset, operation.howMany );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'rename': {\n\t\t\t\tif ( this._isInInsertedElement( operation.position.parent ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._markRemove( operation.position.parent, operation.position.offset, 1 );\n\t\t\t\tthis._markInsert( operation.position.parent, operation.position.offset, 1 );\n\n\t\t\t\tconst range = Range._createFromPositionAndShift( operation.position, 1 );\n\n\t\t\t\tfor ( const marker of this._markerCollection.getMarkersIntersectingRange( range ) ) {\n\t\t\t\t\tconst markerRange = marker.getRange();\n\n\t\t\t\t\tthis.bufferMarkerChange( marker.name, markerRange, markerRange, marker.affectsData );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'split': {\n\t\t\t\tconst splitElement = operation.splitPosition.parent;\n\n\t\t\t\t// Mark that children of the split element were removed.\n\t\t\t\tif ( !this._isInInsertedElement( splitElement ) ) {\n\t\t\t\t\tthis._markRemove( splitElement, operation.splitPosition.offset, operation.howMany );\n\t\t\t\t}\n\n\t\t\t\t// Mark that the new element (split copy) was inserted.\n\t\t\t\tif ( !this._isInInsertedElement( operation.insertionPosition.parent ) ) {\n\t\t\t\t\tthis._markInsert( operation.insertionPosition.parent, operation.insertionPosition.offset, 1 );\n\t\t\t\t}\n\n\t\t\t\t// If the split took the element from the graveyard, mark that the element from the graveyard was removed.\n\t\t\t\tif ( operation.graveyardPosition ) {\n\t\t\t\t\tthis._markRemove( operation.graveyardPosition.parent, operation.graveyardPosition.offset, 1 );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'merge': {\n\t\t\t\t// Mark that the merged element was removed.\n\t\t\t\tconst mergedElement = operation.sourcePosition.parent;\n\n\t\t\t\tif ( !this._isInInsertedElement( mergedElement.parent ) ) {\n\t\t\t\t\tthis._markRemove( mergedElement.parent, mergedElement.startOffset, 1 );\n\t\t\t\t}\n\n\t\t\t\t// Mark that the merged element was inserted into graveyard.\n\t\t\t\tconst graveyardParent = operation.graveyardPosition.parent;\n\n\t\t\t\tthis._markInsert( graveyardParent, operation.graveyardPosition.offset, 1 );\n\n\t\t\t\t// Mark that children of merged element were inserted at new parent.\n\t\t\t\tconst mergedIntoElement = operation.targetPosition.parent;\n\n\t\t\t\tif ( !this._isInInsertedElement( mergedIntoElement ) ) {\n\t\t\t\t\tthis._markInsert( mergedIntoElement, operation.targetPosition.offset, mergedElement.maxOffset );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Clear cache after each buffered operation as it is no longer valid.\n\t\tthis._cachedChanges = null;\n\t}\n\n\t/**\n\t * Buffers a marker change.\n\t *\n\t * @param {String} markerName The name of the marker that changed.\n\t * @param {module:engine/model/range~Range|null} oldRange Marker range before the change or `null` if the marker has just\n\t * been created.\n\t * @param {module:engine/model/range~Range|null} newRange Marker range after the change or `null` if the marker was removed.\n\t * @param {Boolean} affectsData Flag indicating whether marker affects the editor data.\n\t */\n\tbufferMarkerChange( markerName, oldRange, newRange, affectsData ) {\n\t\tconst buffered = this._changedMarkers.get( markerName );\n\n\t\tif ( !buffered ) {\n\t\t\tthis._changedMarkers.set( markerName, {\n\t\t\t\toldRange,\n\t\t\t\tnewRange,\n\t\t\t\taffectsData\n\t\t\t} );\n\t\t} else {\n\t\t\tbuffered.newRange = newRange;\n\t\t\tbuffered.affectsData = affectsData;\n\n\t\t\tif ( buffered.oldRange == null && buffered.newRange == null ) {\n\t\t\t\t// The marker is going to be removed (`newRange == null`) but it did not exist before the first buffered change\n\t\t\t\t// (`buffered.oldRange == null`). In this case, do not keep the marker in buffer at all.\n\t\t\t\tthis._changedMarkers.delete( markerName );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns all markers that should be removed as a result of buffered changes.\n\t *\n\t * @returns {Array.<Object>} Markers to remove. Each array item is an object containing the `name` and `range` properties.\n\t */\n\tgetMarkersToRemove() {\n\t\tconst result = [];\n\n\t\tfor ( const [ name, change ] of this._changedMarkers ) {\n\t\t\tif ( change.oldRange != null ) {\n\t\t\t\tresult.push( { name, range: change.oldRange } );\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns all markers which should be added as a result of buffered changes.\n\t *\n\t * @returns {Array.<Object>} Markers to add. Each array item is an object containing the `name` and `range` properties.\n\t */\n\tgetMarkersToAdd() {\n\t\tconst result = [];\n\n\t\tfor ( const [ name, change ] of this._changedMarkers ) {\n\t\t\tif ( change.newRange != null ) {\n\t\t\t\tresult.push( { name, range: change.newRange } );\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns all markers which changed.\n\t *\n\t * @returns {Array.<Object>}\n\t */\n\tgetChangedMarkers() {\n\t\treturn Array.from( this._changedMarkers ).map( item => (\n\t\t\t{\n\t\t\t\tname: item[ 0 ],\n\t\t\t\tdata: {\n\t\t\t\t\toldRange: item[ 1 ].oldRange,\n\t\t\t\t\tnewRange: item[ 1 ].newRange\n\t\t\t\t}\n\t\t\t}\n\t\t) );\n\t}\n\n\t/**\n\t * Checks whether some of the buffered changes affect the editor data.\n\t *\n\t * Types of changes which affect the editor data:\n\t *\n\t * * model structure changes,\n\t * * attribute changes,\n\t * * changes of markers which were defined as `affectingData`.\n\t *\n\t * @returns {Boolean}\n\t */\n\thasDataChanges() {\n\t\tfor ( const [ , change ] of this._changedMarkers ) {\n\t\t\tif ( change.affectsData ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\t// If markers do not affect the data, check whether there are some changes in elements.\n\t\treturn this._changesInElement.size > 0;\n\t}\n\n\t/**\n\t * Calculates the diff between the old model tree state (the state before the first buffered operations since the last {@link #reset}\n\t * call) and the new model tree state (actual one). It should be called after all buffered operations are executed.\n\t *\n\t * The diff set is returned as an array of diff items, each describing a change done on the model. The items are sorted by\n\t * the position on which the change happened. If a position {@link module:engine/model/position~Position#isBefore is before}\n\t * another one, it will be on an earlier index in the diff set.\n\t *\n\t * Because calculating the diff is a costly operation, the result is cached. If no new operation was buffered since the\n\t * previous {@link #getChanges} call, the next call will return the cached value.\n\t *\n\t * @param {Object} options Additional options.\n\t * @param {Boolean} [options.includeChangesInGraveyard=false] If set to `true`, also changes that happened\n\t * in the graveyard root will be returned. By default, changes in the graveyard root are not returned.\n\t * @returns {Array.<Object>} Diff between the old and the new model tree state.\n\t */\n\tgetChanges( options = { includeChangesInGraveyard: false } ) {\n\t\t// If there are cached changes, just return them instead of calculating changes again.\n\t\tif ( this._cachedChanges ) {\n\t\t\tif ( options.includeChangesInGraveyard ) {\n\t\t\t\treturn this._cachedChangesWithGraveyard.slice();\n\t\t\t} else {\n\t\t\t\treturn this._cachedChanges.slice();\n\t\t\t}\n\t\t}\n\n\t\t// Will contain returned results.\n\t\tconst diffSet = [];\n\n\t\t// Check all changed elements.\n\t\tfor ( const element of this._changesInElement.keys() ) {\n\t\t\t// Get changes for this element and sort them.\n\t\t\tconst changes = this._changesInElement.get( element ).sort( ( a, b ) => {\n\t\t\t\tif ( a.offset === b.offset ) {\n\t\t\t\t\tif ( a.type != b.type ) {\n\t\t\t\t\t\t// If there are multiple changes at the same position, \"remove\" change should be first.\n\t\t\t\t\t\t// If the order is different, for example, we would first add some nodes and then removed them\n\t\t\t\t\t\t// (instead of the nodes that we should remove).\n\t\t\t\t\t\treturn a.type == 'remove' ? -1 : 1;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\treturn a.offset < b.offset ? -1 : 1;\n\t\t\t} );\n\n\t\t\t// Get children of this element before any change was applied on it.\n\t\t\tconst snapshotChildren = this._elementSnapshots.get( element );\n\t\t\t// Get snapshot of current element's children.\n\t\t\tconst elementChildren = _getChildrenSnapshot( element.getChildren() );\n\n\t\t\t// Generate actions basing on changes done on element.\n\t\t\tconst actions = _generateActionsFromChanges( snapshotChildren.length, changes );\n\n\t\t\tlet i = 0; // Iterator in `elementChildren` array -- iterates through current children of element.\n\t\t\tlet j = 0; // Iterator in `snapshotChildren` array -- iterates through old children of element.\n\n\t\t\t// Process every action.\n\t\t\tfor ( const action of actions ) {\n\t\t\t\tif ( action === 'i' ) {\n\t\t\t\t\t// Generate diff item for this element and insert it into the diff set.\n\t\t\t\t\tdiffSet.push( this._getInsertDiff( element, i, elementChildren[ i ].name ) );\n\n\t\t\t\t\ti++;\n\t\t\t\t} else if ( action === 'r' ) {\n\t\t\t\t\t// Generate diff item for this element and insert it into the diff set.\n\t\t\t\t\tdiffSet.push( this._getRemoveDiff( element, i, snapshotChildren[ j ].name ) );\n\n\t\t\t\t\tj++;\n\t\t\t\t} else if ( action === 'a' ) {\n\t\t\t\t\t// Take attributes from saved and current children.\n\t\t\t\t\tconst elementAttributes = elementChildren[ i ].attributes;\n\t\t\t\t\tconst snapshotAttributes = snapshotChildren[ j ].attributes;\n\t\t\t\t\tlet range;\n\n\t\t\t\t\tif ( elementChildren[ i ].name == '$text' ) {\n\t\t\t\t\t\trange = new Range( Position._createAt( element, i ), Position._createAt( element, i + 1 ) );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst index = element.offsetToIndex( i );\n\t\t\t\t\t\trange = new Range( Position._createAt( element, i ), Position._createAt( element.getChild( index ), 0 ) );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Generate diff items for this change (there might be multiple attributes changed and\n\t\t\t\t\t// there is a single diff for each of them) and insert them into the diff set.\n\t\t\t\t\tdiffSet.push( ...this._getAttributesDiff( range, snapshotAttributes, elementAttributes ) );\n\n\t\t\t\t\ti++;\n\t\t\t\t\tj++;\n\t\t\t\t} else {\n\t\t\t\t\t// `action` is 'equal'. Child not changed.\n\t\t\t\t\ti++;\n\t\t\t\t\tj++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Then, sort the changes by the position (change at position before other changes is first).\n\t\tdiffSet.sort( ( a, b ) => {\n\t\t\t// If the change is in different root, we don't care much, but we'd like to have all changes in given\n\t\t\t// root \"together\" in the array. So let's just sort them by the root name. It does not matter which root\n\t\t\t// will be processed first.\n\t\t\tif ( a.position.root != b.position.root ) {\n\t\t\t\treturn a.position.root.rootName < b.position.root.rootName ? -1 : 1;\n\t\t\t}\n\n\t\t\t// If change happens at the same position...\n\t\t\tif ( a.position.isEqual( b.position ) ) {\n\t\t\t\t// Keep chronological order of operations.\n\t\t\t\treturn a.changeCount - b.changeCount;\n\t\t\t}\n\n\t\t\t// If positions differ, position \"on the left\" should be earlier in the result.\n\t\t\treturn a.position.isBefore( b.position ) ? -1 : 1;\n\t\t} );\n\n\t\t// Glue together multiple changes (mostly on text nodes).\n\t\tfor ( let i = 1; i < diffSet.length; i++ ) {\n\t\t\tconst prevDiff = diffSet[ i - 1 ];\n\t\t\tconst thisDiff = diffSet[ i ];\n\n\t\t\t// Glue remove changes if they happen on text on same position.\n\t\t\tconst isConsecutiveTextRemove =\n\t\t\t\tprevDiff.type == 'remove' && thisDiff.type == 'remove' &&\n\t\t\t\tprevDiff.name == '$text' && thisDiff.name == '$text' &&\n\t\t\t\tprevDiff.position.isEqual( thisDiff.position );\n\n\t\t\t// Glue insert changes if they happen on text on consecutive fragments.\n\t\t\tconst isConsecutiveTextAdd =\n\t\t\t\tprevDiff.type == 'insert' && thisDiff.type == 'insert' &&\n\t\t\t\tprevDiff.name == '$text' && thisDiff.name == '$text' &&\n\t\t\t\tprevDiff.position.parent == thisDiff.position.parent &&\n\t\t\t\tprevDiff.position.offset + prevDiff.length == thisDiff.position.offset;\n\n\t\t\t// Glue attribute changes if they happen on consecutive fragments and have same key, old value and new value.\n\t\t\tconst isConsecutiveAttributeChange =\n\t\t\t\tprevDiff.type == 'attribute' && thisDiff.type == 'attribute' &&\n\t\t\t\tprevDiff.position.parent == thisDiff.position.parent &&\n\t\t\t\tprevDiff.range.isFlat && thisDiff.range.isFlat &&\n\t\t\t\tprevDiff.position.offset + prevDiff.length == thisDiff.position.offset &&\n\t\t\t\tprevDiff.attributeKey == thisDiff.attributeKey &&\n\t\t\t\tprevDiff.attributeOldValue == thisDiff.attributeOldValue &&\n\t\t\t\tprevDiff.attributeNewValue == thisDiff.attributeNewValue;\n\n\t\t\tif ( isConsecutiveTextRemove || isConsecutiveTextAdd || isConsecutiveAttributeChange ) {\n\t\t\t\tdiffSet[ i - 1 ].length++;\n\n\t\t\t\tif ( isConsecutiveAttributeChange ) {\n\t\t\t\t\tdiffSet[ i - 1 ].range.end = diffSet[ i - 1 ].range.end.getShiftedBy( 1 );\n\t\t\t\t}\n\n\t\t\t\tdiffSet.splice( i, 1 );\n\t\t\t\ti--;\n\t\t\t}\n\t\t}\n\n\t\t// Remove `changeCount` property from diff items. It is used only for sorting and is internal thing.\n\t\tfor ( const item of diffSet ) {\n\t\t\tdelete item.changeCount;\n\n\t\t\tif ( item.type == 'attribute' ) {\n\t\t\t\tdelete item.position;\n\t\t\t\tdelete item.length;\n\t\t\t}\n\t\t}\n\n\t\tthis._changeCount = 0;\n\n\t\t// Cache changes.\n\t\tthis._cachedChangesWithGraveyard = diffSet.slice();\n\t\tthis._cachedChanges = diffSet.slice().filter( _changesInGraveyardFilter );\n\n\t\tif ( options.includeChangesInGraveyard ) {\n\t\t\treturn this._cachedChangesWithGraveyard;\n\t\t} else {\n\t\t\treturn this._cachedChanges;\n\t\t}\n\t}\n\n\t/**\n\t * Resets `Differ`. Removes all buffered changes.\n\t */\n\treset() {\n\t\tthis._changesInElement.clear();\n\t\tthis._elementSnapshots.clear();\n\t\tthis._changedMarkers.clear();\n\t\tthis._cachedChanges = null;\n\t}\n\n\t/**\n\t * Saves and handles an insert change.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} parent\n\t * @param {Number} offset\n\t * @param {Number} howMany\n\t */\n\t_markInsert( parent, offset, howMany ) {\n\t\tconst changeItem = { type: 'insert', offset, howMany, count: this._changeCount++ };\n\n\t\tthis._markChange( parent, changeItem );\n\t}\n\n\t/**\n\t * Saves and handles a remove change.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} parent\n\t * @param {Number} offset\n\t * @param {Number} howMany\n\t */\n\t_markRemove( parent, offset, howMany ) {\n\t\tconst changeItem = { type: 'remove', offset, howMany, count: this._changeCount++ };\n\n\t\tthis._markChange( parent, changeItem );\n\n\t\tthis._removeAllNestedChanges( parent, offset, howMany );\n\t}\n\n\t/**\n\t * Saves and handles an attribute change.\n\t *\n\t * @private\n\t * @param {module:engine/model/item~Item} item\n\t */\n\t_markAttribute( item ) {\n\t\tconst changeItem = { type: 'attribute', offset: item.startOffset, howMany: item.offsetSize, count: this._changeCount++ };\n\n\t\tthis._markChange( item.parent, changeItem );\n\t}\n\n\t/**\n\t * Saves and handles a model change.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} parent\n\t * @param {Object} changeItem\n\t */\n\t_markChange( parent, changeItem ) {\n\t\t// First, make a snapshot of this parent's children (it will be made only if it was not made before).\n\t\tthis._makeSnapshot( parent );\n\n\t\t// Then, get all changes that already were done on the element (empty array if this is the first change).\n\t\tconst changes = this._getChangesForElement( parent );\n\n\t\t// Then, look through all the changes, and transform them or the new change.\n\t\tthis._handleChange( changeItem, changes );\n\n\t\t// Add the new change.\n\t\tchanges.push( changeItem );\n\n\t\t// Remove incorrect changes. During transformation some change might be, for example, included in another.\n\t\t// In that case, the change will have `howMany` property set to `0` or less. We need to remove those changes.\n\t\tfor ( let i = 0; i < changes.length; i++ ) {\n\t\t\tif ( changes[ i ].howMany < 1 ) {\n\t\t\t\tchanges.splice( i, 1 );\n\n\t\t\t\ti--;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Gets an array of changes that have already been saved for a given element.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} element\n\t * @returns {Array.<Object>}\n\t */\n\t_getChangesForElement( element ) {\n\t\tlet changes;\n\n\t\tif ( this._changesInElement.has( element ) ) {\n\t\t\tchanges = this._changesInElement.get( element );\n\t\t} else {\n\t\t\tchanges = [];\n\n\t\t\tthis._changesInElement.set( element, changes );\n\t\t}\n\n\t\treturn changes;\n\t}\n\n\t/**\n\t * Saves a children snapshot for a given element.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} element\n\t */\n\t_makeSnapshot( element ) {\n\t\tif ( !this._elementSnapshots.has( element ) ) {\n\t\t\tthis._elementSnapshots.set( element, _getChildrenSnapshot( element.getChildren() ) );\n\t\t}\n\t}\n\n\t/**\n\t * For a given newly saved change, compares it with a change already done on the element and modifies the incoming\n\t * change and/or the old change.\n\t *\n\t * @private\n\t * @param {Object} inc Incoming (new) change.\n\t * @param {Array.<Object>} changes An array containing all the changes done on that element.\n\t */\n\t_handleChange( inc, changes ) {\n\t\t// We need a helper variable that will store how many nodes are to be still handled for this change item.\n\t\t// `nodesToHandle` (how many nodes still need to be handled) and `howMany` (how many nodes were affected)\n\t\t// needs to be differentiated.\n\t\t//\n\t\t// This comes up when there are multiple changes that are affected by `inc` change item.\n\t\t//\n\t\t// For example: assume two insert changes: `{ offset: 2, howMany: 1 }` and `{ offset: 5, howMany: 1 }`.\n\t\t// Assume that `inc` change is remove `{ offset: 2, howMany: 2, nodesToHandle: 2 }`.\n\t\t//\n\t\t// Then, we:\n\t\t// - \"forget\" about first insert change (it is \"eaten\" by remove),\n\t\t// - because of that, at the end we will want to remove only one node (`nodesToHandle = 1`),\n\t\t// - but still we have to change offset of the second insert change from `5` to `3`!\n\t\t//\n\t\t// So, `howMany` does not change throughout items transformation and keeps information about how many nodes were affected,\n\t\t// while `nodesToHandle` means how many nodes need to be handled after the change item is transformed by other changes.\n\t\tinc.nodesToHandle = inc.howMany;\n\n\t\tfor ( const old of changes ) {\n\t\t\tconst incEnd = inc.offset + inc.howMany;\n\t\t\tconst oldEnd = old.offset + old.howMany;\n\n\t\t\tif ( inc.type == 'insert' ) {\n\t\t\t\tif ( old.type == 'insert' ) {\n\t\t\t\t\tif ( inc.offset <= old.offset ) {\n\t\t\t\t\t\told.offset += inc.howMany;\n\t\t\t\t\t} else if ( inc.offset < oldEnd ) {\n\t\t\t\t\t\told.howMany += inc.nodesToHandle;\n\t\t\t\t\t\tinc.nodesToHandle = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( old.type == 'remove' ) {\n\t\t\t\t\tif ( inc.offset < old.offset ) {\n\t\t\t\t\t\told.offset += inc.howMany;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( old.type == 'attribute' ) {\n\t\t\t\t\tif ( inc.offset <= old.offset ) {\n\t\t\t\t\t\told.offset += inc.howMany;\n\t\t\t\t\t} else if ( inc.offset < oldEnd ) {\n\t\t\t\t\t\t// This case is more complicated, because attribute change has to be split into two.\n\t\t\t\t\t\t// Example (assume that uppercase and lowercase letters mean different attributes):\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// initial state:\t\tabcxyz\n\t\t\t\t\t\t// attribute change:\taBCXYz\n\t\t\t\t\t\t// incoming insert:\t\taBCfooXYz\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// Change ranges cannot intersect because each item has to be described exactly (it was either\n\t\t\t\t\t\t// not changed, inserted, removed, or its attribute was changed). That's why old attribute\n\t\t\t\t\t\t// change has to be split and both parts has to be handled separately from now on.\n\t\t\t\t\t\tconst howMany = old.howMany;\n\n\t\t\t\t\t\told.howMany = inc.offset - old.offset;\n\n\t\t\t\t\t\t// Add the second part of attribute change to the beginning of processed array so it won't\n\t\t\t\t\t\t// be processed again in this loop.\n\t\t\t\t\t\tchanges.unshift( {\n\t\t\t\t\t\t\ttype: 'attribute',\n\t\t\t\t\t\t\toffset: incEnd,\n\t\t\t\t\t\t\thowMany: howMany - old.howMany,\n\t\t\t\t\t\t\tcount: this._changeCount++\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( inc.type == 'remove' ) {\n\t\t\t\tif ( old.type == 'insert' ) {\n\t\t\t\t\tif ( incEnd <= old.offset ) {\n\t\t\t\t\t\told.offset -= inc.howMany;\n\t\t\t\t\t} else if ( incEnd <= oldEnd ) {\n\t\t\t\t\t\tif ( inc.offset < old.offset ) {\n\t\t\t\t\t\t\tconst intersectionLength = incEnd - old.offset;\n\n\t\t\t\t\t\t\told.offset = inc.offset;\n\n\t\t\t\t\t\t\told.howMany -= intersectionLength;\n\t\t\t\t\t\t\tinc.nodesToHandle -= intersectionLength;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\told.howMany -= inc.nodesToHandle;\n\t\t\t\t\t\t\tinc.nodesToHandle = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif ( inc.offset <= old.offset ) {\n\t\t\t\t\t\t\tinc.nodesToHandle -= old.howMany;\n\t\t\t\t\t\t\told.howMany = 0;\n\t\t\t\t\t\t} else if ( inc.offset < oldEnd ) {\n\t\t\t\t\t\t\tconst intersectionLength = oldEnd - inc.offset;\n\n\t\t\t\t\t\t\told.howMany -= intersectionLength;\n\t\t\t\t\t\t\tinc.nodesToHandle -= intersectionLength;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( old.type == 'remove' ) {\n\t\t\t\t\tif ( incEnd <= old.offset ) {\n\t\t\t\t\t\told.offset -= inc.howMany;\n\t\t\t\t\t} else if ( inc.offset < old.offset ) {\n\t\t\t\t\t\tinc.nodesToHandle += old.howMany;\n\t\t\t\t\t\told.howMany = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( old.type == 'attribute' ) {\n\t\t\t\t\tif ( incEnd <= old.offset ) {\n\t\t\t\t\t\told.offset -= inc.howMany;\n\t\t\t\t\t} else if ( inc.offset < old.offset ) {\n\t\t\t\t\t\tconst intersectionLength = incEnd - old.offset;\n\n\t\t\t\t\t\told.offset = inc.offset;\n\t\t\t\t\t\told.howMany -= intersectionLength;\n\t\t\t\t\t} else if ( inc.offset < oldEnd ) {\n\t\t\t\t\t\tif ( incEnd <= oldEnd ) {\n\t\t\t\t\t\t\t// On first sight in this case we don't need to split attribute operation into two.\n\t\t\t\t\t\t\t// However the changes set is later converted to actions (see `_generateActionsFromChanges`).\n\t\t\t\t\t\t\t// For that reason, no two changes may intersect.\n\t\t\t\t\t\t\t// So we cannot have an attribute change that \"contains\" remove change.\n\t\t\t\t\t\t\t// Attribute change needs to be split.\n\t\t\t\t\t\t\tconst howMany = old.howMany;\n\n\t\t\t\t\t\t\told.howMany = inc.offset - old.offset;\n\n\t\t\t\t\t\t\tconst howManyAfter = howMany - old.howMany - inc.nodesToHandle;\n\n\t\t\t\t\t\t\t// Add the second part of attribute change to the beginning of processed array so it won't\n\t\t\t\t\t\t\t// be processed again in this loop.\n\t\t\t\t\t\t\tchanges.unshift( {\n\t\t\t\t\t\t\t\ttype: 'attribute',\n\t\t\t\t\t\t\t\toffset: inc.offset,\n\t\t\t\t\t\t\t\thowMany: howManyAfter,\n\t\t\t\t\t\t\t\tcount: this._changeCount++\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\told.howMany -= oldEnd - inc.offset;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( inc.type == 'attribute' ) {\n\t\t\t\t// In case of attribute change, `howMany` should be kept same as `nodesToHandle`. It's not an error.\n\t\t\t\tif ( old.type == 'insert' ) {\n\t\t\t\t\tif ( inc.offset < old.offset && incEnd > old.offset ) {\n\t\t\t\t\t\tif ( incEnd > oldEnd ) {\n\t\t\t\t\t\t\t// This case is similar to a case described when incoming change was insert and old change was attribute.\n\t\t\t\t\t\t\t// See comment above.\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// This time incoming change is attribute. We need to split incoming change in this case too.\n\t\t\t\t\t\t\t// However this time, the second part of the attribute change needs to be processed further\n\t\t\t\t\t\t\t// because there might be other changes that it collides with.\n\t\t\t\t\t\t\tconst attributePart = {\n\t\t\t\t\t\t\t\ttype: 'attribute',\n\t\t\t\t\t\t\t\toffset: oldEnd,\n\t\t\t\t\t\t\t\thowMany: incEnd - oldEnd,\n\t\t\t\t\t\t\t\tcount: this._changeCount++\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tthis._handleChange( attributePart, changes );\n\n\t\t\t\t\t\t\tchanges.push( attributePart );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tinc.nodesToHandle = old.offset - inc.offset;\n\t\t\t\t\t\tinc.howMany = inc.nodesToHandle;\n\t\t\t\t\t} else if ( inc.offset >= old.offset && inc.offset < oldEnd ) {\n\t\t\t\t\t\tif ( incEnd > oldEnd ) {\n\t\t\t\t\t\t\tinc.nodesToHandle = incEnd - oldEnd;\n\t\t\t\t\t\t\tinc.offset = oldEnd;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tinc.nodesToHandle = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( old.type == 'remove' ) {\n\t\t\t\t\t// This is a case when attribute change \"contains\" remove change.\n\t\t\t\t\t// The attribute change needs to be split into two because changes cannot intersect.\n\t\t\t\t\tif ( inc.offset < old.offset && incEnd > old.offset ) {\n\t\t\t\t\t\tconst attributePart = {\n\t\t\t\t\t\t\ttype: 'attribute',\n\t\t\t\t\t\t\toffset: old.offset,\n\t\t\t\t\t\t\thowMany: incEnd - old.offset,\n\t\t\t\t\t\t\tcount: this._changeCount++\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tthis._handleChange( attributePart, changes );\n\n\t\t\t\t\t\tchanges.push( attributePart );\n\n\t\t\t\t\t\tinc.nodesToHandle = old.offset - inc.offset;\n\t\t\t\t\t\tinc.howMany = inc.nodesToHandle;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( old.type == 'attribute' ) {\n\t\t\t\t\t// There are only two conflicting scenarios possible here:\n\t\t\t\t\tif ( inc.offset >= old.offset && incEnd <= oldEnd ) {\n\t\t\t\t\t\t// `old` change includes `inc` change, or they are the same.\n\t\t\t\t\t\tinc.nodesToHandle = 0;\n\t\t\t\t\t\tinc.howMany = 0;\n\t\t\t\t\t\tinc.offset = 0;\n\t\t\t\t\t} else if ( inc.offset <= old.offset && incEnd >= oldEnd ) {\n\t\t\t\t\t\t// `inc` change includes `old` change.\n\t\t\t\t\t\told.howMany = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tinc.howMany = inc.nodesToHandle;\n\t\tdelete inc.nodesToHandle;\n\t}\n\n\t/**\n\t * Returns an object with a single insert change description.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} parent The element in which the change happened.\n\t * @param {Number} offset The offset at which change happened.\n\t * @param {String} name The name of the removed element or `'$text'` for a character.\n\t * @returns {Object} The diff item.\n\t */\n\t_getInsertDiff( parent, offset, name ) {\n\t\treturn {\n\t\t\ttype: 'insert',\n\t\t\tposition: Position._createAt( parent, offset ),\n\t\t\tname,\n\t\t\tlength: 1,\n\t\t\tchangeCount: this._changeCount++\n\t\t};\n\t}\n\n\t/**\n\t * Returns an object with a single remove change description.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} parent The element in which change happened.\n\t * @param {Number} offset The offset at which change happened.\n\t * @param {String} name The name of the removed element or `'$text'` for a character.\n\t * @returns {Object} The diff item.\n\t */\n\t_getRemoveDiff( parent, offset, name ) {\n\t\treturn {\n\t\t\ttype: 'remove',\n\t\t\tposition: Position._createAt( parent, offset ),\n\t\t\tname,\n\t\t\tlength: 1,\n\t\t\tchangeCount: this._changeCount++\n\t\t};\n\t}\n\n\t/**\n\t * Returns an array of objects where each one is a single attribute change description.\n\t *\n\t * @private\n\t * @param {module:engine/model/range~Range} range The range where the change happened.\n\t * @param {Map} oldAttributes A map, map iterator or compatible object that contains attributes before the change.\n\t * @param {Map} newAttributes A map, map iterator or compatible object that contains attributes after the change.\n\t * @returns {Array.<Object>} An array containing one or more diff items.\n\t */\n\t_getAttributesDiff( range, oldAttributes, newAttributes ) {\n\t\t// Results holder.\n\t\tconst diffs = [];\n\n\t\t// Clone new attributes as we will be performing changes on this object.\n\t\tnewAttributes = new Map( newAttributes );\n\n\t\t// Look through old attributes.\n\t\tfor ( const [ key, oldValue ] of oldAttributes ) {\n\t\t\t// Check what is the new value of the attribute (or if it was removed).\n\t\t\tconst newValue = newAttributes.has( key ) ? newAttributes.get( key ) : null;\n\n\t\t\t// If values are different (or attribute was removed)...\n\t\t\tif ( newValue !== oldValue ) {\n\t\t\t\t// Add diff item.\n\t\t\t\tdiffs.push( {\n\t\t\t\t\ttype: 'attribute',\n\t\t\t\t\tposition: range.start,\n\t\t\t\t\trange: range.clone(),\n\t\t\t\t\tlength: 1,\n\t\t\t\t\tattributeKey: key,\n\t\t\t\t\tattributeOldValue: oldValue,\n\t\t\t\t\tattributeNewValue: newValue,\n\t\t\t\t\tchangeCount: this._changeCount++\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t// Prevent returning two diff items for the same change.\n\t\t\tnewAttributes.delete( key );\n\t\t}\n\n\t\t// Look through new attributes that weren't handled above.\n\t\tfor ( const [ key, newValue ] of newAttributes ) {\n\t\t\t// Each of them is a new attribute. Add diff item.\n\t\t\tdiffs.push( {\n\t\t\t\ttype: 'attribute',\n\t\t\t\tposition: range.start,\n\t\t\t\trange: range.clone(),\n\t\t\t\tlength: 1,\n\t\t\t\tattributeKey: key,\n\t\t\t\tattributeOldValue: null,\n\t\t\t\tattributeNewValue: newValue,\n\t\t\t\tchangeCount: this._changeCount++\n\t\t\t} );\n\t\t}\n\n\t\treturn diffs;\n\t}\n\n\t/**\n\t * Checks whether given element or any of its parents is an element that is buffered as an inserted element.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} element Element to check.\n\t * @returns {Boolean}\n\t */\n\t_isInInsertedElement( element ) {\n\t\tconst parent = element.parent;\n\n\t\tif ( !parent ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst changes = this._changesInElement.get( parent );\n\t\tconst offset = element.startOffset;\n\n\t\tif ( changes ) {\n\t\t\tfor ( const change of changes ) {\n\t\t\t\tif ( change.type == 'insert' && offset >= change.offset && offset < change.offset + change.howMany ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this._isInInsertedElement( parent );\n\t}\n\n\t/**\n\t * Removes deeply all buffered changes that are registered in elements from range specified by `parent`, `offset`\n\t * and `howMany`.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} parent\n\t * @param {Number} offset\n\t * @param {Number} howMany\n\t */\n\t_removeAllNestedChanges( parent, offset, howMany ) {\n\t\tconst range = new Range( Position._createAt( parent, offset ), Position._createAt( parent, offset + howMany ) );\n\n\t\tfor ( const item of range.getItems( { shallow: true } ) ) {\n\t\t\tif ( item.is( 'element' ) ) {\n\t\t\t\tthis._elementSnapshots.delete( item );\n\t\t\t\tthis._changesInElement.delete( item );\n\n\t\t\t\tthis._removeAllNestedChanges( item, 0, item.maxOffset );\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Returns an array that is a copy of passed child list with the exception that text nodes are split to one or more\n// objects, each representing one character and attributes set on that character.\nfunction _getChildrenSnapshot( children ) {\n\tconst snapshot = [];\n\n\tfor ( const child of children ) {\n\t\tif ( child.is( '$text' ) ) {\n\t\t\tfor ( let i = 0; i < child.data.length; i++ ) {\n\t\t\t\tsnapshot.push( {\n\t\t\t\t\tname: '$text',\n\t\t\t\t\tattributes: new Map( child.getAttributes() )\n\t\t\t\t} );\n\t\t\t}\n\t\t} else {\n\t\t\tsnapshot.push( {\n\t\t\t\tname: child.name,\n\t\t\t\tattributes: new Map( child.getAttributes() )\n\t\t\t} );\n\t\t}\n\t}\n\n\treturn snapshot;\n}\n\n// Generates array of actions for given changes set.\n// It simulates what `diff` function does.\n// Generated actions are:\n// - 'e' for 'equal' - when item at that position did not change,\n// - 'i' for 'insert' - when item at that position was inserted,\n// - 'r' for 'remove' - when item at that position was removed,\n// - 'a' for 'attribute' - when item at that position has it attributes changed.\n//\n// Example (assume that uppercase letters have bold attribute, compare with function code):\n//\n// children before:\tfooBAR\n// children after:\tfoxybAR\n//\n// changes: type: remove, offset: 1, howMany: 1\n//\t\t\ttype: insert, offset: 2, howMany: 2\n//\t\t\ttype: attribute, offset: 4, howMany: 1\n//\n// expected actions: equal (f), remove (o), equal (o), insert (x), insert (y), attribute (b), equal (A), equal (R)\n//\n// steps taken by th script:\n//\n// 1. change = \"type: remove, offset: 1, howMany: 1\"; offset = 0; oldChildrenHandled = 0\n//    1.1 between this change and the beginning is one not-changed node, fill with one equal action, one old child has been handled\n//    1.2 this change removes one node, add one remove action\n//    1.3 change last visited `offset` to 1\n//    1.4 since an old child has been removed, one more old child has been handled\n//    1.5 actions at this point are: equal, remove\n//\n// 2. change = \"type: insert, offset: 2, howMany: 2\"; offset = 1; oldChildrenHandled = 2\n//    2.1 between this change and previous change is one not-changed node, add equal action, another one old children has been handled\n//    2.2 this change inserts two nodes, add two insert actions\n//    2.3 change last visited offset to the end of the inserted range, that is 4\n//    2.4 actions at this point are: equal, remove, equal, insert, insert\n//\n// 3. change = \"type: attribute, offset: 4, howMany: 1\"; offset = 4, oldChildrenHandled = 3\n//    3.1 between this change and previous change are no not-changed nodes\n//    3.2 this change changes one node, add one attribute action\n//    3.3 change last visited `offset` to the end of change range, that is 5\n//    3.4 since an old child has been changed, one more old child has been handled\n//    3.5 actions at this point are: equal, remove, equal, insert, insert, attribute\n//\n// 4. after loop oldChildrenHandled = 4, oldChildrenLength = 6 (fooBAR is 6 characters)\n//    4.1 fill up with two equal actions\n//\n// The result actions are: equal, remove, equal, insert, insert, attribute, equal, equal.\nfunction _generateActionsFromChanges( oldChildrenLength, changes ) {\n\tconst actions = [];\n\n\tlet offset = 0;\n\tlet oldChildrenHandled = 0;\n\n\t// Go through all buffered changes.\n\tfor ( const change of changes ) {\n\t\t// First, fill \"holes\" between changes with \"equal\" actions.\n\t\tif ( change.offset > offset ) {\n\t\t\tfor ( let i = 0; i < change.offset - offset; i++ ) {\n\t\t\t\tactions.push( 'e' );\n\t\t\t}\n\n\t\t\toldChildrenHandled += change.offset - offset;\n\t\t}\n\n\t\t// Then, fill up actions accordingly to change type.\n\t\tif ( change.type == 'insert' ) {\n\t\t\tfor ( let i = 0; i < change.howMany; i++ ) {\n\t\t\t\tactions.push( 'i' );\n\t\t\t}\n\n\t\t\t// The last handled offset is after inserted range.\n\t\t\toffset = change.offset + change.howMany;\n\t\t} else if ( change.type == 'remove' ) {\n\t\t\tfor ( let i = 0; i < change.howMany; i++ ) {\n\t\t\t\tactions.push( 'r' );\n\t\t\t}\n\n\t\t\t// The last handled offset is at the position where the nodes were removed.\n\t\t\toffset = change.offset;\n\t\t\t// We removed `howMany` old nodes, update `oldChildrenHandled`.\n\t\t\toldChildrenHandled += change.howMany;\n\t\t} else {\n\t\t\tactions.push( ...'a'.repeat( change.howMany ).split( '' ) );\n\n\t\t\t// The last handled offset is at the position after the changed range.\n\t\t\toffset = change.offset + change.howMany;\n\t\t\t// We changed `howMany` old nodes, update `oldChildrenHandled`.\n\t\t\toldChildrenHandled += change.howMany;\n\t\t}\n\t}\n\n\t// Fill \"equal\" actions at the end of actions set. Use `oldChildrenHandled` to see how many children\n\t// has not been changed / removed at the end of their parent.\n\tif ( oldChildrenHandled < oldChildrenLength ) {\n\t\tfor ( let i = 0; i < oldChildrenLength - oldChildrenHandled - offset; i++ ) {\n\t\t\tactions.push( 'e' );\n\t\t}\n\t}\n\n\treturn actions;\n}\n\n// Filter callback for Array.filter that filters out change entries that are in graveyard.\nfunction _changesInGraveyardFilter( entry ) {\n\tconst posInGy = entry.position && entry.position.root.rootName == '$graveyard';\n\tconst rangeInGy = entry.range && entry.range.root.rootName == '$graveyard';\n\n\treturn !posInGy && !rangeInGy;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/history\n */\n\n/**\n * `History` keeps the track of all the operations applied to the {@link module:engine/model/document~Document document}.\n */\nexport default class History {\n\t/**\n\t * Creates an empty History instance.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Operations added to the history.\n\t\t *\n\t\t * @protected\n\t\t * @member {Array.<module:engine/model/operation/operation~Operation>} module:engine/model/history~History#_operations\n\t\t */\n\t\tthis._operations = [];\n\n\t\t/**\n\t\t * Holds an information which {@link module:engine/model/operation/operation~Operation operation} undoes which\n\t\t * {@link module:engine/model/operation/operation~Operation operation}.\n\t\t *\n\t\t * Keys of the map are \"undoing operations\", that is operations that undone some other operations. For each key, the\n\t\t * value is an operation that has been undone by the \"undoing operation\".\n\t\t *\n\t\t * @private\n\t\t * @member {Map} module:engine/model/history~History#_undoPairs\n\t\t */\n\t\tthis._undoPairs = new Map();\n\n\t\t/**\n\t\t * Holds all undone operations.\n\t\t *\n\t\t * @private\n\t\t * @member {Set.<module:engine/model/operation/operation~Operation>} module:engine/model/history~History#_undoneOperations\n\t\t */\n\t\tthis._undoneOperations = new Set();\n\t}\n\n\t/**\n\t * Adds an operation to the history.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation Operation to add.\n\t */\n\taddOperation( operation ) {\n\t\tif ( this._operations.includes( operation ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._operations.push( operation );\n\t}\n\n\t/**\n\t * Returns operations added to the history.\n\t *\n\t * @param {Number} [from=Number.NEGATIVE_INFINITY] Base version from which operations should be returned (inclusive).\n\t * Defaults to `Number.NEGATIVE_INFINITY`, which means that operations from the first one will be returned.\n\t * @param {Number} [to=Number.POSITIVE_INFINITY] Base version up to which operations should be returned (exclusive).\n\t * Defaults to `Number.POSITIVE_INFINITY` which means that operations up to the last one will be returned.\n\t * @returns {Array.<module:engine/model/operation/operation~Operation>} Operations added to the history.\n\t */\n\tgetOperations( from = Number.NEGATIVE_INFINITY, to = Number.POSITIVE_INFINITY ) {\n\t\tconst operations = [];\n\n\t\tfor ( const operation of this._operations ) {\n\t\t\tif ( operation.baseVersion >= from && operation.baseVersion < to ) {\n\t\t\t\toperations.push( operation );\n\t\t\t}\n\t\t}\n\n\t\treturn operations;\n\t}\n\n\t/**\n\t * Returns operation from the history that bases on given `baseVersion`.\n\t *\n\t * @param {Number} baseVersion Base version of the operation to get.\n\t * @returns {module:engine/model/operation/operation~Operation|undefined} Operation with given base version or `undefined` if\n\t * there is no such operation in history.\n\t */\n\tgetOperation( baseVersion ) {\n\t\tfor ( const operation of this._operations ) {\n\t\t\tif ( operation.baseVersion == baseVersion ) {\n\t\t\t\treturn operation;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Marks in history that one operation is an operation that is undoing the other operation. By marking operation this way,\n\t * history is keeping more context information about operations, which helps in operational transformation.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} undoneOperation Operation which is undone by `undoingOperation`.\n\t * @param {module:engine/model/operation/operation~Operation} undoingOperation Operation which undoes `undoneOperation`.\n\t */\n\tsetOperationAsUndone( undoneOperation, undoingOperation ) {\n\t\tthis._undoPairs.set( undoingOperation, undoneOperation );\n\t\tthis._undoneOperations.add( undoneOperation );\n\t}\n\n\t/**\n\t * Checks whether given `operation` is undoing any other operation.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation Operation to check.\n\t * @returns {Boolean} `true` if given `operation` is undoing any other operation, `false` otherwise.\n\t */\n\tisUndoingOperation( operation ) {\n\t\treturn this._undoPairs.has( operation );\n\t}\n\n\t/**\n\t * Checks whether given `operation` has been undone by any other operation.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation Operation to check.\n\t * @returns {Boolean} `true` if given `operation` has been undone any other operation, `false` otherwise.\n\t */\n\tisUndoneOperation( operation ) {\n\t\treturn this._undoneOperations.has( operation );\n\t}\n\n\t/**\n\t * For given `undoingOperation`, returns the operation which has been undone by it.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} undoingOperation\n\t * @returns {module:engine/model/operation/operation~Operation|undefined} Operation that has been undone by given\n\t * `undoingOperation` or `undefined` if given `undoingOperation` is not undoing any other operation.\n\t */\n\tgetUndoneOperation( undoingOperation ) {\n\t\treturn this._undoPairs.get( undoingOperation );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * Set of utils to handle unicode characters.\n *\n * @module utils/unicode\n */\n\n/**\n * Checks whether given `character` is a combining mark.\n *\n * @param {String} character Character to check.\n * @returns {Boolean}\n */\nexport function isCombiningMark( character ) {\n\t// eslint-disable-next-line no-misleading-character-class\n\treturn !!character && character.length == 1 && /[\\u0300-\\u036f\\u1ab0-\\u1aff\\u1dc0-\\u1dff\\u20d0-\\u20ff\\ufe20-\\ufe2f]/.test( character );\n}\n\n/**\n * Checks whether given `character` is a high half of surrogate pair.\n *\n * Using UTF-16 terminology, a surrogate pair denotes UTF-16 character using two UTF-8 characters. The surrogate pair\n * consist of high surrogate pair character followed by low surrogate pair character.\n *\n * @param {String} character Character to check.\n * @returns {Boolean}\n */\nexport function isHighSurrogateHalf( character ) {\n\treturn !!character && character.length == 1 && /[\\ud800-\\udbff]/.test( character );\n}\n\n/**\n * Checks whether given `character` is a low half of surrogate pair.\n *\n * Using UTF-16 terminology, a surrogate pair denotes UTF-16 character using two UTF-8 characters. The surrogate pair\n * consist of high surrogate pair character followed by low surrogate pair character.\n *\n * @param {String} character Character to check.\n * @returns {Boolean}\n */\nexport function isLowSurrogateHalf( character ) {\n\treturn !!character && character.length == 1 && /[\\udc00-\\udfff]/.test( character );\n}\n\n/**\n * Checks whether given offset in a string is inside a surrogate pair (between two surrogate halves).\n *\n * @param {String} string String to check.\n * @param {Number} offset Offset to check.\n * @returns {Boolean}\n */\nexport function isInsideSurrogatePair( string, offset ) {\n\treturn isHighSurrogateHalf( string.charAt( offset - 1 ) ) && isLowSurrogateHalf( string.charAt( offset ) );\n}\n\n/**\n * Checks whether given offset in a string is between base character and combining mark or between two combining marks.\n *\n * @param {String} string String to check.\n * @param {Number} offset Offset to check.\n * @returns {Boolean}\n */\nexport function isInsideCombinedSymbol( string, offset ) {\n\treturn isCombiningMark( string.charAt( offset ) );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/document\n */\n\nimport Differ from './differ';\nimport RootElement from './rootelement';\nimport History from './history';\nimport DocumentSelection from './documentselection';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport { isInsideSurrogatePair, isInsideCombinedSymbol } from '@ckeditor/ckeditor5-utils/src/unicode';\nimport { clone } from 'lodash-es';\n\n// @if CK_DEBUG_ENGINE // const { logDocument } = require( '../dev-utils/utils' );\n\nconst graveyardName = '$graveyard';\n\n/**\n * Data model's document. It contains the model's structure, its selection and the history of changes.\n *\n * Read more about working with the model in\n * {@glink framework/guides/architecture/editing-engine#model introduction to the the editing engine's architecture}.\n *\n * Usually, the document contains just one {@link module:engine/model/document~Document#roots root element}, so\n * you can retrieve it by just calling {@link module:engine/model/document~Document#getRoot} without specifying its name:\n *\n *\t\tmodel.document.getRoot(); // -> returns the main root\n *\n * However, the document may contain multiple roots – e.g. when the editor has multiple editable areas\n * (e.g. a title and a body of a message).\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class Document {\n\t/**\n\t * Creates an empty document instance with no {@link #roots} (other than\n\t * the {@link #graveyard graveyard root}).\n\t */\n\tconstructor( model ) {\n\t\t/**\n\t\t * The {@link module:engine/model/model~Model model} that the document is a part of.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/model/model~Model}\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * The document version. It starts from `0` and every operation increases the version number. It is used to ensure that\n\t\t * operations are applied on a proper document version.\n\t\t *\n\t\t * If the {@link module:engine/model/operation/operation~Operation#baseVersion base version} does not match the document version,\n\t\t * a {@link module:utils/ckeditorerror~CKEditorError model-document-applyoperation-wrong-version} error is thrown.\n\t\t *\n\t\t * @type {Number}\n\t\t */\n\t\tthis.version = 0;\n\n\t\t/**\n\t\t * The document's history.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/model/history~History}\n\t\t */\n\t\tthis.history = new History( this );\n\n\t\t/**\n\t\t * The selection in this document.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/model/documentselection~DocumentSelection}\n\t\t */\n\t\tthis.selection = new DocumentSelection( this );\n\n\t\t/**\n\t\t * A list of roots that are owned and managed by this document. Use {@link #createRoot} and\n\t\t * {@link #getRoot} to manipulate it.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:utils/collection~Collection}\n\t\t */\n\t\tthis.roots = new Collection( { idProperty: 'rootName' } );\n\n\t\t/**\n\t\t * The model differ object. Its role is to buffer changes done on the model document and then calculate a diff of those changes.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/model/differ~Differ}\n\t\t */\n\t\tthis.differ = new Differ( model.markers );\n\n\t\t/**\n\t\t * Post-fixer callbacks registered to the model document.\n\t\t *\n\t\t * @private\n\t\t * @type {Set.<Function>}\n\t\t */\n\t\tthis._postFixers = new Set();\n\n\t\t/**\n\t\t * A boolean indicates whether the selection has changed until\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._hasSelectionChangedFromTheLastChangeBlock = false;\n\n\t\t// Graveyard tree root. Document always have a graveyard root, which stores removed nodes.\n\t\tthis.createRoot( '$root', graveyardName );\n\n\t\t// First, if the operation is a document operation check if it's base version is correct.\n\t\tthis.listenTo( model, 'applyOperation', ( evt, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\tif ( operation.isDocumentOperation && operation.baseVersion !== this.version ) {\n\t\t\t\t/**\n\t\t\t\t * Only operations with matching versions can be applied.\n\t\t\t\t *\n\t\t\t\t * @error model-document-applyoperation-wrong-version\n\t\t\t\t * @param {module:engine/model/operation/operation~Operation} operation\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'model-document-applyoperation-wrong-version', this, { operation } );\n\t\t\t}\n\t\t}, { priority: 'highest' } );\n\n\t\t// Then, still before an operation is applied on model, buffer the change in differ.\n\t\tthis.listenTo( model, 'applyOperation', ( evt, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\tif ( operation.isDocumentOperation ) {\n\t\t\t\tthis.differ.bufferOperation( operation );\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\n\t\t// After the operation is applied, bump document's version and add the operation to the history.\n\t\tthis.listenTo( model, 'applyOperation', ( evt, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\tif ( operation.isDocumentOperation ) {\n\t\t\t\tthis.version++;\n\t\t\t\tthis.history.addOperation( operation );\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\n\t\t// Listen to selection changes. If selection changed, mark it.\n\t\tthis.listenTo( this.selection, 'change', () => {\n\t\t\tthis._hasSelectionChangedFromTheLastChangeBlock = true;\n\t\t} );\n\n\t\t// Buffer marker changes.\n\t\t// This is not covered in buffering operations because markers may change outside of them (when they\n\t\t// are modified using `model.markers` collection, not through `MarkerOperation`).\n\t\tthis.listenTo( model.markers, 'update', ( evt, marker, oldRange, newRange ) => {\n\t\t\t// Whenever marker is updated, buffer that change.\n\t\t\tthis.differ.bufferMarkerChange( marker.name, oldRange, newRange, marker.affectsData );\n\n\t\t\tif ( oldRange === null ) {\n\t\t\t\t// If this is a new marker, add a listener that will buffer change whenever marker changes.\n\t\t\t\tmarker.on( 'change', ( evt, oldRange ) => {\n\t\t\t\t\tthis.differ.bufferMarkerChange( marker.name, oldRange, marker.getRange(), marker.affectsData );\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * The graveyard tree root. A document always has a graveyard root that stores removed nodes.\n\t *\n\t * @readonly\n\t * @member {module:engine/model/rootelement~RootElement}\n\t */\n\tget graveyard() {\n\t\treturn this.getRoot( graveyardName );\n\t}\n\n\t/**\n\t * Creates a new root.\n\t *\n\t * @param {String} [elementName='$root'] The element name. Defaults to `'$root'` which also has some basic schema defined\n\t * (`$block`s are allowed inside the `$root`). Make sure to define a proper schema if you use a different name.\n\t * @param {String} [rootName='main'] A unique root name.\n\t * @returns {module:engine/model/rootelement~RootElement} The created root.\n\t */\n\tcreateRoot( elementName = '$root', rootName = 'main' ) {\n\t\tif ( this.roots.get( rootName ) ) {\n\t\t\t/**\n\t\t\t * A root with the specified name already exists.\n\t\t\t *\n\t\t\t * @error model-document-createroot-name-exists\n\t\t\t * @param {module:engine/model/document~Document} doc\n\t\t\t * @param {String} name\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-document-createroot-name-exists', this, { name: rootName } );\n\t\t}\n\n\t\tconst root = new RootElement( this, elementName, rootName );\n\t\tthis.roots.add( root );\n\n\t\treturn root;\n\t}\n\n\t/**\n\t * Removes all event listeners set by the document instance.\n\t */\n\tdestroy() {\n\t\tthis.selection.destroy();\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Returns a root by its name.\n\t *\n\t * @param {String} [name='main'] A unique root name.\n\t * @returns {module:engine/model/rootelement~RootElement|null} The root registered under a given name or `null` when\n\t * there is no root with the given name.\n\t */\n\tgetRoot( name = 'main' ) {\n\t\treturn this.roots.get( name );\n\t}\n\n\t/**\n\t * Returns an array with names of all roots (without the {@link #graveyard}) added to the document.\n\t *\n\t * @returns {Array.<String>} Roots names.\n\t */\n\tgetRootNames() {\n\t\treturn Array.from( this.roots, root => root.rootName ).filter( name => name != graveyardName );\n\t}\n\n\t/**\n\t * Used to register a post-fixer callback. A post-fixer mechanism guarantees that the features\n\t * will operate on a correct model state.\n\t *\n\t * An execution of a feature may lead to an incorrect document tree state. The callbacks are used to fix the document tree after\n\t * it has changed. Post-fixers are fired just after all changes from the outermost change block were applied but\n\t * before the {@link module:engine/model/document~Document#event:change change event} is fired. If a post-fixer callback made\n\t * a change, it should return `true`. When this happens, all post-fixers are fired again to check if something else should\n\t * not be fixed in the new document tree state.\n\t *\n\t * As a parameter, a post-fixer callback receives a {@link module:engine/model/writer~Writer writer} instance connected with the\n\t * executed changes block. Thanks to that, all changes done by the callback will be added to the same\n\t * {@link module:engine/model/batch~Batch batch} (and undo step) as the original changes. This makes post-fixer changes transparent\n\t * for the user.\n\t *\n\t * An example of a post-fixer is a callback that checks if all the data were removed from the editor. If so, the\n\t * callback should add an empty paragraph so that the editor is never empty:\n\t *\n\t *\t\tdocument.registerPostFixer( writer => {\n\t *\t\t\tconst changes = document.differ.getChanges();\n\t *\n\t *\t\t\t// Check if the changes lead to an empty root in the editor.\n\t *\t\t\tfor ( const entry of changes ) {\n\t *\t\t\t\tif ( entry.type == 'remove' && entry.position.root.isEmpty ) {\n\t *\t\t\t\t\twriter.insertElement( 'paragraph', entry.position.root, 0 );\n\t *\n\t *\t\t\t\t\t// It is fine to return early, even if multiple roots would need to be fixed.\n\t *\t\t\t\t\t// All post-fixers will be fired again, so if there are more empty roots, those will be fixed, too.\n\t *\t\t\t\t\treturn true;\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * @param {Function} postFixer\n\t */\n\tregisterPostFixer( postFixer ) {\n\t\tthis._postFixers.add( postFixer );\n\t}\n\n\t/**\n\t * A custom `toJSON()` method to solve child-parent circular dependencies.\n\t *\n\t * @returns {Object} A clone of this object with the document property changed to a string.\n\t */\n\ttoJSON() {\n\t\tconst json = clone( this );\n\n\t\t// Due to circular references we need to remove parent reference.\n\t\tjson.selection = '[engine.model.DocumentSelection]';\n\t\tjson.model = '[engine.model.Model]';\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Check if there were any changes done on document, and if so, call post-fixers,\n\t * fire `change` event for features and conversion and then reset the differ.\n\t * Fire `change:data` event when at least one operation or buffered marker changes the data.\n\t *\n\t * @protected\n\t * @fires change\n\t * @fires change:data\n\t * @param {module:engine/model/writer~Writer} writer The writer on which post-fixers will be called.\n\t */\n\t_handleChangeBlock( writer ) {\n\t\tif ( this._hasDocumentChangedFromTheLastChangeBlock() ) {\n\t\t\tthis._callPostFixers( writer );\n\n\t\t\t// Refresh selection attributes according to the final position in the model after the change.\n\t\t\tthis.selection.refresh();\n\n\t\t\tif ( this.differ.hasDataChanges() ) {\n\t\t\t\tthis.fire( 'change:data', writer.batch );\n\t\t\t} else {\n\t\t\t\tthis.fire( 'change', writer.batch );\n\t\t\t}\n\n\t\t\t// Theoretically, it is not necessary to refresh selection after change event because\n\t\t\t// post-fixers are the last who should change the model, but just in case...\n\t\t\tthis.selection.refresh();\n\n\t\t\tthis.differ.reset();\n\t\t}\n\n\t\tthis._hasSelectionChangedFromTheLastChangeBlock = false;\n\t}\n\n\t/**\n\t * Returns whether there is a buffered change or if the selection has changed from the last\n\t * {@link module:engine/model/model~Model#enqueueChange `enqueueChange()` block}\n\t * or {@link module:engine/model/model~Model#change `change()` block}.\n\t *\n\t * @protected\n\t * @returns {Boolean} Returns `true` if document has changed from the last `change()` or `enqueueChange()` block.\n\t */\n\t_hasDocumentChangedFromTheLastChangeBlock() {\n\t\treturn !this.differ.isEmpty || this._hasSelectionChangedFromTheLastChangeBlock;\n\t}\n\n\t/**\n\t * Returns the default root for this document which is either the first root that was added to the document using\n\t * {@link #createRoot} or the {@link #graveyard graveyard root} if no other roots were created.\n\t *\n\t * @protected\n\t * @returns {module:engine/model/rootelement~RootElement} The default root for this document.\n\t */\n\t_getDefaultRoot() {\n\t\tfor ( const root of this.roots ) {\n\t\t\tif ( root !== this.graveyard ) {\n\t\t\t\treturn root;\n\t\t\t}\n\t\t}\n\n\t\treturn this.graveyard;\n\t}\n\n\t/**\n\t * Returns the default range for this selection. The default range is a collapsed range that starts and ends\n\t * at the beginning of this selection's document {@link #_getDefaultRoot default root}.\n\t *\n\t * @protected\n\t * @returns {module:engine/model/range~Range}\n\t */\n\t_getDefaultRange() {\n\t\tconst defaultRoot = this._getDefaultRoot();\n\t\tconst model = this.model;\n\t\tconst schema = model.schema;\n\n\t\t// Find the first position where the selection can be put.\n\t\tconst position = model.createPositionFromPath( defaultRoot, [ 0 ] );\n\t\tconst nearestRange = schema.getNearestSelectionRange( position );\n\n\t\t// If valid selection range is not found - return range collapsed at the beginning of the root.\n\t\treturn nearestRange || model.createRange( position );\n\t}\n\n\t/**\n\t * Checks whether a given {@link module:engine/model/range~Range range} is a valid range for\n\t * the {@link #selection document's selection}.\n\t *\n\t * @private\n\t * @param {module:engine/model/range~Range} range A range to check.\n\t * @returns {Boolean} `true` if `range` is valid, `false` otherwise.\n\t */\n\t_validateSelectionRange( range ) {\n\t\treturn validateTextNodePosition( range.start ) && validateTextNodePosition( range.end );\n\t}\n\n\t/**\n\t * Performs post-fixer loops. Executes post-fixer callbacks as long as none of them has done any changes to the model.\n\t *\n\t * @private\n\t * @param {module:engine/model/writer~Writer} writer The writer on which post-fixer callbacks will be called.\n\t */\n\t_callPostFixers( writer ) {\n\t\tlet wasFixed = false;\n\n\t\tdo {\n\t\t\tfor ( const callback of this._postFixers ) {\n\t\t\t\t// Ensure selection attributes are up to date before each post-fixer.\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-engine/issues/1673.\n\t\t\t\t//\n\t\t\t\t// It might be good to refresh the selection after each operation but at the moment it leads\n\t\t\t\t// to losing attributes for composition or and spell checking\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-typing/issues/188\n\t\t\t\tthis.selection.refresh();\n\n\t\t\t\twasFixed = callback( writer );\n\n\t\t\t\tif ( wasFixed ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} while ( wasFixed );\n\t}\n\n\t/**\n\t * Fired after each {@link module:engine/model/model~Model#enqueueChange `enqueueChange()` block} or the outermost\n\t * {@link module:engine/model/model~Model#change `change()` block} was executed and the document was changed\n\t * during that block's execution.\n\t *\n\t * The changes which this event will cover include:\n\t *\n\t * * document structure changes,\n\t * * selection changes,\n\t * * marker changes.\n\t *\n\t * If you want to be notified about all these changes, then simply listen to this event like this:\n\t *\n\t *\t\tmodel.document.on( 'change', () => {\n\t *\t\t\tconsole.log( 'The document has changed!' );\n\t *\t\t} );\n\t *\n\t * If, however, you only want to be notified about the data changes, then use the\n\t * {@link module:engine/model/document~Document#event:change:data change:data} event,\n\t * which is fired for document structure changes and marker changes (which affects the data).\n\t *\n\t *\t\tmodel.document.on( 'change:data', () => {\n\t *\t\t\tconsole.log( 'The data has changed!' );\n\t *\t\t} );\n\t *\n\t * @event change\n\t * @param {module:engine/model/batch~Batch} batch The batch that was used in the executed changes block.\n\t */\n\n\t/**\n\t * It is a narrower version of the {@link #event:change} event. It is fired for changes which\n\t * affect the editor data. This is:\n\t *\n\t * * document structure changes,\n\t * * marker changes (which affects the data).\n\t *\n\t * If you want to be notified about the data changes, then listen to this event:\n\t *\n\t *\t\tmodel.document.on( 'change:data', () => {\n\t *\t\t\tconsole.log( 'The data has changed!' );\n\t *\t\t} );\n\t *\n\t * If you would like to listen to all document changes, then check out the\n\t * {@link module:engine/model/document~Document#event:change change} event.\n\t *\n\t * @event change:data\n\t * @param {module:engine/model/batch~Batch} batch The batch that was used in the executed changes block.\n\t */\n\n\t// @if CK_DEBUG_ENGINE // log( version = null ) {\n\t// @if CK_DEBUG_ENGINE // \tversion = version === null ? this.version : version;\n\t// @if CK_DEBUG_ENGINE // \tlogDocument( this, version );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\nmix( Document, EmitterMixin );\n\n// Checks whether given range boundary position is valid for document selection, meaning that is not between\n// unicode surrogate pairs or base character and combining marks.\nfunction validateTextNodePosition( rangeBoundary ) {\n\tconst textNode = rangeBoundary.textNode;\n\n\tif ( textNode ) {\n\t\tconst data = textNode.data;\n\t\tconst offset = rangeBoundary.offset - textNode.startOffset;\n\n\t\treturn !isInsideSurrogatePair( data, offset ) && !isInsideCombinedSymbol( data, offset );\n\t}\n\n\treturn true;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/markercollection\n */\n\nimport LiveRange from './liverange';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * The collection of all {@link module:engine/model/markercollection~Marker markers} attached to the document.\n * It lets you {@link module:engine/model/markercollection~MarkerCollection#get get} markers or track them using\n * {@link module:engine/model/markercollection~MarkerCollection#event:update} event.\n *\n * To create, change or remove makers use {@link module:engine/model/writer~Writer model writers'} methods:\n * {@link module:engine/model/writer~Writer#addMarker} or {@link module:engine/model/writer~Writer#removeMarker}. Since\n * the writer is the only proper way to change the data model it is not possible to change markers directly using this\n * collection. All markers created by the writer will be automatically added to this collection.\n *\n * By default there is one marker collection available as {@link module:engine/model/model~Model#markers model property}.\n *\n * @see module:engine/model/markercollection~Marker\n */\nexport default class MarkerCollection {\n\t/**\n\t * Creates a markers collection.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Stores {@link ~Marker markers} added to the collection.\n\t\t *\n\t\t * @private\n\t\t * @member {Map} #_markers\n\t\t */\n\t\tthis._markers = new Map();\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over all {@link ~Marker markers} added to the collection.\n\t *\n\t * @returns {Iterable}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._markers.values();\n\t}\n\n\t/**\n\t * Checks if marker with given `markerName` is in the collection.\n\t *\n\t * @param {String} markerName Marker name.\n\t * @returns {Boolean} `true` if marker with given `markerName` is in the collection, `false` otherwise.\n\t */\n\thas( markerName ) {\n\t\treturn this._markers.has( markerName );\n\t}\n\n\t/**\n\t * Returns {@link ~Marker marker} with given `markerName`.\n\t *\n\t * @param {String} markerName Name of marker to get.\n\t * @returns {module:engine/model/markercollection~Marker|null} Marker with given name or `null` if such marker was\n\t * not added to the collection.\n\t */\n\tget( markerName ) {\n\t\treturn this._markers.get( markerName ) || null;\n\t}\n\n\t/**\n\t * Creates and adds a {@link ~Marker marker} to the `MarkerCollection` with given name on given\n\t * {@link module:engine/model/range~Range range}.\n\t *\n\t * If `MarkerCollection` already had a marker with given name (or {@link ~Marker marker} was passed), the marker in\n\t * collection is updated and {@link module:engine/model/markercollection~MarkerCollection#event:update} event is fired\n\t * but only if there was a change (marker range or {@link module:engine/model/markercollection~Marker#managedUsingOperations}\n\t * flag has changed.\n\t *\n\t * @protected\n\t * @fires module:engine/model/markercollection~MarkerCollection#event:update\n\t * @param {String|module:engine/model/markercollection~Marker} markerOrName Name of marker to set or marker instance to update.\n\t * @param {module:engine/model/range~Range} range Marker range.\n\t * @param {Boolean} [managedUsingOperations=false] Specifies whether the marker is managed using operations.\n\t * @param {Boolean} [affectsData=false] Specifies whether the marker affects the data produced by the data pipeline\n\t * (is persisted in the editor's data).\n\t * @returns {module:engine/model/markercollection~Marker} `Marker` instance which was added or updated.\n\t */\n\t_set( markerOrName, range, managedUsingOperations = false, affectsData = false ) {\n\t\tconst markerName = markerOrName instanceof Marker ? markerOrName.name : markerOrName;\n\n\t\tif ( markerName.includes( ',' ) ) {\n\t\t\t/**\n\t\t\t * Marker name cannot contain the \",\" character.\n\t\t\t *\n\t\t\t * @error markercollection-incorrect-marker-name\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'markercollection-incorrect-marker-name', this );\n\t\t}\n\n\t\tconst oldMarker = this._markers.get( markerName );\n\n\t\tif ( oldMarker ) {\n\t\t\tconst oldRange = oldMarker.getRange();\n\t\t\tlet hasChanged = false;\n\n\t\t\tif ( !oldRange.isEqual( range ) ) {\n\t\t\t\toldMarker._attachLiveRange( LiveRange.fromRange( range ) );\n\t\t\t\thasChanged = true;\n\t\t\t}\n\n\t\t\tif ( managedUsingOperations != oldMarker.managedUsingOperations ) {\n\t\t\t\toldMarker._managedUsingOperations = managedUsingOperations;\n\t\t\t\thasChanged = true;\n\t\t\t}\n\n\t\t\tif ( typeof affectsData === 'boolean' && affectsData != oldMarker.affectsData ) {\n\t\t\t\toldMarker._affectsData = affectsData;\n\t\t\t\thasChanged = true;\n\t\t\t}\n\n\t\t\tif ( hasChanged ) {\n\t\t\t\tthis.fire( 'update:' + markerName, oldMarker, oldRange, range );\n\t\t\t}\n\n\t\t\treturn oldMarker;\n\t\t}\n\n\t\tconst liveRange = LiveRange.fromRange( range );\n\t\tconst marker = new Marker( markerName, liveRange, managedUsingOperations, affectsData );\n\n\t\tthis._markers.set( markerName, marker );\n\t\tthis.fire( 'update:' + markerName, marker, null, range );\n\n\t\treturn marker;\n\t}\n\n\t/**\n\t * Removes given {@link ~Marker marker} or a marker with given name from the `MarkerCollection`.\n\t *\n\t * @protected\n\t * @fires module:engine/model/markercollection~MarkerCollection#event:update\n\t * @param {String} markerOrName Marker or name of a marker to remove.\n\t * @returns {Boolean} `true` if marker was found and removed, `false` otherwise.\n\t */\n\t_remove( markerOrName ) {\n\t\tconst markerName = markerOrName instanceof Marker ? markerOrName.name : markerOrName;\n\t\tconst oldMarker = this._markers.get( markerName );\n\n\t\tif ( oldMarker ) {\n\t\t\tthis._markers.delete( markerName );\n\t\t\tthis.fire( 'update:' + markerName, oldMarker, oldMarker.getRange(), null );\n\n\t\t\tthis._destroyMarker( oldMarker );\n\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Fires an {@link module:engine/model/markercollection~MarkerCollection#event:update} event for the given {@link ~Marker marker}\n\t * but does not change the marker. Useful to force {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher downcast\n\t * conversion} for the marker.\n\t *\n\t * @protected\n\t * @fires module:engine/model/markercollection~MarkerCollection#event:update\n\t * @param {String} markerOrName Marker or name of a marker to refresh.\n\t */\n\t_refresh( markerOrName ) {\n\t\tconst markerName = markerOrName instanceof Marker ? markerOrName.name : markerOrName;\n\t\tconst marker = this._markers.get( markerName );\n\n\t\tif ( !marker ) {\n\t\t\t/**\n\t\t\t * Marker with provided name does not exists.\n\t\t\t *\n\t\t\t * @error markercollection-refresh-marker-not-exists\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'markercollection-refresh-marker-not-exists', this );\n\t\t}\n\n\t\tconst range = marker.getRange();\n\n\t\tthis.fire( 'update:' + markerName, marker, range, range, marker.managedUsingOperations, marker.affectsData );\n\t}\n\n\t/**\n\t * Returns iterator that iterates over all markers, which ranges contain given {@link module:engine/model/position~Position position}.\n\t *\n\t * @param {module:engine/model/position~Position} position\n\t * @returns {Iterable.<module:engine/model/markercollection~Marker>}\n\t */\n\t* getMarkersAtPosition( position ) {\n\t\tfor ( const marker of this ) {\n\t\t\tif ( marker.getRange().containsPosition( position ) ) {\n\t\t\t\tyield marker;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns iterator that iterates over all markers, which intersects with given {@link module:engine/model/range~Range range}.\n\t *\n\t * @param {module:engine/model/range~Range} range\n\t * @returns {Iterable.<module:engine/model/markercollection~Marker>}\n\t */\n\t* getMarkersIntersectingRange( range ) {\n\t\tfor ( const marker of this ) {\n\t\t\tif ( marker.getRange().getIntersection( range ) !== null ) {\n\t\t\t\tyield marker;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Destroys marker collection and all markers inside it.\n\t */\n\tdestroy() {\n\t\tfor ( const marker of this._markers.values() ) {\n\t\t\tthis._destroyMarker( marker );\n\t\t}\n\n\t\tthis._markers = null;\n\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Iterates over all markers that starts with given `prefix`.\n\t *\n\t *\t\tconst markerFooA = markersCollection.set( 'foo:a', rangeFooA );\n\t *\t\tconst markerFooB = markersCollection.set( 'foo:b', rangeFooB );\n\t *\t\tconst markerBarA = markersCollection.set( 'bar:a', rangeBarA );\n\t *\t\tconst markerFooBarA = markersCollection.set( 'foobar:a', rangeFooBarA );\n\t *\t\tArray.from( markersCollection.getMarkersGroup( 'foo' ) ); // [ markerFooA, markerFooB ]\n\t *\t\tArray.from( markersCollection.getMarkersGroup( 'a' ) ); // []\n\t *\n\t * @param prefix\n\t * @returns {Iterable.<module:engine/model/markercollection~Marker>}\n\t */\n\t* getMarkersGroup( prefix ) {\n\t\tfor ( const marker of this._markers.values() ) {\n\t\t\tif ( marker.name.startsWith( prefix + ':' ) ) {\n\t\t\t\tyield marker;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Destroys the marker.\n\t *\n\t * @private\n\t * @param {module:engine/model/markercollection~Marker} marker Marker to destroy.\n\t */\n\t_destroyMarker( marker ) {\n\t\tmarker.stopListening();\n\t\tmarker._detachLiveRange();\n\t}\n\n\t/**\n\t * Fired whenever marker is added, updated or removed from `MarkerCollection`.\n\t *\n\t * @event update\n\t * @param {module:engine/model/markercollection~Marker} marker Updated Marker.\n\t * @param {module:engine/model/range~Range|null} oldRange Marker range before the update. When is not defined it\n\t * means that marker is just added.\n\t * @param {module:engine/model/range~Range|null} newRange Marker range after update. When is not defined it\n\t * means that marker is just removed.\n\t */\n}\n\nmix( MarkerCollection, EmitterMixin );\n\n/**\n * `Marker` is a continuous parts of model (like a range), is named and represent some kind of information about marked\n * part of model document. In contrary to {@link module:engine/model/node~Node nodes}, which are building blocks of\n * model document tree, markers are not stored directly in document tree but in\n * {@link module:engine/model/model~Model#markers model markers' collection}. Still, they are document data, by giving\n * additional meaning to the part of a model document between marker start and marker end.\n *\n * In this sense, markers are similar to adding and converting attributes on nodes. The difference is that attribute is\n * connected with a given node (e.g. a character is bold no matter if it gets moved or content around it changes).\n * Markers on the other hand are continuous ranges and are characterized by their start and end position. This means that\n * any character in the marker is marked by the marker. For example, if a character is moved outside of marker it stops being\n * \"special\" and the marker is shrunk. Similarly, when a character is moved into the marker from other place in document\n * model, it starts being \"special\" and the marker is enlarged.\n *\n * Another upside of markers is that finding marked part of document is fast and easy. Using attributes to mark some nodes\n * and then trying to find that part of document would require traversing whole document tree. Marker gives instant access\n * to the range which it is marking at the moment.\n *\n * Markers are built from a name and a range.\n *\n * Range of the marker is updated automatically when document changes, using\n * {@link module:engine/model/liverange~LiveRange live range} mechanism.\n *\n * Name is used to group and identify markers. Names have to be unique, but markers can be grouped by\n * using common prefixes, separated with `:`, for example: `user:john` or `search:3`. That's useful in term of creating\n * namespaces for custom elements (e.g. comments, highlights). You can use this prefixes in\n * {@link module:engine/model/markercollection~MarkerCollection#event:update} listeners to listen on changes in a group of markers.\n * For instance: `model.markers.on( 'update:user', callback );` will be called whenever any `user:*` markers changes.\n *\n * There are two types of markers.\n *\n * 1. Markers managed directly, without using operations. They are added directly by {@link module:engine/model/writer~Writer}\n * to the {@link module:engine/model/markercollection~MarkerCollection} without any additional mechanism. They can be used\n * as bookmarks or visual markers. They are great for showing results of the find, or select link when the focus is in the input.\n *\n * 1. Markers managed using operations. These markers are also stored in {@link module:engine/model/markercollection~MarkerCollection}\n * but changes in these markers is managed the same way all other changes in the model structure - using operations.\n * Therefore, they are handled in the undo stack and synchronized between clients if the collaboration plugin is enabled.\n * This type of markers is useful for solutions like spell checking or comments.\n *\n * Both type of them should be added / updated by {@link module:engine/model/writer~Writer#addMarker}\n * and removed by {@link module:engine/model/writer~Writer#removeMarker} methods.\n *\n *\t\tmodel.change( ( writer ) => {\n * \t\t\tconst marker = writer.addMarker( name, { range, usingOperation: true } );\n *\n * \t\t\t// ...\n *\n * \t\t\twriter.removeMarker( marker );\n *\t\t} );\n *\n * See {@link module:engine/model/writer~Writer} to find more examples.\n *\n * Since markers need to track change in the document, for efficiency reasons, it is best to create and keep as little\n * markers as possible and remove them as soon as they are not needed anymore.\n *\n * Markers can be downcasted and upcasted.\n *\n * Markers downcast happens on {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker} and\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:removeMarker} events.\n * Use {@link module:engine/conversion/downcasthelpers downcast converters} or attach a custom converter to mentioned events.\n * For {@link module:engine/controller/datacontroller~DataController data pipeline}, marker should be downcasted to an element.\n * Then, it can be upcasted back to a marker. Again, use {@link module:engine/conversion/upcasthelpers upcast converters} or\n * attach a custom converter to {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element}.\n *\n * `Marker` instances are created and destroyed only by {@link ~MarkerCollection MarkerCollection}.\n */\nclass Marker {\n\t/**\n\t * Creates a marker instance.\n\t *\n\t * @param {String} name Marker name.\n\t * @param {module:engine/model/liverange~LiveRange} liveRange Range marked by the marker.\n\t * @param {Boolean} managedUsingOperations Specifies whether the marker is managed using operations.\n\t * @param {Boolean} affectsData Specifies whether the marker affects the data produced by the data pipeline\n\t * (is persisted in the editor's data).\n\t */\n\tconstructor( name, liveRange, managedUsingOperations, affectsData ) {\n\t\t/**\n\t\t * Marker's name.\n\t\t *\n\t\t * @readonly\n\t\t * @type {String}\n\t\t */\n\t\tthis.name = name;\n\n\t\t/**\n\t\t * Range marked by the marker.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:engine/model/liverange~LiveRange}\n\t\t */\n\t\tthis._liveRange = this._attachLiveRange( liveRange );\n\n\t\t/**\n\t\t * Flag indicates if the marker is managed using operations or not.\n\t\t *\n\t\t * @private\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._managedUsingOperations = managedUsingOperations;\n\n\t\t/**\n\t\t * Specifies whether the marker affects the data produced by the data pipeline\n\t\t * (is persisted in the editor's data).\n\t\t *\n\t\t * @private\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._affectsData = affectsData;\n\t}\n\n\t/**\n\t * A value indicating if the marker is managed using operations.\n\t * See {@link ~Marker marker class description} to learn more about marker types.\n\t * See {@link module:engine/model/writer~Writer#addMarker}.\n\t *\n\t * @returns {Boolean}\n\t */\n\tget managedUsingOperations() {\n\t\tif ( !this._liveRange ) {\n\t\t\tthrow new CKEditorError( 'marker-destroyed', this );\n\t\t}\n\n\t\treturn this._managedUsingOperations;\n\t}\n\n\t/**\n\t * A value indicating if the marker changes the data.\n\t *\n\t * @returns {Boolean}\n\t */\n\tget affectsData() {\n\t\tif ( !this._liveRange ) {\n\t\t\tthrow new CKEditorError( 'marker-destroyed', this );\n\t\t}\n\n\t\treturn this._affectsData;\n\t}\n\n\t/**\n\t * Returns current marker start position.\n\t *\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tgetStart() {\n\t\tif ( !this._liveRange ) {\n\t\t\tthrow new CKEditorError( 'marker-destroyed', this );\n\t\t}\n\n\t\treturn this._liveRange.start.clone();\n\t}\n\n\t/**\n\t * Returns current marker end position.\n\t *\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tgetEnd() {\n\t\tif ( !this._liveRange ) {\n\t\t\tthrow new CKEditorError( 'marker-destroyed', this );\n\t\t}\n\n\t\treturn this._liveRange.end.clone();\n\t}\n\n\t/**\n\t * Returns a range that represents the current state of the marker.\n\t *\n\t * Keep in mind that returned value is a {@link module:engine/model/range~Range Range}, not a\n\t * {@link module:engine/model/liverange~LiveRange LiveRange}. This means that it is up-to-date and relevant only\n\t * until next model document change. Do not store values returned by this method. Instead, store {@link ~Marker#name}\n\t * and get `Marker` instance from {@link module:engine/model/markercollection~MarkerCollection MarkerCollection} every\n\t * time there is a need to read marker properties. This will guarantee that the marker has not been removed and\n\t * that it's data is up-to-date.\n\t *\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tgetRange() {\n\t\tif ( !this._liveRange ) {\n\t\t\tthrow new CKEditorError( 'marker-destroyed', this );\n\t\t}\n\n\t\treturn this._liveRange.toRange();\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tmarker.is( 'marker' ); // -> true\n\t *\t\tmarker.is( 'model:marker' ); // -> true\n\t *\n\t *\t\tmarker.is( 'view:element' ); // -> false\n\t *\t\tmarker.is( 'documentSelection' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'marker' || type === 'model:marker';\n\t}\n\n\t/**\n\t * Binds new live range to the marker and detach the old one if is attached.\n\t *\n\t * @protected\n\t * @param {module:engine/model/liverange~LiveRange} liveRange Live range to attach\n\t * @returns {module:engine/model/liverange~LiveRange} Attached live range.\n\t */\n\t_attachLiveRange( liveRange ) {\n\t\tif ( this._liveRange ) {\n\t\t\tthis._detachLiveRange();\n\t\t}\n\n\t\t// Delegating does not work with namespaces. Alternatively, we could delegate all events (using `*`).\n\t\tliveRange.delegate( 'change:range' ).to( this );\n\t\tliveRange.delegate( 'change:content' ).to( this );\n\n\t\tthis._liveRange = liveRange;\n\n\t\treturn liveRange;\n\t}\n\n\t/**\n\t * Unbinds and destroys currently attached live range.\n\t *\n\t * @protected\n\t */\n\t_detachLiveRange() {\n\t\tthis._liveRange.stopDelegating( 'change:range', this );\n\t\tthis._liveRange.stopDelegating( 'change:content', this );\n\t\tthis._liveRange.detach();\n\t\tthis._liveRange = null;\n\t}\n\n\t/**\n\t * Fired whenever {@link ~Marker#_liveRange marker range} is changed due to changes on {@link module:engine/model/document~Document}.\n\t * This is a delegated {@link module:engine/model/liverange~LiveRange#event:change:range LiveRange change:range event}.\n\t *\n\t * When marker is removed from {@link module:engine/model/markercollection~MarkerCollection MarkerCollection},\n\t * all event listeners listening to it should be removed. It is best to do it on\n\t * {@link module:engine/model/markercollection~MarkerCollection#event:update MarkerCollection update event}.\n\t *\n\t * @see module:engine/model/liverange~LiveRange#event:change:range\n\t * @event change:range\n\t * @param {module:engine/model/range~Range} oldRange\n\t * @param {Object} data\n\t */\n\n\t/**\n\t * Fired whenever change on {@link module:engine/model/document~Document} is done inside {@link ~Marker#_liveRange marker range}.\n\t * This is a delegated {@link module:engine/model/liverange~LiveRange#event:change:content LiveRange change:content event}.\n\t *\n\t * When marker is removed from {@link module:engine/model/markercollection~MarkerCollection MarkerCollection},\n\t * all event listeners listening to it should be removed. It is best to do it on\n\t * {@link module:engine/model/markercollection~MarkerCollection#event:update MarkerCollection update event}.\n\t *\n\t * @see module:engine/model/liverange~LiveRange#event:change:content\n\t * @event change:content\n\t * @param {module:engine/model/range~Range} oldRange\n\t * @param {Object} data\n\t */\n}\n\nmix( Marker, EmitterMixin );\n\n/**\n * Cannot use a {@link module:engine/model/markercollection~MarkerCollection#destroy destroyed marker} instance.\n *\n * @error marker-destroyed\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/nooperation\n */\n\nimport Operation from './operation';\n\n/**\n * Operation which is doing nothing (\"empty operation\", \"do-nothing operation\", \"noop\"). This is an operation,\n * which when executed does not change the tree model. It still has some parameters defined for transformation purposes.\n *\n * In most cases this operation is a result of transforming operations. When transformation returns\n * {@link module:engine/model/operation/nooperation~NoOperation} it means that changes done by the transformed operation\n * have already been applied.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class NoOperation extends Operation {\n\tget type() {\n\t\treturn 'noop';\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/nooperation~NoOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new NoOperation( this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/nooperation~NoOperation}\n\t */\n\tgetReversed() {\n\t\treturn new NoOperation( this.baseVersion + 1 );\n\t}\n\n\t_execute() {\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'NoOperation';\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `NoOperation( ${ this.baseVersion } )`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/operationfactory\n */\n\nimport AttributeOperation from '../operation/attributeoperation';\nimport InsertOperation from '../operation/insertoperation';\nimport MarkerOperation from '../operation/markeroperation';\nimport MoveOperation from '../operation/moveoperation';\nimport NoOperation from '../operation/nooperation';\nimport Operation from '../operation/operation';\nimport RenameOperation from '../operation/renameoperation';\nimport RootAttributeOperation from '../operation/rootattributeoperation';\nimport SplitOperation from '../operation/splitoperation';\nimport MergeOperation from '../operation/mergeoperation';\n\nconst operations = {};\noperations[ AttributeOperation.className ] = AttributeOperation;\noperations[ InsertOperation.className ] = InsertOperation;\noperations[ MarkerOperation.className ] = MarkerOperation;\noperations[ MoveOperation.className ] = MoveOperation;\noperations[ NoOperation.className ] = NoOperation;\noperations[ Operation.className ] = Operation;\noperations[ RenameOperation.className ] = RenameOperation;\noperations[ RootAttributeOperation.className ] = RootAttributeOperation;\noperations[ SplitOperation.className ] = SplitOperation;\noperations[ MergeOperation.className ] = MergeOperation;\n\n/**\n * A factory class for creating operations.\n *\n * @abstract\n */\nexport default class OperationFactory {\n\t/**\n\t * Creates an operation instance from a JSON object (parsed JSON string).\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/operation~Operation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\treturn operations[ json.__className ].fromJSON( json, document );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/liveposition\n */\n\nimport Position from './position';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * `LivePosition` is a type of {@link module:engine/model/position~Position Position}\n * that updates itself as {@link module:engine/model/document~Document document}\n * is changed through operations. It may be used as a bookmark.\n *\n * **Note:** Contrary to {@link module:engine/model/position~Position}, `LivePosition` works only in roots that are\n * {@link module:engine/model/rootelement~RootElement}.\n * If {@link module:engine/model/documentfragment~DocumentFragment} is passed, error will be thrown.\n *\n * **Note:** Be very careful when dealing with `LivePosition`. Each `LivePosition` instance bind events that might\n * have to be unbound.\n * Use {@link module:engine/model/liveposition~LivePosition#detach} whenever you don't need `LivePosition` anymore.\n *\n * @extends module:engine/model/position~Position\n */\nexport default class LivePosition extends Position {\n\t/**\n\t * Creates a live position.\n\t *\n\t * @see module:engine/model/position~Position\n\t * @param {module:engine/model/rootelement~RootElement} root\n\t * @param {Array.<Number>} path\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness]\n\t */\n\tconstructor( root, path, stickiness = 'toNone' ) {\n\t\tsuper( root, path, stickiness );\n\n\t\tif ( !this.root.is( 'rootElement' ) ) {\n\t\t\t/**\n\t\t\t * LivePosition's root has to be an instance of RootElement.\n\t\t\t *\n\t\t\t * @error model-liveposition-root-not-rootelement\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-liveposition-root-not-rootelement', root );\n\t\t}\n\n\t\tbindWithDocument.call( this );\n\t}\n\n\t/**\n\t * Unbinds all events previously bound by `LivePosition`. Use it whenever you don't need `LivePosition` instance\n\t * anymore (i.e. when leaving scope in which it was declared or before re-assigning variable that was\n\t * referring to it).\n\t */\n\tdetach() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tlivePosition.is( 'position' ); // -> true\n\t *\t\tlivePosition.is( 'model:position' ); // -> true\n\t *\t\tlivePosition.is( 'liveposition' ); // -> true\n\t *\t\tlivePosition.is( 'model:livePosition' ); // -> true\n\t *\n\t *\t\tlivePosition.is( 'view:position' ); // -> false\n\t *\t\tlivePosition.is( 'documentSelection' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'livePosition' || type === 'model:livePosition' ||\n\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\ttype == 'position' || type === 'model:position';\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/model/position~Position position instance}, which is equal to this live position.\n\t *\n\t * @returns {module:engine/model/position~Position}\n\t */\n\ttoPosition() {\n\t\treturn new Position( this.root, this.path.slice(), this.stickiness );\n\t}\n\n\t/**\n\t * Creates a `LivePosition` instance that is equal to position.\n\t *\n\t * @param {module:engine/model/position~Position} position\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness]\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tstatic fromPosition( position, stickiness ) {\n\t\treturn new this( position.root, position.path.slice(), stickiness ? stickiness : position.stickiness );\n\t}\n\n\t/**\n\t * @static\n\t * @protected\n\t * @method module:engine/model/liveposition~LivePosition._createAfter\n\t * @see module:engine/model/position~Position._createAfter\n\t * @param {module:engine/model/node~Node} node\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone']\n\t * @returns {module:engine/model/liveposition~LivePosition}\n\t */\n\n\t/**\n\t * @static\n\t * @protected\n\t * @method module:engine/model/liveposition~LivePosition._createBefore\n\t * @see module:engine/model/position~Position._createBefore\n\t * @param {module:engine/model/node~Node} node\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone']\n\t * @returns {module:engine/model/liveposition~LivePosition}\n\t */\n\n\t/**\n\t * @static\n\t * @protected\n\t * @method module:engine/model/liveposition~LivePosition._createAt\n\t * @see module:engine/model/position~Position._createAt\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset]\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone']\n\t * @returns {module:engine/model/liveposition~LivePosition}\n\t */\n\n\t/**\n\t * Fired when `LivePosition` instance is changed due to changes on {@link module:engine/model/document~Document}.\n\t *\n\t * @event module:engine/model/liveposition~LivePosition#change\n\t * @param {module:engine/model/position~Position} oldPosition Position equal to this live position before it got changed.\n\t */\n}\n\n// Binds this `LivePosition` to the {@link module:engine/model/document~Document document} that owns\n// this position's {@link module:engine/model/position~Position#root root}.\n//\n// @private\nfunction bindWithDocument() {\n\tthis.listenTo(\n\t\tthis.root.document.model,\n\t\t'applyOperation',\n\t\t( event, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\tif ( !operation.isDocumentOperation ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttransform.call( this, operation );\n\t\t},\n\t\t{ priority: 'low' }\n\t);\n}\n\n// Updates this position accordingly to the updates applied to the model. Bases on change events.\n//\n// @private\n// @param {module:engine/model/operation/operation~Operation} operation Executed operation.\nfunction transform( operation ) {\n\tconst result = this.getTransformedByOperation( operation );\n\n\tif ( !this.isEqual( result ) ) {\n\t\tconst oldPosition = this.toPosition();\n\n\t\tthis.path = result.path;\n\t\tthis.root = result.root;\n\n\t\tthis.fire( 'change', oldPosition );\n\t}\n}\n\nmix( LivePosition, EmitterMixin );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/utils/insertcontent\n */\n\nimport Position from '../position';\nimport LivePosition from '../liveposition';\nimport Element from '../element';\nimport Range from '../range';\nimport DocumentSelection from '../documentselection';\nimport Selection from '../selection';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Inserts content into the editor (specified selection) as one would expect the paste\n * functionality to work.\n *\n * If an instance of {@link module:engine/model/selection~Selection} is passed as `selectable` it will be modified\n * to the insertion selection (equal to a range to be selected after insertion).\n *\n * If `selectable` is not passed, the content will be inserted using the current selection of the model document.\n *\n * **Note:** Use {@link module:engine/model/model~Model#insertContent} instead of this function.\n * This function is only exposed to be reusable in algorithms which change the {@link module:engine/model/model~Model#insertContent}\n * method's behavior.\n *\n * @param {module:engine/model/model~Model} model The model in context of which the insertion\n * should be performed.\n * @param {module:engine/model/documentfragment~DocumentFragment|module:engine/model/item~Item} content The content to insert.\n * @param {module:engine/model/selection~Selectable} [selectable=model.document.selection]\n * Selection into which the content should be inserted.\n * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n * @returns {module:engine/model/range~Range} Range which contains all the performed changes. This is a range that, if removed,\n * would return the model to the state before the insertion. If no changes were preformed by `insertContent`, returns a range collapsed\n * at the insertion position.\n */\nexport default function insertContent( model, content, selectable, placeOrOffset ) {\n\treturn model.change( writer => {\n\t\tlet selection;\n\n\t\tif ( !selectable ) {\n\t\t\tselection = model.document.selection;\n\t\t} else if ( selectable instanceof Selection || selectable instanceof DocumentSelection ) {\n\t\t\tselection = selectable;\n\t\t} else {\n\t\t\tselection = writer.createSelection( selectable, placeOrOffset );\n\t\t}\n\n\t\tif ( !selection.isCollapsed ) {\n\t\t\tmodel.deleteContent( selection, { doNotAutoparagraph: true } );\n\t\t}\n\n\t\tconst insertion = new Insertion( model, writer, selection.anchor );\n\n\t\tlet nodesToInsert;\n\n\t\tif ( content.is( 'documentFragment' ) ) {\n\t\t\tnodesToInsert = content.getChildren();\n\t\t} else {\n\t\t\tnodesToInsert = [ content ];\n\t\t}\n\n\t\tinsertion.handleNodes( nodesToInsert, {\n\t\t\t// The set of children being inserted is the only set in this context\n\t\t\t// so it's the first and last (it's a hack ;)).\n\t\t\tisFirst: true,\n\t\t\tisLast: true\n\t\t} );\n\n\t\tconst newRange = insertion.getSelectionRange();\n\n\t\t/* istanbul ignore else */\n\t\tif ( newRange ) {\n\t\t\tif ( selection instanceof DocumentSelection ) {\n\t\t\t\twriter.setSelection( newRange );\n\t\t\t} else {\n\t\t\t\tselection.setTo( newRange );\n\t\t\t}\n\t\t} else {\n\t\t\t// We are not testing else because it's a safe check for unpredictable edge cases:\n\t\t\t// an insertion without proper range to select.\n\t\t\t//\n\t\t\t// @if CK_DEBUG // console.warn( 'Cannot determine a proper selection range after insertion.' );\n\t\t}\n\n\t\tconst affectedRange = insertion.getAffectedRange() || model.createRange( selection.anchor );\n\n\t\tinsertion.destroy();\n\n\t\treturn affectedRange;\n\t} );\n}\n\n/**\n * Utility class for performing content insertion.\n *\n * @private\n */\nclass Insertion {\n\tconstructor( model, writer, position ) {\n\t\t/**\n\t\t * The model in context of which the insertion should be performed.\n\t\t *\n\t\t * @member {module:engine/model~Model} #model\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * Batch to which operations will be added.\n\t\t *\n\t\t * @member {module:engine/controller/writer~Batch} #writer\n\t\t */\n\t\tthis.writer = writer;\n\n\t\t/**\n\t\t * The position at which (or near which) the next node will be inserted.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} #position\n\t\t */\n\t\tthis.position = position;\n\n\t\t/**\n\t\t * Elements with which the inserted elements can be merged.\n\t\t *\n\t\t *\t\t<p>x^</p><p>y</p> + <p>z</p> (can merge to <p>x</p>)\n\t\t *\t\t<p>x</p><p>^y</p> + <p>z</p> (can merge to <p>y</p>)\n\t\t *\t\t<p>x^y</p> + <p>z</p> (can merge to <p>xy</p> which will be split during the action,\n\t\t *\t\t\t\t\t\t\t\tso both its pieces will be added to this set)\n\t\t *\n\t\t *\n\t\t * @member {Set} #canMergeWith\n\t\t */\n\t\tthis.canMergeWith = new Set( [ this.position.parent ] );\n\n\t\t/**\n\t\t * Schema of the model.\n\t\t *\n\t\t * @member {module:engine/model/schema~Schema} #schema\n\t\t */\n\t\tthis.schema = model.schema;\n\n\t\tthis._filterAttributesOf = [];\n\n\t\t/**\n\t\t * Beginning of the affected range. See {@link module:engine/model/utils/insertcontent~Insertion#getAffectedRange}.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/liveposition~LivePosition|null} #_affectedStart\n\t\t */\n\t\tthis._affectedStart = null;\n\n\t\t/**\n\t\t * End of the affected range. See {@link module:engine/model/utils/insertcontent~Insertion#getAffectedRange}.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/liveposition~LivePosition|null} #_affectedEnd\n\t\t */\n\t\tthis._affectedEnd = null;\n\t}\n\n\t/**\n\t * Handles insertion of a set of nodes.\n\t *\n\t * @param {Iterable.<module:engine/model/node~Node>} nodes Nodes to insert.\n\t * @param {Object} parentContext Context in which parent of these nodes was supposed to be inserted.\n\t * If the parent context is passed it means that the parent element was stripped (was not allowed).\n\t */\n\thandleNodes( nodes, parentContext ) {\n\t\tnodes = Array.from( nodes );\n\n\t\tfor ( let i = 0; i < nodes.length; i++ ) {\n\t\t\tconst node = nodes[ i ];\n\n\t\t\tthis._handleNode( node, {\n\t\t\t\tisFirst: i === 0 && parentContext.isFirst,\n\t\t\t\tisLast: ( i === ( nodes.length - 1 ) ) && parentContext.isLast\n\t\t\t} );\n\t\t}\n\n\t\t// TMP this will become a post-fixer.\n\t\tthis.schema.removeDisallowedAttributes( this._filterAttributesOf, this.writer );\n\t\tthis._filterAttributesOf = [];\n\t}\n\n\t/**\n\t * Returns range to be selected after insertion.\n\t * Returns `null` if there is no valid range to select after insertion.\n\t *\n\t * @returns {module:engine/model/range~Range|null}\n\t */\n\tgetSelectionRange() {\n\t\tif ( this.nodeToSelect ) {\n\t\t\treturn Range._createOn( this.nodeToSelect );\n\t\t}\n\n\t\treturn this.model.schema.getNearestSelectionRange( this.position );\n\t}\n\n\t/**\n\t * Returns a range which contains all the performed changes. This is a range that, if removed, would return the model to the state\n\t * before the insertion. Returns `null` if no changes were done.\n\t *\n\t * @returns {module:engine/model/range~Range|null}\n\t */\n\tgetAffectedRange() {\n\t\tif ( !this._affectedStart ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn new Range( this._affectedStart, this._affectedEnd );\n\t}\n\n\t/**\n\t * Destroys `Insertion` instance.\n\t */\n\tdestroy() {\n\t\tif ( this._affectedStart ) {\n\t\t\tthis._affectedStart.detach();\n\t\t}\n\n\t\tif ( this._affectedEnd ) {\n\t\t\tthis._affectedEnd.detach();\n\t\t}\n\t}\n\n\t/**\n\t * Handles insertion of a single node.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node\n\t * @param {Object} context\n\t * @param {Boolean} context.isFirst Whether the given node is the first one in the content to be inserted.\n\t * @param {Boolean} context.isLast Whether the given node is the last one in the content to be inserted.\n\t */\n\t_handleNode( node, context ) {\n\t\t// Let's handle object in a special way.\n\t\t// * They should never be merged with other elements.\n\t\t// * If they are not allowed in any of the selection ancestors, they could be either autoparagraphed or totally removed.\n\t\tif ( this.schema.isObject( node ) ) {\n\t\t\tthis._handleObject( node, context );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Try to find a place for the given node.\n\t\t// Split the position.parent's branch up to a point where the node can be inserted.\n\t\t// If it isn't allowed in the whole branch, then of course don't split anything.\n\t\tconst isAllowed = this._checkAndSplitToAllowedPosition( node, context );\n\n\t\tif ( !isAllowed ) {\n\t\t\tthis._handleDisallowedNode( node, context );\n\n\t\t\treturn;\n\t\t}\n\n\t\tthis._insert( node );\n\n\t\t// After the node was inserted we may try to merge it with its siblings.\n\t\t// This should happen only if it was the first and/or last of the nodes (so only with boundary nodes)\n\t\t// and only if the selection was in those elements initially.\n\t\t//\n\t\t// E.g.:\n\t\t// <p>x^</p> + <p>y</p> => <p>x</p><p>y</p> => <p>xy[]</p>\n\t\t// and:\n\t\t// <p>x^y</p> + <p>z</p> => <p>x</p>^<p>y</p> + <p>z</p> => <p>x</p><p>z</p><p>y</p> => <p>xz[]y</p>\n\t\t// but:\n\t\t// <p>x</p><p>^</p><p>z</p> + <p>y</p> => <p>x</p><p>y</p><p>z</p> (no merging)\n\t\t// <p>x</p>[<img>]<p>z</p> + <p>y</p> => <p>x</p><p>y</p><p>z</p> (no merging, note: after running deleteContents\n\t\t//\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t it's exactly the same case as above)\n\t\tthis._mergeSiblingsOf( node, context );\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:engine/model/element~Element} node The object element.\n\t * @param {Object} context\n\t */\n\t_handleObject( node, context ) {\n\t\t// Try finding it a place in the tree.\n\t\tif ( this._checkAndSplitToAllowedPosition( node ) ) {\n\t\t\tthis._insert( node );\n\t\t}\n\t\t// Try autoparagraphing.\n\t\telse {\n\t\t\tthis._tryAutoparagraphing( node, context );\n\t\t}\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:engine/model/node~Node} node The disallowed node which needs to be handled.\n\t * @param {Object} context\n\t */\n\t_handleDisallowedNode( node, context ) {\n\t\t// If the node is an element, try inserting its children (strip the parent).\n\t\tif ( node.is( 'element' ) ) {\n\t\t\tthis.handleNodes( node.getChildren(), context );\n\t\t}\n\t\t// If text is not allowed, try autoparagraphing it.\n\t\telse {\n\t\t\tthis._tryAutoparagraphing( node, context );\n\t\t}\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node to insert.\n\t */\n\t_insert( node ) {\n\t\t/* istanbul ignore if */\n\t\tif ( !this.schema.checkChild( this.position, node ) ) {\n\t\t\t// Algorithm's correctness check. We should never end up here but it's good to know that we did.\n\t\t\t// Note that it would often be a silent issue if we insert node in a place where it's not allowed.\n\n\t\t\t/**\n\t\t\t * Given node cannot be inserted on the given position.\n\t\t\t *\n\t\t\t * @error insertcontent-wrong-position\n\t\t\t * @param {module:engine/model/node~Node} node Node to insert.\n\t\t\t * @param {module:engine/model/position~Position} position Position to insert the node at.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'insertcontent-wrong-position',\n\t\t\t\tthis,\n\t\t\t\t{ node, position: this.position }\n\t\t\t);\n\t\t}\n\n\t\tconst livePos = LivePosition.fromPosition( this.position, 'toNext' );\n\n\t\tthis._setAffectedBoundaries( this.position );\n\t\tthis.writer.insert( node, this.position );\n\n\t\tthis.position = livePos.toPosition();\n\t\tlivePos.detach();\n\n\t\t// The last inserted object should be selected because we can't put a collapsed selection after it.\n\t\tif ( this.schema.isObject( node ) && !this.schema.checkChild( this.position, '$text' ) ) {\n\t\t\tthis.nodeToSelect = node;\n\t\t} else {\n\t\t\tthis.nodeToSelect = null;\n\t\t}\n\n\t\tthis._filterAttributesOf.push( node );\n\t}\n\n\t/**\n\t * Sets `_affectedStart` and `_affectedEnd` to the given `position`. Should be used before a change is done during insertion process to\n\t * mark the affected range.\n\t *\n\t * This method is used before inserting a node or splitting a parent node. `_affectedStart` and `_affectedEnd` are also changed\n\t * during merging, but the logic there is more complicated so it is left out of this function.\n\t *\n\t * @private\n\t * @param {module:engine/model/position~Position} position\n\t */\n\t_setAffectedBoundaries( position ) {\n\t\t// Set affected boundaries stickiness so that those position will \"expand\" when something is inserted in between them:\n\t\t// <paragraph>Foo][bar</paragraph> -> <paragraph>Foo]xx[bar</paragraph>\n\t\t// This is why it cannot be a range but two separate positions.\n\t\tif ( !this._affectedStart ) {\n\t\t\tthis._affectedStart = LivePosition.fromPosition( position, 'toPrevious' );\n\t\t}\n\n\t\t// If `_affectedEnd` is before the new boundary position, expand `_affectedEnd`. This can happen if first inserted node was\n\t\t// inserted into the parent but the next node is moved-out of that parent:\n\t\t// (1) <paragraph>Foo][</paragraph> -> <paragraph>Foo]xx[</paragraph>\n\t\t// (2) <paragraph>Foo]xx[</paragraph> -> <paragraph>Foo]xx</paragraph><widget></widget>[\n\t\tif ( !this._affectedEnd || this._affectedEnd.isBefore( position ) ) {\n\t\t\tif ( this._affectedEnd ) {\n\t\t\t\tthis._affectedEnd.detach();\n\t\t\t}\n\n\t\t\tthis._affectedEnd = LivePosition.fromPosition( position, 'toNext' );\n\t\t}\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node which could potentially be merged.\n\t * @param {Object} context\n\t */\n\t_mergeSiblingsOf( node, context ) {\n\t\tif ( !( node instanceof Element ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst mergeLeft = this._canMergeLeft( node, context );\n\t\tconst mergeRight = this._canMergeRight( node, context );\n\t\tconst mergePosLeft = LivePosition._createBefore( node );\n\t\tmergePosLeft.stickiness = 'toNext';\n\t\tconst mergePosRight = LivePosition._createAfter( node );\n\t\tmergePosRight.stickiness = 'toNext';\n\n\t\tif ( mergeLeft ) {\n\t\t\tconst livePosition = LivePosition.fromPosition( this.position );\n\t\t\tlivePosition.stickiness = 'toNext';\n\n\t\t\t// If `_affectedStart` is sames as merge position, it means that the element \"marked\" by `_affectedStart` is going to be\n\t\t\t// removed and its contents will be moved. This won't transform `LivePosition` so `_affectedStart` needs to be moved\n\t\t\t// by hand to properly reflect affected range. (Due to `_affectedStart` and `_affectedEnd` stickiness, the \"range\" is\n\t\t\t// shown as `][`).\n\t\t\t//\n\t\t\t// Example - insert `<paragraph>Abc</paragraph><paragraph>Xyz</paragraph>` at the end of `<paragraph>Foo^</paragraph>`:\n\t\t\t//\n\t\t\t// <paragraph>Foo</paragraph><paragraph>Bar</paragraph>   -->\n\t\t\t// <paragraph>Foo</paragraph>]<paragraph>Abc</paragraph><paragraph>Xyz</paragraph>[<paragraph>Bar</paragraph>   -->\n\t\t\t// <paragraph>Foo]Abc</paragraph><paragraph>Xyz</paragraph>[<paragraph>Bar</paragraph>\n\t\t\t//\n\t\t\t// Note, that if we are here then something must have been inserted, so `_affectedStart` and `_affectedEnd` have to be set.\n\t\t\tif ( this._affectedStart.isEqual( mergePosLeft ) ) {\n\t\t\t\tthis._affectedStart.detach();\n\t\t\t\tthis._affectedStart = LivePosition._createAt( mergePosLeft.nodeBefore, 'end', 'toPrevious' );\n\t\t\t}\n\n\t\t\tthis.writer.merge( mergePosLeft );\n\n\t\t\t// If only one element (the merged one) is in the \"affected range\", also move the affected range end appropriately.\n\t\t\t//\n\t\t\t// Example - insert `<paragraph>Abc</paragraph>` at the of `<paragraph>Foo^</paragraph>`:\n\t\t\t//\n\t\t\t// <paragraph>Foo</paragraph><paragraph>Bar</paragraph>   -->\n\t\t\t// <paragraph>Foo</paragraph>]<paragraph>Abc</paragraph>[<paragraph>Bar</paragraph>   -->\n\t\t\t// <paragraph>Foo]Abc</paragraph>[<paragraph>Bar</paragraph>   -->\n\t\t\t// <paragraph>Foo]Abc[</paragraph><paragraph>Bar</paragraph>\n\t\t\tif ( mergePosLeft.isEqual( this._affectedEnd ) && context.isLast ) {\n\t\t\t\tthis._affectedEnd.detach();\n\t\t\t\tthis._affectedEnd = LivePosition._createAt( mergePosLeft.nodeBefore, 'end', 'toNext' );\n\t\t\t}\n\n\t\t\tthis.position = livePosition.toPosition();\n\t\t\tlivePosition.detach();\n\t\t}\n\n\t\tif ( mergeRight ) {\n\t\t\t/* istanbul ignore if */\n\t\t\tif ( !this.position.isEqual( mergePosRight ) ) {\n\t\t\t\t// Algorithm's correctness check. We should never end up here but it's good to know that we did.\n\t\t\t\t// At this point the insertion position should be after the node we'll merge. If it isn't,\n\t\t\t\t// it should need to be secured as in the left merge case.\n\t\t\t\t/**\n\t\t\t\t * An internal error occurred when merging inserted content with its siblings.\n\t\t\t\t * The insertion position should equal the merge position.\n\t\t\t\t *\n\t\t\t\t * If you encountered this error, report it back to the CKEditor 5 team\n\t\t\t\t * with as many details as possible regarding the content being inserted and the insertion position.\n\t\t\t\t *\n\t\t\t\t * @error insertcontent-invalid-insertion-position\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'insertcontent-invalid-insertion-position', this );\n\t\t\t}\n\n\t\t\t// Move the position to the previous node, so it isn't moved to the graveyard on merge.\n\t\t\t// <p>x</p>[]<p>y</p> => <p>x[]</p><p>y</p>\n\t\t\tthis.position = Position._createAt( mergePosRight.nodeBefore, 'end' );\n\n\t\t\t// OK:  <p>xx[]</p> + <p>yy</p> => <p>xx[]yy</p> (when sticks to previous)\n\t\t\t// NOK: <p>xx[]</p> + <p>yy</p> => <p>xxyy[]</p> (when sticks to next)\n\t\t\tconst livePosition = LivePosition.fromPosition( this.position, 'toPrevious' );\n\n\t\t\t// See comment above on moving `_affectedStart`.\n\t\t\tif ( this._affectedEnd.isEqual( mergePosRight ) ) {\n\t\t\t\tthis._affectedEnd.detach();\n\t\t\t\tthis._affectedEnd = LivePosition._createAt( mergePosRight.nodeBefore, 'end', 'toNext' );\n\t\t\t}\n\n\t\t\tthis.writer.merge( mergePosRight );\n\n\t\t\t// See comment above on moving `_affectedStart`.\n\t\t\tif ( mergePosRight.getShiftedBy( -1 ).isEqual( this._affectedStart ) && context.isFirst ) {\n\t\t\t\tthis._affectedStart.detach();\n\t\t\t\tthis._affectedStart = LivePosition._createAt( mergePosRight.nodeBefore, 0, 'toPrevious' );\n\t\t\t}\n\n\t\t\tthis.position = livePosition.toPosition();\n\t\t\tlivePosition.detach();\n\t\t}\n\n\t\tif ( mergeLeft || mergeRight ) {\n\t\t\t// After merge elements that were marked by _insert() to be filtered might be gone so\n\t\t\t// we need to mark the new container.\n\t\t\tthis._filterAttributesOf.push( this.position.parent );\n\t\t}\n\n\t\tmergePosLeft.detach();\n\t\tmergePosRight.detach();\n\t}\n\n\t/**\n\t * Checks whether specified node can be merged with previous sibling element.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node which could potentially be merged.\n\t * @param {Object} context\n\t * @returns {Boolean}\n\t */\n\t_canMergeLeft( node, context ) {\n\t\tconst previousSibling = node.previousSibling;\n\n\t\treturn context.isFirst &&\n\t\t\t( previousSibling instanceof Element ) &&\n\t\t\tthis.canMergeWith.has( previousSibling ) &&\n\t\t\tthis.model.schema.checkMerge( previousSibling, node );\n\t}\n\n\t/**\n\t * Checks whether specified node can be merged with next sibling element.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node which could potentially be merged.\n\t * @param {Object} context\n\t * @returns {Boolean}\n\t */\n\t_canMergeRight( node, context ) {\n\t\tconst nextSibling = node.nextSibling;\n\n\t\treturn context.isLast &&\n\t\t\t( nextSibling instanceof Element ) &&\n\t\t\tthis.canMergeWith.has( nextSibling ) &&\n\t\t\tthis.model.schema.checkMerge( node, nextSibling );\n\t}\n\n\t/**\n\t * Tries wrapping the node in a new paragraph and inserting it this way.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node which needs to be autoparagraphed.\n\t * @param {Object} context\n\t */\n\t_tryAutoparagraphing( node, context ) {\n\t\tconst paragraph = this.writer.createElement( 'paragraph' );\n\n\t\t// Do not autoparagraph if the paragraph won't be allowed there,\n\t\t// cause that would lead to an infinite loop. The paragraph would be rejected in\n\t\t// the next _handleNode() call and we'd be here again.\n\t\tif ( this._getAllowedIn( paragraph, this.position.parent ) && this.schema.checkChild( paragraph, node ) ) {\n\t\t\tparagraph._appendChild( node );\n\t\t\tthis._handleNode( paragraph, context );\n\t\t}\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:engine/model/node~Node} node\n\t * @returns {Boolean} Whether an allowed position was found.\n\t * `false` is returned if the node isn't allowed at any position up in the tree, `true` if was.\n\t */\n\t_checkAndSplitToAllowedPosition( node ) {\n\t\tconst allowedIn = this._getAllowedIn( node, this.position.parent );\n\n\t\tif ( !allowedIn ) {\n\t\t\treturn false;\n\t\t}\n\n\t\twhile ( allowedIn != this.position.parent ) {\n\t\t\t// If a parent which we'd need to leave is a limit element, break.\n\t\t\tif ( this.schema.isLimit( this.position.parent ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif ( this.position.isAtStart ) {\n\t\t\t\t// If insertion position is at the beginning of the parent, move it out instead of splitting.\n\t\t\t\t// <p>^Foo</p> -> ^<p>Foo</p>\n\t\t\t\tconst parent = this.position.parent;\n\n\t\t\t\tthis.position = this.writer.createPositionBefore( parent );\n\n\t\t\t\t// Special case – parent is empty (<p>^</p>).\n\t\t\t\t//\n\t\t\t\t// 1. parent.isEmpty\n\t\t\t\t// We can remove the element after moving insertion position out of it.\n\t\t\t\t//\n\t\t\t\t// 2. parent.parent === allowedIn\n\t\t\t\t// However parent should remain in place when allowed element is above limit element in document tree.\n\t\t\t\t// For example there shouldn't be allowed to remove empty paragraph from tableCell, when is pasted\n\t\t\t\t// content allowed in $root.\n\t\t\t\tif ( parent.isEmpty && parent.parent === allowedIn ) {\n\t\t\t\t\tthis.writer.remove( parent );\n\t\t\t\t}\n\t\t\t} else if ( this.position.isAtEnd ) {\n\t\t\t\t// If insertion position is at the end of the parent, move it out instead of splitting.\n\t\t\t\t// <p>Foo^</p> -> <p>Foo</p>^\n\t\t\t\tthis.position = this.writer.createPositionAfter( this.position.parent );\n\t\t\t} else {\n\t\t\t\tconst tempPos = this.writer.createPositionAfter( this.position.parent );\n\n\t\t\t\tthis._setAffectedBoundaries( this.position );\n\t\t\t\tthis.writer.split( this.position );\n\n\t\t\t\tthis.position = tempPos;\n\n\t\t\t\tthis.canMergeWith.add( this.position.nodeAfter );\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Gets the element in which the given node is allowed. It checks the passed element and all its ancestors.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node to check.\n\t * @param {module:engine/model/element~Element} element The element in which the node's correctness should be checked.\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\t_getAllowedIn( node, element ) {\n\t\tif ( this.schema.checkChild( element, node ) ) {\n\t\t\treturn element;\n\t\t}\n\n\t\tif ( element.parent ) {\n\t\t\treturn this._getAllowedIn( node, element.parent );\n\t\t}\n\n\t\treturn null;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/utils/deletecontent\n */\n\nimport LivePosition from '../liveposition';\nimport Range from '../range';\nimport DocumentSelection from '../documentselection';\n\n/**\n * Deletes content of the selection and merge siblings. The resulting selection is always collapsed.\n *\n * **Note:** Use {@link module:engine/model/model~Model#deleteContent} instead of this function.\n * This function is only exposed to be reusable in algorithms\n * which change the {@link module:engine/model/model~Model#deleteContent}\n * method's behavior.\n *\n * @param {module:engine/model/model~Model} model The model in context of which the insertion\n * should be performed.\n * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n * Selection of which the content should be deleted.\n * @param {Object} [options]\n * @param {Boolean} [options.leaveUnmerged=false] Whether to merge elements after removing the content of the selection.\n *\n * For example `<heading>x[x</heading><paragraph>y]y</paragraph>` will become:\n *\n * * `<heading>x^y</heading>` with the option disabled (`leaveUnmerged == false`)\n * * `<heading>x^</heading><paragraph>y</paragraph>` with enabled (`leaveUnmerged == true`).\n *\n * Note: {@link module:engine/model/schema~Schema#isObject object} and {@link module:engine/model/schema~Schema#isLimit limit}\n * elements will not be merged.\n *\n * @param {Boolean} [options.doNotResetEntireContent=false] Whether to skip replacing the entire content with a\n * paragraph when the entire content was selected.\n *\n * For example `<heading>[x</heading><paragraph>y]</paragraph>` will become:\n *\n * * `<paragraph>^</paragraph>` with the option disabled (`doNotResetEntireContent == false`)\n * * `<heading>^</heading>` with enabled (`doNotResetEntireContent == true`).\n *\n * @param {Boolean} [options.doNotAutoparagraph=false] Whether to create a paragraph if after content deletion selection is moved\n * to a place where text cannot be inserted.\n *\n * For example `<paragraph>x</paragraph>[<image src=\"foo.jpg\"></image>]` will become:\n *\n * * `<paragraph>x</paragraph><paragraph>[]</paragraph>` with the option disabled (`doNotAutoparagraph == false`)\n * * `<paragraph>x</paragraph>[]` with the option enabled (`doNotAutoparagraph == true`).\n *\n * If you use this option you need to make sure to handle invalid selections yourself or leave\n * them to the selection post-fixer (may not always work).\n *\n * **Note:** if there is no valid position for the selection, the paragraph will always be created:\n *\n * `[<image src=\"foo.jpg\"></image>]` -> `<paragraph>[]</paragraph>`.\n */\nexport default function deleteContent( model, selection, options = {} ) {\n\tif ( selection.isCollapsed ) {\n\t\treturn;\n\t}\n\n\tconst selRange = selection.getFirstRange();\n\n\t// If the selection is already removed, don't do anything.\n\tif ( selRange.root.rootName == '$graveyard' ) {\n\t\treturn;\n\t}\n\n\tconst schema = model.schema;\n\n\tmodel.change( writer => {\n\t\t// 1. Replace the entire content with paragraph.\n\t\t// See: https://github.com/ckeditor/ckeditor5-engine/issues/1012#issuecomment-315017594.\n\t\tif ( !options.doNotResetEntireContent && shouldEntireContentBeReplacedWithParagraph( schema, selection ) ) {\n\t\t\treplaceEntireContentWithParagraph( writer, selection, schema );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Get the live positions for the range adjusted to span only blocks selected from the user perspective.\n\t\tconst [ startPosition, endPosition ] = getLivePositionsForSelectedBlocks( selRange );\n\n\t\t// 2. Remove the content if there is any.\n\t\tif ( !startPosition.isTouching( endPosition ) ) {\n\t\t\twriter.remove( writer.createRange( startPosition, endPosition ) );\n\t\t}\n\n\t\t// 3. Merge elements in the right branch to the elements in the left branch.\n\t\t// The only reasonable (in terms of data and selection correctness) case in which we need to do that is:\n\t\t//\n\t\t// <heading type=1>Fo[</heading><paragraph>]ar</paragraph> => <heading type=1>Fo^ar</heading>\n\t\t//\n\t\t// However, the algorithm supports also merging deeper structures (up to the depth of the shallower branch),\n\t\t// as it's hard to imagine what should actually be the default behavior. Usually, specific features will\n\t\t// want to override that behavior anyway.\n\t\tif ( !options.leaveUnmerged ) {\n\t\t\tmergeBranches( writer, startPosition, endPosition );\n\n\t\t\t// TMP this will be replaced with a postfixer.\n\t\t\t// We need to check and strip disallowed attributes in all nested nodes because after merge\n\t\t\t// some attributes could end up in a path where are disallowed.\n\t\t\t//\n\t\t\t// e.g. bold is disallowed for <H1>\n\t\t\t// <h1>Fo{o</h1><p>b}a<b>r</b><p> -> <h1>Fo{}a<b>r</b><h1> -> <h1>Fo{}ar<h1>.\n\t\t\tschema.removeDisallowedAttributes( startPosition.parent.getChildren(), writer );\n\t\t}\n\n\t\tcollapseSelectionAt( writer, selection, startPosition );\n\n\t\t// 4. Add a paragraph to set selection in it.\n\t\t// Check if a text is allowed in the new container. If not, try to create a new paragraph (if it's allowed here).\n\t\t// If autoparagraphing is off, we assume that you know what you do so we leave the selection wherever it was.\n\t\tif ( !options.doNotAutoparagraph && shouldAutoparagraph( schema, startPosition ) ) {\n\t\t\tinsertParagraph( writer, startPosition, selection );\n\t\t}\n\n\t\tstartPosition.detach();\n\t\tendPosition.detach();\n\t} );\n}\n\n// Returns the live positions for the range adjusted to span only blocks selected from the user perspective. Example:\n//\n//     <heading1>[foo</heading1>\n//     <paragraph>bar</paragraph>\n//     <heading1>]abc</heading1>  <-- this block is not considered as selected\n//\n// This is the same behavior as in Selection#getSelectedBlocks() \"special case\".\nfunction getLivePositionsForSelectedBlocks( range ) {\n\tconst model = range.root.document.model;\n\n\tconst startPosition = range.start;\n\tlet endPosition = range.end;\n\n\t// If the end of selection is at the start position of last block in the selection, then\n\t// shrink it to not include that trailing block. Note that this should happen only for not empty selection.\n\tif ( model.hasContent( range, { ignoreMarkers: true } ) ) {\n\t\tconst endBlock = getParentBlock( endPosition );\n\n\t\tif ( endBlock && endPosition.isTouching( model.createPositionAt( endBlock, 0 ) ) ) {\n\t\t\t// Create forward selection as a probe to find a valid position after excluding last block from the range.\n\t\t\tconst selection = model.createSelection( range );\n\n\t\t\t// Modify the forward selection in backward direction to shrink it and remove first position of following block from it.\n\t\t\t// This is how modifySelection works and here we are making use of it.\n\t\t\tmodel.modifySelection( selection, { direction: 'backward' } );\n\n\t\t\tendPosition = selection.getLastPosition();\n\t\t}\n\t}\n\n\treturn [\n\t\tLivePosition.fromPosition( startPosition, 'toPrevious' ),\n\t\tLivePosition.fromPosition( endPosition, 'toNext' )\n\t];\n}\n\n// Finds the lowest element in position's ancestors which is a block.\n// Returns null if a limit element is encountered before reaching a block element.\nfunction getParentBlock( position ) {\n\tconst element = position.parent;\n\tconst schema = element.root.document.model.schema;\n\tconst ancestors = element.getAncestors( { parentFirst: true, includeSelf: true } );\n\n\tfor ( const element of ancestors ) {\n\t\tif ( schema.isLimit( element ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( schema.isBlock( element ) ) {\n\t\t\treturn element;\n\t\t}\n\t}\n}\n\n// This function is a result of reaching the Ballmer's peak for just the right amount of time.\n// Even I had troubles documenting it after a while and after reading it again I couldn't believe that it really works.\nfunction mergeBranches( writer, startPosition, endPosition ) {\n\tconst model = writer.model;\n\n\t// Verify if there is a need and possibility to merge.\n\tif ( !checkShouldMerge( writer.model.schema, startPosition, endPosition ) ) {\n\t\treturn;\n\t}\n\n\t// If the start element on the common ancestor level is empty, and the end element on the same level is not empty\n\t// then merge those to the right element so that it's properties are preserved (name, attributes).\n\t// Because of OT merging is used instead of removing elements.\n\t//\n\t// Merge left:\n\t//     <heading1>foo[</heading1>    ->  <heading1>foo[]bar</heading1>\n\t//     <paragraph>]bar</paragraph>  ->               --^\n\t//\n\t// Merge right:\n\t//     <heading1>[</heading1>       ->\n\t//     <paragraph>]bar</paragraph>  ->  <paragraph>[]bar</paragraph>\n\t//\n\t// Merge left:\n\t//     <blockQuote>                     ->  <blockQuote>\n\t//         <heading1>foo[</heading1>    ->      <heading1>foo[]bar</heading1>\n\t//         <paragraph>]bar</paragraph>  ->                   --^\n\t//     </blockQuote>                    ->  </blockQuote>\n\t//\n\t// Merge right:\n\t//     <blockQuote>                     ->  <blockQuote>\n\t//         <heading1>[</heading1>       ->\n\t//         <paragraph>]bar</paragraph>  ->      <paragraph>[]bar</paragraph>\n\t//     </blockQuote>                    ->  </blockQuote>\n\n\t// Merging should not go deeper than common ancestor.\n\tconst [ startAncestor, endAncestor ] = getAncestorsJustBelowCommonAncestor( startPosition, endPosition );\n\n\t// Branches can't be merged if one of the positions is directly inside a common ancestor.\n\t//\n\t// Example:\n\t//     <blockQuote>\n\t//         <paragraph>[foo</paragraph>]\n\t//         <table> ... </table>\n\t//     <blockQuote>\n\t//\n\tif ( !startAncestor || !endAncestor ) {\n\t\treturn;\n\t}\n\n\tif ( !model.hasContent( startAncestor, { ignoreMarkers: true } ) && model.hasContent( endAncestor, { ignoreMarkers: true } ) ) {\n\t\tmergeBranchesRight( writer, startPosition, endPosition, startAncestor.parent );\n\t} else {\n\t\tmergeBranchesLeft( writer, startPosition, endPosition, startAncestor.parent );\n\t}\n}\n\n// Merging blocks to the left (properties of the left block are preserved).\n// Simple example:\n//     <heading1>foo[</heading1>    ->  <heading1>foo[bar</heading1>]\n//     <paragraph>]bar</paragraph>  ->              --^\n//\n// Nested example:\n//     <blockQuote>                     ->  <blockQuote>\n//         <heading1>foo[</heading1>    ->      <heading1>foo[bar</heading1>\n//     </blockQuote>                    ->  </blockQuote>]    ^\n//     <blockBlock>                     ->                    |\n//         <paragraph>]bar</paragraph>  ->                 ---\n//     </blockBlock>                    ->\n//\nfunction mergeBranchesLeft( writer, startPosition, endPosition, commonAncestor ) {\n\tconst startElement = startPosition.parent;\n\tconst endElement = endPosition.parent;\n\n\t// Merging reached the common ancestor element, stop here.\n\tif ( startElement == commonAncestor || endElement == commonAncestor ) {\n\t\treturn;\n\t}\n\n\t// Remember next positions to merge in next recursive step (also used as modification points pointers).\n\tstartPosition = writer.createPositionAfter( startElement );\n\tendPosition = writer.createPositionBefore( endElement );\n\n\t// Move endElement just after startElement if they aren't siblings.\n\tif ( !endPosition.isEqual( startPosition ) ) {\n\t\t//\n\t\t//     <blockQuote>                     ->  <blockQuote>\n\t\t//         <heading1>foo[</heading1>    ->      <heading1>foo</heading1>[<paragraph>bar</paragraph>\n\t\t//     </blockQuote>                    ->  </blockQuote>                ^\n\t\t//     <blockBlock>                     ->  <blockBlock>                 |\n\t\t//         <paragraph>]bar</paragraph>  ->      ]                     ---\n\t\t//     </blockBlock>                    ->  </blockBlock>\n\t\t//\n\t\twriter.insert( endElement, startPosition );\n\t}\n\n\t// Merge two siblings (nodes on sides of startPosition):\n\t//\n\t//     <blockQuote>                                             ->  <blockQuote>\n\t//         <heading1>foo</heading1>[<paragraph>bar</paragraph>  ->      <heading1>foo[bar</heading1>\n\t//     </blockQuote>                                            ->  </blockQuote>\n\t//     <blockBlock>                                             ->  <blockBlock>\n\t//         ]                                                    ->      ]\n\t//     </blockBlock>                                            ->  </blockBlock>\n\t//\n\t// Or in simple case (without moving elements in above if):\n\t//     <heading1>foo</heading1>[<paragraph>bar</paragraph>]  ->  <heading1>foo[bar</heading1>]\n\t//\n\twriter.merge( startPosition );\n\n\t// Remove empty end ancestors:\n\t//\n\t//     <blockQuote>                      ->  <blockQuote>\n\t//         <heading1>foo[bar</heading1>  ->      <heading1>foo[bar</heading1>\n\t//     </blockQuote>                     ->  </blockQuote>\n\t//     <blockBlock>                      ->\n\t//         ]                             ->  ]\n\t//     </blockBlock>                     ->\n\t//\n\twhile ( endPosition.parent.isEmpty ) {\n\t\tconst parentToRemove = endPosition.parent;\n\n\t\tendPosition = writer.createPositionBefore( parentToRemove );\n\n\t\twriter.remove( parentToRemove );\n\t}\n\n\t// Verify if there is a need and possibility to merge next level.\n\tif ( !checkShouldMerge( writer.model.schema, startPosition, endPosition ) ) {\n\t\treturn;\n\t}\n\n\t// Continue merging next level (blockQuote with blockBlock in the examples above if it would not be empty and got removed).\n\tmergeBranchesLeft( writer, startPosition, endPosition, commonAncestor );\n}\n\n// Merging blocks to the right (properties of the right block are preserved).\n// Simple example:\n//     <heading1>foo[</heading1>    ->            --v\n//     <paragraph>]bar</paragraph>  ->  [<paragraph>foo]bar</paragraph>\n//\n// Nested example:\n//     <blockQuote>                     ->\n//         <heading1>foo[</heading1>    ->              ---\n//     </blockQuote>                    ->                 |\n//     <blockBlock>                     ->  [<blockBlock>  v\n//         <paragraph>]bar</paragraph>  ->      <paragraph>foo]bar</paragraph>\n//     </blockBlock>                    ->  </blockBlock>\n//\nfunction mergeBranchesRight( writer, startPosition, endPosition, commonAncestor ) {\n\tconst startElement = startPosition.parent;\n\tconst endElement = endPosition.parent;\n\n\t// Merging reached the common ancestor element, stop here.\n\tif ( startElement == commonAncestor || endElement == commonAncestor ) {\n\t\treturn;\n\t}\n\n\t// Remember next positions to merge in next recursive step (also used as modification points pointers).\n\tstartPosition = writer.createPositionAfter( startElement );\n\tendPosition = writer.createPositionBefore( endElement );\n\n\t// Move startElement just before endElement if they aren't siblings.\n\tif ( !endPosition.isEqual( startPosition ) ) {\n\t\t//\n\t\t//     <blockQuote>                     ->  <blockQuote>\n\t\t//         <heading1>foo[</heading1>    ->      [                   ---\n\t\t//     </blockQuote>                    ->  </blockQuote>              |\n\t\t//     <blockBlock>                     ->  <blockBlock>               v\n\t\t//         <paragraph>]bar</paragraph>  ->      <heading1>foo</heading1>]<paragraph>bar</paragraph>\n\t\t//     </blockBlock>                    ->  </blockBlock>\n\t\t//\n\t\twriter.insert( startElement, endPosition );\n\t}\n\n\t// Remove empty end ancestors:\n\t//\n\t//     <blockQuote>                                             ->\n\t//         [                                                    ->  [\n\t//     </blockQuote>                                            ->\n\t//     <blockBlock>                                             ->  <blockBlock>\n\t//         <heading1>foo</heading1>]<paragraph>bar</paragraph>  ->      <heading1>foo</heading1>]<paragraph>bar</paragraph>\n\t//     </blockBlock>                                            ->  </blockBlock>\n\t//\n\twhile ( startPosition.parent.isEmpty ) {\n\t\tconst parentToRemove = startPosition.parent;\n\n\t\tstartPosition = writer.createPositionBefore( parentToRemove );\n\n\t\twriter.remove( parentToRemove );\n\t}\n\n\t// Update endPosition after inserting and removing elements.\n\tendPosition = writer.createPositionBefore( endElement );\n\n\t// Merge right two siblings (nodes on sides of endPosition):\n\t//                                                              ->\n\t//     [                                                        ->  [\n\t//                                                              ->\n\t//     <blockBlock>                                             ->  <blockBlock>\n\t//         <heading1>foo</heading1>]<paragraph>bar</paragraph>  ->      <paragraph>foo]bar</paragraph>\n\t//     </blockBlock>                                            ->  </blockBlock>\n\t//\n\t// Or in simple case (without moving elements in above if):\n\t//     [<heading1>foo</heading1>]<paragraph>bar</paragraph>  ->  [<heading1>foo]bar</heading1>\n\t//\n\tmergeRight( writer, endPosition );\n\n\t// Verify if there is a need and possibility to merge next level.\n\tif ( !checkShouldMerge( writer.model.schema, startPosition, endPosition ) ) {\n\t\treturn;\n\t}\n\n\t// Continue merging next level (blockQuote with blockBlock in the examples above if it would not be empty and got removed).\n\tmergeBranchesRight( writer, startPosition, endPosition, commonAncestor );\n}\n\n// There is no right merge operation so we need to simulate it.\nfunction mergeRight( writer, position ) {\n\tconst startElement = position.nodeBefore;\n\tconst endElement = position.nodeAfter;\n\n\tif ( startElement.name != endElement.name ) {\n\t\twriter.rename( startElement, endElement.name );\n\t}\n\n\twriter.clearAttributes( startElement );\n\twriter.setAttributes( Object.fromEntries( endElement.getAttributes() ), startElement );\n\n\twriter.merge( position );\n}\n\n// Verifies if merging is needed and possible. It's not needed if both positions are in the same element\n// and it's not possible if some element is a limit or the range crosses a limit element.\nfunction checkShouldMerge( schema, startPosition, endPosition ) {\n\tconst startElement = startPosition.parent;\n\tconst endElement = endPosition.parent;\n\n\t// If both positions ended up in the same parent, then there's nothing more to merge:\n\t// <$root><p>x[</p><p>]y</p></$root> => <$root><p>xy</p>[]</$root>\n\tif ( startElement == endElement ) {\n\t\treturn false;\n\t}\n\n\t// If one of the positions is a limit element, then there's nothing to merge because we don't want to cross the limit boundaries.\n\tif ( schema.isLimit( startElement ) || schema.isLimit( endElement ) ) {\n\t\treturn false;\n\t}\n\n\t// Check if operations we'll need to do won't need to cross object or limit boundaries.\n\t// E.g., we can't merge endElement into startElement in this case:\n\t// <limit><startElement>x[</startElement></limit><endElement>]</endElement>\n\treturn isCrossingLimitElement( startPosition, endPosition, schema );\n}\n\n// Returns the elements that are the ancestors of the provided positions that are direct children of the common ancestor.\nfunction getAncestorsJustBelowCommonAncestor( positionA, positionB ) {\n\tconst ancestorsA = positionA.getAncestors();\n\tconst ancestorsB = positionB.getAncestors();\n\n\tlet i = 0;\n\n\twhile ( ancestorsA[ i ] && ancestorsA[ i ] == ancestorsB[ i ] ) {\n\t\ti++;\n\t}\n\n\treturn [ ancestorsA[ i ], ancestorsB[ i ] ];\n}\n\nfunction shouldAutoparagraph( schema, position ) {\n\tconst isTextAllowed = schema.checkChild( position, '$text' );\n\tconst isParagraphAllowed = schema.checkChild( position, 'paragraph' );\n\n\treturn !isTextAllowed && isParagraphAllowed;\n}\n\n// Check if parents of two positions can be merged by checking if there are no limit/object\n// boundaries between those two positions.\n//\n// E.g. in <bQ><p>x[]</p></bQ><widget><caption>{}</caption></widget>\n// we'll check <p>, <bQ>, <widget> and <caption>.\n// Usually, widget and caption are marked as objects/limits in the schema, so in this case merging will be blocked.\nfunction isCrossingLimitElement( leftPos, rightPos, schema ) {\n\tconst rangeToCheck = new Range( leftPos, rightPos );\n\n\tfor ( const value of rangeToCheck.getWalker() ) {\n\t\tif ( schema.isLimit( value.item ) ) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\nfunction insertParagraph( writer, position, selection ) {\n\tconst paragraph = writer.createElement( 'paragraph' );\n\n\twriter.insert( paragraph, position );\n\n\tcollapseSelectionAt( writer, selection, writer.createPositionAt( paragraph, 0 ) );\n}\n\nfunction replaceEntireContentWithParagraph( writer, selection ) {\n\tconst limitElement = writer.model.schema.getLimitElement( selection );\n\n\twriter.remove( writer.createRangeIn( limitElement ) );\n\tinsertParagraph( writer, writer.createPositionAt( limitElement, 0 ), selection );\n}\n\n// We want to replace the entire content with a paragraph when:\n// * the entire content is selected,\n// * selection contains at least two elements,\n// * whether the paragraph is allowed in schema in the common ancestor.\nfunction shouldEntireContentBeReplacedWithParagraph( schema, selection ) {\n\tconst limitElement = schema.getLimitElement( selection );\n\n\tif ( !selection.containsEntireContent( limitElement ) ) {\n\t\treturn false;\n\t}\n\n\tconst range = selection.getFirstRange();\n\n\tif ( range.start.parent == range.end.parent ) {\n\t\treturn false;\n\t}\n\n\treturn schema.checkChild( limitElement, 'paragraph' );\n}\n\n// Helper function that sets the selection. Depending whether given `selection` is a document selection or not,\n// uses a different method to set it.\nfunction collapseSelectionAt( writer, selection, positionOrRange ) {\n\tif ( selection instanceof DocumentSelection ) {\n\t\twriter.setSelection( positionOrRange );\n\t} else {\n\t\tselection.setTo( positionOrRange );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/utils/modifyselection\n */\n\nimport Position from '../position';\nimport TreeWalker from '../treewalker';\nimport Range from '../range';\nimport { isInsideSurrogatePair, isInsideCombinedSymbol } from '@ckeditor/ckeditor5-utils/src/unicode';\nimport DocumentSelection from '../documentselection';\n\nconst wordBoundaryCharacters = ' ,.?!:;\"-()';\n\n/**\n * Modifies the selection. Currently, the supported modifications are:\n *\n * * Extending. The selection focus is moved in the specified `options.direction` with a step specified in `options.unit`.\n * Possible values for `unit` are:\n *  * `'character'` (default) - moves selection by one user-perceived character. In most cases this means moving by one\n *  character in `String` sense. However, unicode also defines \"combing marks\". These are special symbols, that combines\n *  with a symbol before it (\"base character\") to create one user-perceived character. For example, `q̣̇` is a normal\n *  letter `q` with two \"combining marks\": upper dot (`Ux0307`) and lower dot (`Ux0323`). For most actions, i.e. extending\n *  selection by one position, it is correct to include both \"base character\" and all of it's \"combining marks\". That is\n *  why `'character'` value is most natural and common method of modifying selection.\n *  * `'codePoint'` - moves selection by one unicode code point. In contrary to, `'character'` unit, this will insert\n *  selection between \"base character\" and \"combining mark\", because \"combining marks\" have their own unicode code points.\n *  However, for technical reasons, unicode code points with values above `UxFFFF` are represented in native `String` by\n *  two characters, called \"surrogate pairs\". Halves of \"surrogate pairs\" have a meaning only when placed next to each other.\n *  For example `𨭎` is represented in `String` by `\\uD862\\uDF4E`. Both `\\uD862` and `\\uDF4E` do not have any meaning\n *  outside the pair (are rendered as ? when alone). Position between them would be incorrect. In this case, selection\n *  extension will include whole \"surrogate pair\".\n *  * `'word'` - moves selection by a whole word.\n *\n * **Note:** if you extend a forward selection in a backward direction you will in fact shrink it.\n *\n * **Note:** Use {@link module:engine/model/model~Model#modifySelection} instead of this function.\n * This function is only exposed to be reusable in algorithms\n * which change the {@link module:engine/model/model~Model#modifySelection}\n * method's behavior.\n *\n * @param {module:engine/model/model~Model} model The model in context of which\n * the selection modification should be performed.\n * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n * The selection to modify.\n * @param {Object} [options]\n * @param {'forward'|'backward'} [options.direction='forward'] The direction in which the selection should be modified.\n * @param {'character'|'codePoint'|'word'} [options.unit='character'] The unit by which selection should be modified.\n */\nexport default function modifySelection( model, selection, options = {} ) {\n\tconst schema = model.schema;\n\tconst isForward = options.direction != 'backward';\n\tconst unit = options.unit ? options.unit : 'character';\n\n\tconst focus = selection.focus;\n\n\tconst walker = new TreeWalker( {\n\t\tboundaries: getSearchRange( focus, isForward ),\n\t\tsingleCharacters: true,\n\t\tdirection: isForward ? 'forward' : 'backward'\n\t} );\n\n\tconst data = { walker, schema, isForward, unit };\n\n\tlet next;\n\n\twhile ( ( next = walker.next() ) ) {\n\t\tif ( next.done ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst position = tryExtendingTo( data, next.value );\n\n\t\tif ( position ) {\n\t\t\tif ( selection instanceof DocumentSelection ) {\n\t\t\t\tmodel.change( writer => {\n\t\t\t\t\twriter.setSelectionFocus( position );\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\tselection.setFocus( position );\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n// Checks whether the selection can be extended to the the walker's next value (next position).\n// @param {{ walker, unit, isForward, schema }} data\n// @param {module:engine/view/treewalker~TreeWalkerValue} value\nfunction tryExtendingTo( data, value ) {\n\tconst { isForward, walker, unit, schema } = data;\n\tconst { type, item, nextPosition } = value;\n\n\t// If found text, we can certainly put the focus in it. Let's just find a correct position\n\t// based on the unit.\n\tif ( type == 'text' ) {\n\t\tif ( data.unit === 'word' ) {\n\t\t\treturn getCorrectWordBreakPosition( walker, isForward );\n\t\t}\n\n\t\treturn getCorrectPosition( walker, unit, isForward );\n\t}\n\n\t// Entering an element.\n\tif ( type == ( isForward ? 'elementStart' : 'elementEnd' ) ) {\n\t\t// If it's a selectable, we can select it now.\n\t\tif ( schema.isSelectable( item ) ) {\n\t\t\treturn Position._createAt( item, isForward ? 'after' : 'before' );\n\t\t}\n\n\t\t// If text allowed on this position, extend to this place.\n\t\tif ( schema.checkChild( nextPosition, '$text' ) ) {\n\t\t\treturn nextPosition;\n\t\t}\n\t}\n\t// Leaving an element.\n\telse {\n\t\t// If leaving a limit element, stop.\n\t\tif ( schema.isLimit( item ) ) {\n\t\t\t// NOTE: Fast-forward the walker until the end.\n\t\t\twalker.skip( () => true );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// If text allowed on this position, extend to this place.\n\t\tif ( schema.checkChild( nextPosition, '$text' ) ) {\n\t\t\treturn nextPosition;\n\t\t}\n\t}\n}\n\n// Finds a correct position by walking in a text node and checking whether selection can be extended to given position\n// or should be extended further.\n//\n// @param {module:engine/model/treewalker~TreeWalker} walker\n// @param {String} unit The unit by which selection should be modified.\nfunction getCorrectPosition( walker, unit ) {\n\tconst textNode = walker.position.textNode;\n\n\tif ( textNode ) {\n\t\tconst data = textNode.data;\n\t\tlet offset = walker.position.offset - textNode.startOffset;\n\n\t\twhile ( isInsideSurrogatePair( data, offset ) || ( unit == 'character' && isInsideCombinedSymbol( data, offset ) ) ) {\n\t\t\twalker.next();\n\n\t\t\toffset = walker.position.offset - textNode.startOffset;\n\t\t}\n\t}\n\n\treturn walker.position;\n}\n\n// Finds a correct position of a word break by walking in a text node and checking whether selection can be extended to given position\n// or should be extended further.\n//\n// @param {module:engine/model/treewalker~TreeWalker} walker\n// @param {Boolean} isForward Is the direction in which the selection should be modified is forward.\nfunction getCorrectWordBreakPosition( walker, isForward ) {\n\tlet textNode = walker.position.textNode;\n\n\tif ( textNode ) {\n\t\tlet offset = walker.position.offset - textNode.startOffset;\n\n\t\twhile ( !isAtWordBoundary( textNode.data, offset, isForward ) && !isAtNodeBoundary( textNode, offset, isForward ) ) {\n\t\t\twalker.next();\n\n\t\t\t// Check of adjacent text nodes with different attributes (like BOLD).\n\t\t\t// Example          : 'foofoo []bar<$text bold=\"true\">bar</$text> bazbaz'\n\t\t\t// should expand to : 'foofoo [bar<$text bold=\"true\">bar</$text>] bazbaz'.\n\t\t\tconst nextNode = isForward ? walker.position.nodeAfter : walker.position.nodeBefore;\n\n\t\t\t// Scan only text nodes. Ignore inline elements (like `<softBreak>`).\n\t\t\tif ( nextNode && nextNode.is( '$text' ) ) {\n\t\t\t\t// Check boundary char of an adjacent text node.\n\t\t\t\tconst boundaryChar = nextNode.data.charAt( isForward ? 0 : nextNode.data.length - 1 );\n\n\t\t\t\t// Go to the next node if the character at the boundary of that node belongs to the same word.\n\t\t\t\tif ( !wordBoundaryCharacters.includes( boundaryChar ) ) {\n\t\t\t\t\t// If adjacent text node belongs to the same word go to it & reset values.\n\t\t\t\t\twalker.next();\n\n\t\t\t\t\ttextNode = walker.position.textNode;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\toffset = walker.position.offset - textNode.startOffset;\n\t\t}\n\t}\n\n\treturn walker.position;\n}\n\nfunction getSearchRange( start, isForward ) {\n\tconst root = start.root;\n\tconst searchEnd = Position._createAt( root, isForward ? 'end' : 0 );\n\n\tif ( isForward ) {\n\t\treturn new Range( start, searchEnd );\n\t} else {\n\t\treturn new Range( searchEnd, start );\n\t}\n}\n\n// Checks if selection is on word boundary.\n//\n// @param {String} data The text node value to investigate.\n// @param {Number} offset Position offset.\n// @param {Boolean} isForward Is the direction in which the selection should be modified is forward.\nfunction isAtWordBoundary( data, offset, isForward ) {\n\t// The offset to check depends on direction.\n\tconst offsetToCheck = offset + ( isForward ? 0 : -1 );\n\n\treturn wordBoundaryCharacters.includes( data.charAt( offsetToCheck ) );\n}\n\n// Checks if selection is on node boundary.\n//\n// @param {module:engine/model/text~Text} textNode The text node to investigate.\n// @param {Number} offset Position offset.\n// @param {Boolean} isForward Is the direction in which the selection should be modified is forward.\nfunction isAtNodeBoundary( textNode, offset, isForward ) {\n\treturn offset === ( isForward ? textNode.endOffset : 0 );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/utils/getselectedcontent\n */\n\n/**\n * Gets a clone of the selected content.\n *\n * For example, for the following selection:\n *\n * ```html\n * <p>x</p><quote><p>y</p><h>fir[st</h></quote><p>se]cond</p><p>z</p>\n * ```\n *\n * It will return a document fragment with such a content:\n *\n * ```html\n * <quote><h>st</h></quote><p>se</p>\n * ```\n *\n * @param {module:engine/model/model~Model} model The model in context of which\n * the selection modification should be performed.\n * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n * The selection of which content will be returned.\n * @returns {module:engine/model/documentfragment~DocumentFragment}\n */\nexport default function getSelectedContent( model, selection ) {\n\treturn model.change( writer => {\n\t\tconst frag = writer.createDocumentFragment();\n\t\tconst range = selection.getFirstRange();\n\n\t\tif ( !range || range.isCollapsed ) {\n\t\t\treturn frag;\n\t\t}\n\n\t\tconst root = range.start.root;\n\t\tconst commonPath = range.start.getCommonPath( range.end );\n\t\tconst commonParent = root.getNodeByPath( commonPath );\n\n\t\t// ## 1st step\n\t\t//\n\t\t// First, we'll clone a fragment represented by a minimal flat range\n\t\t// containing the original range to be cloned.\n\t\t// E.g. let's consider such a range:\n\t\t//\n\t\t// <p>x</p><quote><p>y</p><h>fir[st</h></quote><p>se]cond</p><p>z</p>\n\t\t//\n\t\t// A minimal flat range containing this one is:\n\t\t//\n\t\t// <p>x</p>[<quote><p>y</p><h>first</h></quote><p>second</p>]<p>z</p>\n\t\t//\n\t\t// We can easily clone this structure, preserving e.g. the <quote> element.\n\t\tlet flatSubtreeRange;\n\n\t\tif ( range.start.parent == range.end.parent ) {\n\t\t\t// The original range is flat, so take it.\n\t\t\tflatSubtreeRange = range;\n\t\t} else {\n\t\t\tflatSubtreeRange = writer.createRange(\n\t\t\t\twriter.createPositionAt( commonParent, range.start.path[ commonPath.length ] ),\n\t\t\t\twriter.createPositionAt( commonParent, range.end.path[ commonPath.length ] + 1 )\n\t\t\t);\n\t\t}\n\n\t\tconst howMany = flatSubtreeRange.end.offset - flatSubtreeRange.start.offset;\n\n\t\t// Clone the whole contents.\n\t\tfor ( const item of flatSubtreeRange.getItems( { shallow: true } ) ) {\n\t\t\tif ( item.is( '$textProxy' ) ) {\n\t\t\t\twriter.appendText( item.data, item.getAttributes(), frag );\n\t\t\t} else {\n\t\t\t\twriter.append( writer.cloneElement( item, true ), frag );\n\t\t\t}\n\t\t}\n\n\t\t// ## 2nd step\n\t\t//\n\t\t// If the original range wasn't flat, then we need to remove the excess nodes from the both ends of the cloned fragment.\n\t\t//\n\t\t// For example, for the range shown in the 1st step comment, we need to remove these pieces:\n\t\t//\n\t\t// <quote>[<p>y</p>]<h>[fir]st</h></quote><p>se[cond]</p>\n\t\t//\n\t\t// So this will be the final copied content:\n\t\t//\n\t\t// <quote><h>st</h></quote><p>se</p>\n\t\t//\n\t\t// In order to do that, we remove content from these two ranges:\n\t\t//\n\t\t// [<quote><p>y</p><h>fir]st</h></quote><p>se[cond</p>]\n\t\tif ( flatSubtreeRange != range ) {\n\t\t\t// Find the position of the original range in the cloned fragment.\n\t\t\tconst newRange = range._getTransformedByMove( flatSubtreeRange.start, writer.createPositionAt( frag, 0 ), howMany )[ 0 ];\n\n\t\t\tconst leftExcessRange = writer.createRange( writer.createPositionAt( frag, 0 ), newRange.start );\n\t\t\tconst rightExcessRange = writer.createRange( newRange.end, writer.createPositionAt( frag, 'end' ) );\n\n\t\t\tremoveRangeContent( rightExcessRange, writer );\n\t\t\tremoveRangeContent( leftExcessRange, writer );\n\t\t}\n\n\t\treturn frag;\n\t} );\n}\n\n// After https://github.com/ckeditor/ckeditor5-engine/issues/690 is fixed,\n// this function will, most likely, be able to rewritten using getMinimalFlatRanges().\nfunction removeRangeContent( range, writer ) {\n\tconst parentsToCheck = [];\n\n\tArray.from( range.getItems( { direction: 'backward' } ) )\n\t\t// We should better store ranges because text proxies will lose integrity\n\t\t// with the text nodes when we'll start removing content.\n\t\t.map( item => writer.createRangeOn( item ) )\n\t\t// Filter only these items which are fully contained in the passed range.\n\t\t//\n\t\t// E.g. for the following range: [<quote><p>y</p><h>fir]st</h>\n\t\t// the walker will return the entire <h> element, when only the \"fir\" item inside it is fully contained.\n\t\t.filter( itemRange => {\n\t\t\t// We should be able to use Range.containsRange, but https://github.com/ckeditor/ckeditor5-engine/issues/691.\n\t\t\tconst contained =\n\t\t\t\t( itemRange.start.isAfter( range.start ) || itemRange.start.isEqual( range.start ) ) &&\n\t\t\t\t( itemRange.end.isBefore( range.end ) || itemRange.end.isEqual( range.end ) );\n\n\t\t\treturn contained;\n\t\t} )\n\t\t.forEach( itemRange => {\n\t\t\tparentsToCheck.push( itemRange.start.parent );\n\n\t\t\twriter.remove( itemRange );\n\t\t} );\n\n\t// Remove ancestors of the removed items if they turned to be empty now\n\t// (their whole content was contained in the range).\n\tparentsToCheck.forEach( parentToCheck => {\n\t\tlet parent = parentToCheck;\n\n\t\twhile ( parent.parent && parent.isEmpty ) {\n\t\t\tconst removeRange = writer.createRangeOn( parent );\n\n\t\t\tparent = parent.parent;\n\n\t\t\twriter.remove( removeRange );\n\t\t}\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/utils/selection-post-fixer\n */\n\nimport Range from '../range';\nimport Position from '../position';\n\n/**\n * Injects selection post-fixer to the model.\n *\n * The role of the selection post-fixer is to ensure that the selection is in a correct place\n * after a {@link module:engine/model/model~Model#change `change()`} block was executed.\n *\n * The correct position means that:\n *\n * * All collapsed selection ranges are in a place where the {@link module:engine/model/schema~Schema}\n * allows a `$text`.\n * * None of the selection's non-collapsed ranges crosses a {@link module:engine/model/schema~Schema#isLimit limit element}\n * boundary (a range must be rooted within one limit element).\n * * Only {@link module:engine/model/schema~Schema#isSelectable selectable elements} can be selected from the outside\n * (e.g. `[<paragraph>foo</paragraph>]` is invalid). This rule applies independently to both selection ends, so this\n * selection is correct: `<paragraph>f[oo</paragraph><image></image>]`.\n *\n * If the position is not correct, the post-fixer will automatically correct it.\n *\n * ## Fixing a non-collapsed selection\n *\n * See as an example a selection that starts in a P1 element and ends inside the text of a TD element\n * (`[` and `]` are range boundaries and `(l)` denotes an element defined as `isLimit=true`):\n *\n *\t\troot\n *\t\t |- element P1\n *\t\t |   |- \"foo\"                                      root\n *\t\t |- element TABLE (l)                   P1         TABLE             P2\n *\t\t |   |- element TR (l)                 f o[o     TR      TR         b a r\n *\t\t |   |   |- element TD (l)                       TD      TD\n *\t\t |   |       |- \"aaa\"                          a]a a    b b b\n *\t\t |   |- element TR (l)\n *\t\t |   |   |- element TD (l)                           ||\n *\t\t |   |       |- \"bbb\"                                ||\n *\t\t |- element P2                                       VV\n *\t\t |   |- \"bar\"\n *\t\t                                                   root\n *\t\t                                        P1         TABLE]            P2\n *\t\t                                       f o[o     TR      TR         b a r\n *\t\t                                                 TD      TD\n *\t\t                                               a a a    b b b\n *\n * In the example above, the TABLE, TR and TD are defined as `isLimit=true` in the schema. The range which is not contained within\n * a single limit element must be expanded to select the outermost limit element. The range end is inside the text node of the TD element.\n * As the TD element is a child of the TR and TABLE elements, where both are defined as `isLimit=true` in the schema, the range must be\n * expanded to select the whole TABLE element.\n *\n * **Note** If the selection contains multiple ranges, the method returns a minimal set of ranges that are not intersecting after expanding\n * them to select `isLimit=true` elements.\n *\n * @param {module:engine/model/model~Model} model\n */\nexport function injectSelectionPostFixer( model ) {\n\tmodel.document.registerPostFixer( writer => selectionPostFixer( writer, model ) );\n}\n\n// The selection post-fixer.\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/model~Model} model\nfunction selectionPostFixer( writer, model ) {\n\tconst selection = model.document.selection;\n\tconst schema = model.schema;\n\n\tconst ranges = [];\n\n\tlet wasFixed = false;\n\n\tfor ( const modelRange of selection.getRanges() ) {\n\t\t// Go through all ranges in selection and try fixing each of them.\n\t\t// Those ranges might overlap but will be corrected later.\n\t\tconst correctedRange = tryFixingRange( modelRange, schema );\n\n\t\t// \"Selection fixing\" algorithms sometimes get lost. In consequence, it may happen\n\t\t// that a new range is returned but, in fact, it has the same positions as the original\n\t\t// range anyway. If this range is not discarded, a new selection will be set and that,\n\t\t// for instance, would destroy the selection attributes. Let's make sure that the post-fixer\n\t\t// actually worked first before setting a new selection.\n\t\t//\n\t\t// https://github.com/ckeditor/ckeditor5/issues/6693\n\t\tif ( correctedRange && !correctedRange.isEqual( modelRange ) ) {\n\t\t\tranges.push( correctedRange );\n\t\t\twasFixed = true;\n\t\t} else {\n\t\t\tranges.push( modelRange );\n\t\t}\n\t}\n\n\t// If any of ranges were corrected update the selection.\n\tif ( wasFixed ) {\n\t\twriter.setSelection( mergeIntersectingRanges( ranges ), { backward: selection.isBackward } );\n\t}\n}\n\n// Tries fixing a range if it's incorrect.\n//\n// @param {module:engine/model/range~Range} range\n// @param {module:engine/model/schema~Schema} schema\n// @returns {module:engine/model/range~Range|null} Returns fixed range or null if range is valid.\nfunction tryFixingRange( range, schema ) {\n\tif ( range.isCollapsed ) {\n\t\treturn tryFixingCollapsedRange( range, schema );\n\t}\n\n\treturn tryFixingNonCollapsedRage( range, schema );\n}\n\n// Tries to fix collapsed ranges.\n//\n// * Fixes situation when a range is in a place where $text is not allowed\n//\n// @param {module:engine/model/range~Range} range Collapsed range to fix.\n// @param {module:engine/model/schema~Schema} schema\n// @returns {module:engine/model/range~Range|null} Returns fixed range or null if range is valid.\nfunction tryFixingCollapsedRange( range, schema ) {\n\tconst originalPosition = range.start;\n\n\tconst nearestSelectionRange = schema.getNearestSelectionRange( originalPosition );\n\n\t// This might be null ie when editor data is empty.\n\t// In such cases there is no need to fix the selection range.\n\tif ( !nearestSelectionRange ) {\n\t\treturn null;\n\t}\n\n\tif ( !nearestSelectionRange.isCollapsed ) {\n\t\treturn nearestSelectionRange;\n\t}\n\n\tconst fixedPosition = nearestSelectionRange.start;\n\n\t// Fixed position is the same as original - no need to return corrected range.\n\tif ( originalPosition.isEqual( fixedPosition ) ) {\n\t\treturn null;\n\t}\n\n\treturn new Range( fixedPosition );\n}\n\n// Tries to fix an expanded range.\n//\n// @param {module:engine/model/range~Range} range Expanded range to fix.\n// @param {module:engine/model/schema~Schema} schema\n// @returns {module:engine/model/range~Range|null} Returns fixed range or null if range is valid.\nfunction tryFixingNonCollapsedRage( range, schema ) {\n\tconst { start, end } = range;\n\n\tconst isTextAllowedOnStart = schema.checkChild( start, '$text' );\n\tconst isTextAllowedOnEnd = schema.checkChild( end, '$text' );\n\n\tconst startLimitElement = schema.getLimitElement( start );\n\tconst endLimitElement = schema.getLimitElement( end );\n\n\t// Ranges which both end are inside the same limit element (or root) might needs only minor fix.\n\tif ( startLimitElement === endLimitElement ) {\n\t\t// Range is valid when both position allows to place a text:\n\t\t// - <block>f[oobarba]z</block>\n\t\t// This would be \"fixed\" by a next check but as it will be the same it's better to return null so the selection stays the same.\n\t\tif ( isTextAllowedOnStart && isTextAllowedOnEnd ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Range that is on non-limit element (or is partially) must be fixed so it is placed inside the block around $text:\n\t\t// - [<block>foo</block>]    ->    <block>[foo]</block>\n\t\t// - [<block>foo]</block>    ->    <block>[foo]</block>\n\t\t// - <block>f[oo</block>]    ->    <block>f[oo]</block>\n\t\t// - [<block>foo</block><selectable></selectable>]    ->    <block>[foo</block><selectable></selectable>]\n\t\tif ( checkSelectionOnNonLimitElements( start, end, schema ) ) {\n\t\t\tconst isStartBeforeSelectable = start.nodeAfter && schema.isSelectable( start.nodeAfter );\n\t\t\tconst fixedStart = isStartBeforeSelectable ? null : schema.getNearestSelectionRange( start, 'forward' );\n\n\t\t\tconst isEndAfterSelectable = end.nodeBefore && schema.isSelectable( end.nodeBefore );\n\t\t\tconst fixedEnd = isEndAfterSelectable ? null : schema.getNearestSelectionRange( end, 'backward' );\n\n\t\t\t// The schema.getNearestSelectionRange might return null - if that happens use original position.\n\t\t\tconst rangeStart = fixedStart ? fixedStart.start : start;\n\t\t\tconst rangeEnd = fixedEnd ? fixedEnd.end : end;\n\n\t\t\treturn new Range( rangeStart, rangeEnd );\n\t\t}\n\t}\n\n\tconst isStartInLimit = startLimitElement && !startLimitElement.is( 'rootElement' );\n\tconst isEndInLimit = endLimitElement && !endLimitElement.is( 'rootElement' );\n\n\t// At this point we eliminated valid positions on text nodes so if one of range positions is placed inside a limit element\n\t// then the range crossed limit element boundaries and needs to be fixed.\n\tif ( isStartInLimit || isEndInLimit ) {\n\t\tconst bothInSameParent = ( start.nodeAfter && end.nodeBefore ) && start.nodeAfter.parent === end.nodeBefore.parent;\n\n\t\tconst expandStart = isStartInLimit && ( !bothInSameParent || !isSelectable( start.nodeAfter, schema ) );\n\t\tconst expandEnd = isEndInLimit && ( !bothInSameParent || !isSelectable( end.nodeBefore, schema ) );\n\n\t\t// Although we've already found limit element on start/end positions we must find the outer-most limit element.\n\t\t// as limit elements might be nested directly inside (ie table > tableRow > tableCell).\n\t\tlet fixedStart = start;\n\t\tlet fixedEnd = end;\n\n\t\tif ( expandStart ) {\n\t\t\tfixedStart = Position._createBefore( findOutermostLimitAncestor( startLimitElement, schema ) );\n\t\t}\n\n\t\tif ( expandEnd ) {\n\t\t\tfixedEnd = Position._createAfter( findOutermostLimitAncestor( endLimitElement, schema ) );\n\t\t}\n\n\t\treturn new Range( fixedStart, fixedEnd );\n\t}\n\n\t// Range was not fixed at this point so it is valid - ie it was placed around limit element already.\n\treturn null;\n}\n\n// Finds the outer-most ancestor.\n//\n// @param {module:engine/model/node~Node} startingNode\n// @param {module:engine/model/schema~Schema} schema\n// @param {String} expandToDirection Direction of expansion - either 'start' or 'end' of the range.\n// @returns {module:engine/model/node~Node}\nfunction findOutermostLimitAncestor( startingNode, schema ) {\n\tlet isLimitNode = startingNode;\n\tlet parent = isLimitNode;\n\n\t// Find outer most isLimit block as such blocks might be nested (ie. in tables).\n\twhile ( schema.isLimit( parent ) && parent.parent ) {\n\t\tisLimitNode = parent;\n\t\tparent = parent.parent;\n\t}\n\n\treturn isLimitNode;\n}\n\n// Checks whether any of range boundaries is placed around non-limit elements.\n//\n// @param {module:engine/model/position~Position} start\n// @param {module:engine/model/position~Position} end\n// @param {module:engine/model/schema~Schema} schema\n// @returns {Boolean}\nfunction checkSelectionOnNonLimitElements( start, end, schema ) {\n\tconst startIsOnBlock = ( start.nodeAfter && !schema.isLimit( start.nodeAfter ) ) || schema.checkChild( start, '$text' );\n\tconst endIsOnBlock = ( end.nodeBefore && !schema.isLimit( end.nodeBefore ) ) || schema.checkChild( end, '$text' );\n\n\t// We should fix such selection when one of those nodes needs fixing.\n\treturn startIsOnBlock || endIsOnBlock;\n}\n\n// Returns a minimal non-intersecting array of ranges.\n//\n// @param {Array.<module:engine/model/range~Range>} ranges\n// @returns {Array.<module:engine/model/range~Range>}\nfunction mergeIntersectingRanges( ranges ) {\n\tconst nonIntersectingRanges = [];\n\n\t// First range will always be fine.\n\tnonIntersectingRanges.push( ranges.shift() );\n\n\tfor ( const range of ranges ) {\n\t\tconst previousRange = nonIntersectingRanges.pop();\n\n\t\tif ( range.isEqual( previousRange ) ) {\n\t\t\t// Use only one of two identical ranges.\n\t\t\tnonIntersectingRanges.push( previousRange );\n\t\t} else if ( range.isIntersecting( previousRange ) ) {\n\t\t\t// Get the sum of two ranges.\n\t\t\tconst start = previousRange.start.isAfter( range.start ) ? range.start : previousRange.start;\n\t\t\tconst end = previousRange.end.isAfter( range.end ) ? previousRange.end : range.end;\n\n\t\t\tconst merged = new Range( start, end );\n\t\t\tnonIntersectingRanges.push( merged );\n\t\t} else {\n\t\t\tnonIntersectingRanges.push( previousRange );\n\t\t\tnonIntersectingRanges.push( range );\n\t\t}\n\t}\n\n\treturn nonIntersectingRanges;\n}\n\n// Checks if node exists and if it's a selectable.\n//\n// @param {module:engine/model/node~Node} node\n// @param {module:engine/model/schema~Schema} schema\n// @returns {Boolean}\nfunction isSelectable( node, schema ) {\n\treturn node && schema.isSelectable( node );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/model\n */\n\nimport Batch from './batch';\nimport Writer from './writer';\nimport Schema from './schema';\nimport Document from './document';\nimport MarkerCollection from './markercollection';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ModelElement from './element';\nimport ModelRange from './range';\nimport ModelPosition from './position';\nimport ModelSelection from './selection';\nimport OperationFactory from './operation/operationfactory';\n\nimport insertContent from './utils/insertcontent';\nimport deleteContent from './utils/deletecontent';\nimport modifySelection from './utils/modifyselection';\nimport getSelectedContent from './utils/getselectedcontent';\nimport { injectSelectionPostFixer } from './utils/selection-post-fixer';\nimport { autoParagraphEmptyRoots } from './utils/autoparagraphing';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n// @if CK_DEBUG_ENGINE // const { dumpTrees } = require( '../dev-utils/utils' );\n// @if CK_DEBUG_ENGINE // const { OperationReplayer } = require( '../dev-utils/operationreplayer' ).default;\n\n/**\n * Editor's data model. Read about the model in the\n * {@glink framework/guides/architecture/editing-engine engine architecture guide}.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Model {\n\tconstructor() {\n\t\t/**\n\t\t * Model's marker collection.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/markercollection~MarkerCollection}\n\t\t */\n\t\tthis.markers = new MarkerCollection();\n\n\t\t/**\n\t\t * Model's document.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/document~Document}\n\t\t */\n\t\tthis.document = new Document( this );\n\n\t\t/**\n\t\t * Model's schema.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/schema~Schema}\n\t\t */\n\t\tthis.schema = new Schema();\n\n\t\t/**\n\t\t * All callbacks added by {@link module:engine/model/model~Model#change} or\n\t\t * {@link module:engine/model/model~Model#enqueueChange} methods waiting to be executed.\n\t\t *\n\t\t * @private\n\t\t * @type {Array.<Function>}\n\t\t */\n\t\tthis._pendingChanges = [];\n\n\t\t/**\n\t\t * The last created and currently used writer instance.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/writer~Writer}\n\t\t */\n\t\tthis._currentWriter = null;\n\n\t\t[ 'insertContent', 'deleteContent', 'modifySelection', 'getSelectedContent', 'applyOperation' ]\n\t\t\t.forEach( methodName => this.decorate( methodName ) );\n\n\t\t// Adding operation validation with `highest` priority, so it is called before any other feature would like\n\t\t// to do anything with the operation. If the operation has incorrect parameters it should throw on the earliest occasion.\n\t\tthis.on( 'applyOperation', ( evt, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\toperation._validate();\n\t\t}, { priority: 'highest' } );\n\n\t\t// Register some default abstract entities.\n\t\tthis.schema.register( '$root', {\n\t\t\tisLimit: true\n\t\t} );\n\t\tthis.schema.register( '$block', {\n\t\t\tallowIn: '$root',\n\t\t\tisBlock: true\n\t\t} );\n\t\tthis.schema.register( '$text', {\n\t\t\tallowIn: '$block',\n\t\t\tisInline: true,\n\t\t\tisContent: true\n\t\t} );\n\t\tthis.schema.register( '$clipboardHolder', {\n\t\t\tallowContentOf: '$root',\n\t\t\tisLimit: true\n\t\t} );\n\t\tthis.schema.extend( '$text', { allowIn: '$clipboardHolder' } );\n\n\t\t// An element needed by the `upcastElementToMarker` converter.\n\t\t// This element temporarily represents a marker boundary during the conversion process and is removed\n\t\t// at the end of the conversion. `UpcastDispatcher` or at least `Conversion` class looks like a\n\t\t// better place for this registration but both know nothing about `Schema`.\n\t\tthis.schema.register( '$marker' );\n\t\tthis.schema.addChildCheck( ( context, childDefinition ) => {\n\t\t\tif ( childDefinition.name === '$marker' ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} );\n\n\t\tinjectSelectionPostFixer( this );\n\n\t\t// Post-fixer which takes care of adding empty paragraph elements to the empty roots.\n\t\tthis.document.registerPostFixer( autoParagraphEmptyRoots );\n\n\t\t// @if CK_DEBUG_ENGINE // this.on( 'applyOperation', () => {\n\t\t// @if CK_DEBUG_ENGINE // \tdumpTrees( this.document, this.document.version );\n\t\t// @if CK_DEBUG_ENGINE // }, { priority: 'lowest' } );\n\t}\n\n\t/**\n\t * The `change()` method is the primary way of changing the model. You should use it to modify all document nodes\n\t * (including detached nodes – i.e. nodes not added to the {@link module:engine/model/model~Model#document model document}),\n\t * the {@link module:engine/model/document~Document#selection document's selection}, and\n\t * {@link module:engine/model/model~Model#markers model markers}.\n\t *\n\t *\t\tmodel.change( writer => {\n\t *\t\t\twriter.insertText( 'foo', paragraph, 'end' );\n\t *\t\t} );\n\t *\n\t * All changes inside the change block use the same {@link module:engine/model/batch~Batch} so they are combined\n\t * into a single undo step.\n\t *\n\t *\t\tmodel.change( writer => {\n\t *\t\t\twriter.insertText( 'foo', paragraph, 'end' ); // foo.\n\t *\n\t *\t\t\tmodel.change( writer => {\n\t *\t\t\t\twriter.insertText( 'bar', paragraph, 'end' ); // foobar.\n\t *\t\t\t} );\n\t *\n\t * \t\t\twriter.insertText( 'bom', paragraph, 'end' ); // foobarbom.\n\t *\t\t} );\n\t *\n\t * The callback of the `change()` block is executed synchronously.\n\t *\n\t * You can also return a value from the change block.\n\t *\n\t *\t\tconst img = model.change( writer => {\n\t *\t\t\treturn writer.createElement( 'img' );\n\t *\t\t} );\n\t *\n\t * @see #enqueueChange\n\t * @param {Function} callback Callback function which may modify the model.\n\t * @returns {*} Value returned by the callback.\n\t */\n\tchange( callback ) {\n\t\ttry {\n\t\t\tif ( this._pendingChanges.length === 0 ) {\n\t\t\t\t// If this is the outermost block, create a new batch and start `_runPendingChanges` execution flow.\n\t\t\t\tthis._pendingChanges.push( { batch: new Batch(), callback } );\n\n\t\t\t\treturn this._runPendingChanges()[ 0 ];\n\t\t\t} else {\n\t\t\t\t// If this is not the outermost block, just execute the callback.\n\t\t\t\treturn callback( this._currentWriter );\n\t\t\t}\n\t\t} catch ( err ) {\n\t\t\t// @if CK_DEBUG // throw err;\n\t\t\t/* istanbul ignore next */\n\t\t\tCKEditorError.rethrowUnexpectedError( err, this );\n\t\t}\n\t}\n\n\t/**\n\t * The `enqueueChange()` method performs similar task as the {@link #change `change()` method}, with two major differences.\n\t *\n\t * First, the callback of `enqueueChange()` is executed when all other enqueued changes are done. It might be executed\n\t * immediately if it is not nested in any other change block, but if it is nested in another (enqueue)change block,\n\t * it will be delayed and executed after the outermost block.\n\t *\n\t *\t\tmodel.change( writer => {\n\t *\t\t\tconsole.log( 1 );\n\t *\n\t *\t\t\tmodel.enqueueChange( writer => {\n\t *\t\t\t\tconsole.log( 2 );\n\t *\t\t\t} );\n\t *\n\t * \t\t\tconsole.log( 3 );\n\t *\t\t} ); // Will log: 1, 3, 2.\n\t *\n\t * In addition to that, the changes enqueued with `enqueueChange()` will be converted separately from the changes\n\t * done in the outer `change()` block.\n\t *\n\t * Second, it lets you define the {@link module:engine/model/batch~Batch} into which you want to add your changes.\n\t * By default, a new batch is created. In the sample above, `change` and `enqueueChange` blocks use a different\n\t * batch (and different {@link module:engine/model/writer~Writer} since each of them operates on the separate batch).\n\t *\n\t * When using the `enqueueChange()` block you can also add some changes to the batch you used before.\n\t *\n\t *\t\tmodel.enqueueChange( batch, writer => {\n\t *\t\t\twriter.insertText( 'foo', paragraph, 'end' );\n\t *\t\t} );\n\t *\n\t * In order to make a nested `enqueueChange()` create a single undo step together with the changes done in the outer `change()`\n\t * block, you can obtain the batch instance from the  {@link module:engine/model/writer~Writer#batch writer} of the outer block.\n\t *\n\t * @param {module:engine/model/batch~Batch|'transparent'|'default'} batchOrType Batch or batch type should be used in the callback.\n\t * If not defined, a new batch will be created.\n\t * @param {Function} callback Callback function which may modify the model.\n\t */\n\tenqueueChange( batchOrType, callback ) {\n\t\ttry {\n\t\t\tif ( typeof batchOrType === 'string' ) {\n\t\t\t\tbatchOrType = new Batch( batchOrType );\n\t\t\t} else if ( typeof batchOrType == 'function' ) {\n\t\t\t\tcallback = batchOrType;\n\t\t\t\tbatchOrType = new Batch();\n\t\t\t}\n\n\t\t\tthis._pendingChanges.push( { batch: batchOrType, callback } );\n\n\t\t\tif ( this._pendingChanges.length == 1 ) {\n\t\t\t\tthis._runPendingChanges();\n\t\t\t}\n\t\t} catch ( err ) {\n\t\t\t// @if CK_DEBUG // throw err;\n\t\t\t/* istanbul ignore next */\n\t\t\tCKEditorError.rethrowUnexpectedError( err, this );\n\t\t}\n\t}\n\n\t/**\n\t * {@link module:utils/observablemixin~ObservableMixin#decorate Decorated} function for applying\n\t * {@link module:engine/model/operation/operation~Operation operations} to the model.\n\t *\n\t * This is a low-level way of changing the model. It is exposed for very specific use cases (like the undo feature).\n\t * Normally, to modify the model, you will want to use {@link module:engine/model/writer~Writer `Writer`}.\n\t * See also {@glink framework/guides/architecture/editing-engine#changing-the-model Changing the model} section\n\t * of the {@glink framework/guides/architecture/editing-engine Editing architecture} guide.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation The operation to apply.\n\t */\n\tapplyOperation( operation ) {\n\t\t// @if CK_DEBUG_ENGINE // console.log( 'Applying ' + operation );\n\n\t\t// @if CK_DEBUG_ENGINE // if ( !this._operationLogs ) {\n\t\t// @if CK_DEBUG_ENGINE //\tthis._operationLogs = [];\n\t\t// @if CK_DEBUG_ENGINE // }\n\n\t\t// @if CK_DEBUG_ENGINE // this._operationLogs.push( JSON.stringify( operation ) );\n\n\t\t// @if CK_DEBUG_ENGINE //if ( !this._appliedOperations ) {\n\t\t// @if CK_DEBUG_ENGINE //\tthis._appliedOperations = [];\n\t\t// @if CK_DEBUG_ENGINE //}\n\n\t\t// @if CK_DEBUG_ENGINE //this._appliedOperations.push( operation );\n\n\t\toperation._execute();\n\t}\n\n\t// @if CK_DEBUG_ENGINE // getAppliedOperation() {\n\t// @if CK_DEBUG_ENGINE //\tif ( !this._appliedOperations ) {\n\t// @if CK_DEBUG_ENGINE //\t\treturn '';\n\t// @if CK_DEBUG_ENGINE //\t}\n\n\t// @if CK_DEBUG_ENGINE //\treturn this._appliedOperations.map( JSON.stringify ).join( '-------' );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // createReplayer( stringifiedOperations ) {\n\t// @if CK_DEBUG_ENGINE //\treturn new OperationReplayer( this, '-------', stringifiedOperations );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t/**\n\t * Inserts content at the position in the editor specified by the selection, as one would expect the paste\n\t * functionality to work.\n\t *\n\t * This is a high-level method. It takes the {@link #schema schema} into consideration when inserting\n\t * the content, clears the given selection's content before inserting nodes and moves the selection\n\t * to its target position at the end of the process.\n\t * It can split elements, merge them, wrap bare text nodes with paragraphs, etc. &mdash; just like the\n\t * pasting feature should do.\n\t *\n\t * For lower-level methods see {@link module:engine/model/writer~Writer `Writer`}.\n\t *\n\t * This method, unlike {@link module:engine/model/writer~Writer `Writer`}'s methods, does not have to be used\n\t * inside a {@link #change `change()` block}.\n\t *\n\t * # Conversion and schema\n\t *\n\t * Inserting elements and text nodes into the model is not enough to make CKEditor 5 render that content\n\t * to the user. CKEditor 5 implements a model-view-controller architecture and what `model.insertContent()` does\n\t * is only adding nodes to the model. Additionally, you need to define\n\t * {@glink framework/guides/architecture/editing-engine#conversion converters} between the model and view\n\t * and define those nodes in the {@glink framework/guides/architecture/editing-engine#schema schema}.\n\t *\n\t * So, while this method may seem similar to CKEditor 4 `editor.insertHtml()` (in fact, both methods\n\t * are used for paste-like content insertion), the CKEditor 5 method cannot be use to insert arbitrary HTML\n\t * unless converters are defined for all elements and attributes in that HTML.\n\t *\n\t * # Examples\n\t *\n\t * Using `insertContent()` with a manually created model structure:\n\t *\n\t *\t\t// Let's create a document fragment containing such content as:\n\t *\t\t//\n\t *\t\t// <paragraph>foo</paragraph>\n\t *\t\t// <blockQuote>\n\t *\t\t//    <paragraph>bar</paragraph>\n\t *\t\t// </blockQuote>\n\t *\t\tconst docFrag = editor.model.change( writer => {\n\t *\t\t\tconst p1 = writer.createElement( 'paragraph' );\n\t *\t\t\tconst p2 = writer.createElement( 'paragraph' );\n\t *\t\t\tconst blockQuote = writer.createElement( 'blockQuote' );\n\t *\t\t\tconst docFrag = writer.createDocumentFragment();\n\t *\n\t *\t\t\twriter.append( p1, docFrag );\n\t *\t\t\twriter.append( blockQuote, docFrag );\n\t *\t\t\twriter.append( p2, blockQuote );\n\t *\t\t\twriter.insertText( 'foo', p1 );\n\t *\t\t\twriter.insertText( 'bar', p2 );\n\t *\n\t *\t\t\treturn docFrag;\n\t *\t\t} );\n\t *\n\t *\t\t// insertContent() does not have to be used in a change() block. It can, though,\n\t *\t\t// so this code could be moved to the callback defined above.\n\t *\t\teditor.model.insertContent( docFrag );\n\t *\n\t * Using `insertContent()` with an HTML string converted to a model document fragment (similar to the pasting mechanism):\n\t *\n\t *\t\t// You can create your own HtmlDataProcessor instance or use editor.data.processor\n\t *\t\t// if you have not overridden the default one (which is the HtmlDataProcessor instance).\n\t *\t\tconst htmlDP = new HtmlDataProcessor( viewDocument );\n\t *\n\t *\t\t// Convert an HTML string to a view document fragment:\n\t *\t\tconst viewFragment = htmlDP.toView( htmlString );\n\t *\n\t *\t\t// Convert the view document fragment to a model document fragment\n\t *\t\t// in the context of $root. This conversion takes the schema into\n\t *\t\t// account so if, for example, the view document fragment contained a bare text node,\n\t *\t\t// this text node cannot be a child of $root, so it will be automatically\n\t *\t\t// wrapped with a <paragraph>. You can define the context yourself (in the second parameter),\n\t *\t\t// and e.g. convert the content like it would happen in a <paragraph>.\n\t *\t\t// Note: The clipboard feature uses a custom context called $clipboardHolder\n\t *\t\t// which has a loosened schema.\n\t *\t\tconst modelFragment = editor.data.toModel( viewFragment );\n\t *\n\t *\t\teditor.model.insertContent( modelFragment );\n\t *\n\t * By default this method will use the document selection but it can also be used with a position, range or selection instance.\n\t *\n\t *\t\t// Insert text at the current document selection position.\n\t *\t\teditor.model.change( writer => {\n\t *\t\t\teditor.model.insertContent( writer.createText( 'x' ) );\n\t *\t\t} );\n\t *\n\t *\t\t// Insert text at a given position - the document selection will not be modified.\n\t *\t\teditor.model.change( writer => {\n\t *\t\t\teditor.model.insertContent( writer.createText( 'x' ), doc.getRoot(), 2 );\n\t *\n\t *\t\t\t// Which is a shorthand for:\n\t *\t\t\teditor.model.insertContent( writer.createText( 'x' ), writer.createPositionAt( doc.getRoot(), 2 ) );\n\t *\t\t} );\n\t *\n\t * If you want the document selection to be moved to the inserted content, use the\n\t * {@link module:engine/model/writer~Writer#setSelection `setSelection()`} method of the writer after inserting\n\t * the content:\n\t *\n\t *\t\teditor.model.change( writer => {\n\t *\t\t\tconst paragraph = writer.createElement( 'paragraph' );\n\t *\n\t *\t\t\t// Insert an empty paragraph at the beginning of the root.\n\t *\t\t\teditor.model.insertContent( paragraph, writer.createPositionAt( editor.model.document.getRoot(), 0 ) );\n\t *\n\t *\t\t\t// Move the document selection to the inserted paragraph.\n\t *\t\t\twriter.setSelection( paragraph, 'in' );\n\t *\t\t} );\n\t *\n\t * If an instance of the {@link module:engine/model/selection~Selection model selection} is passed as `selectable`,\n\t * the new content will be inserted at the passed selection (instead of document selection):\n\t *\n\t *\t\teditor.model.change( writer => {\n\t *\t\t\t// Create a selection in a paragraph that will be used as a place of insertion.\n\t *\t\t\tconst selection = writer.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t\t// Insert the new text at the created selection.\n\t *\t\t\teditor.model.insertContent( writer.createText( 'x' ), selection );\n\t *\n\t *\t\t\t// insertContent() modifies the passed selection instance so it can be used to set the document selection.\n\t *\t\t\t// Note: This is not necessary when you passed the document selection to insertContent().\n\t *\t\t\twriter.setSelection( selection );\n\t *\t\t} );\n\t *\n\t * @fires insertContent\n\t * @param {module:engine/model/documentfragment~DocumentFragment|module:engine/model/item~Item} content The content to insert.\n\t * @param {module:engine/model/selection~Selectable} [selectable=model.document.selection]\n\t * The selection into which the content should be inserted. If not provided the current model document selection will be used.\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] To be used when a model item was passed as `selectable`.\n\t * This param defines a position in relation to that item.\n\t * @returns {module:engine/model/range~Range} Range which contains all the performed changes. This is a range that, if removed,\n\t * would return the model to the state before the insertion. If no changes were preformed by `insertContent`, returns a range collapsed\n\t * at the insertion position.\n\t */\n\tinsertContent( content, selectable, placeOrOffset ) {\n\t\treturn insertContent( this, content, selectable, placeOrOffset );\n\t}\n\n\t/**\n\t * Deletes content of the selection and merge siblings. The resulting selection is always collapsed.\n\t *\n\t * **Note:** For the sake of predictability, the resulting selection should always be collapsed.\n\t * In cases where a feature wants to modify deleting behavior so selection isn't collapsed\n\t * (e.g. a table feature may want to keep row selection after pressing <kbd>Backspace</kbd>),\n\t * then that behavior should be implemented in the view's listener. At the same time, the table feature\n\t * will need to modify this method's behavior too, e.g. to \"delete contents and then collapse\n\t * the selection inside the last selected cell\" or \"delete the row and collapse selection somewhere near\".\n\t * That needs to be done in order to ensure that other features which use `deleteContent()` will work well with tables.\n\t *\n\t * @fires deleteContent\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n\t * Selection of which the content should be deleted.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.leaveUnmerged=false] Whether to merge elements after removing the content of the selection.\n\t *\n\t * For example `<heading1>x[x</heading1><paragraph>y]y</paragraph>` will become:\n\t *\n\t * * `<heading1>x^y</heading1>` with the option disabled (`leaveUnmerged == false`)\n\t * * `<heading1>x^</heading1><paragraph>y</paragraph>` with enabled (`leaveUnmerged == true`).\n\t *\n\t * Note: {@link module:engine/model/schema~Schema#isObject object} and {@link module:engine/model/schema~Schema#isLimit limit}\n\t * elements will not be merged.\n\t *\n\t * @param {Boolean} [options.doNotResetEntireContent=false] Whether to skip replacing the entire content with a\n\t * paragraph when the entire content was selected.\n\t *\n\t * For example `<heading1>[x</heading1><paragraph>y]</paragraph>` will become:\n\t *\n\t * * `<paragraph>^</paragraph>` with the option disabled (`doNotResetEntireContent == false`)\n\t * * `<heading1>^</heading1>` with enabled (`doNotResetEntireContent == true`)\n\t *\n\t * @param {Boolean} [options.doNotAutoparagraph=false] Whether to create a paragraph if after content deletion selection is moved\n\t * to a place where text cannot be inserted.\n\t *\n\t * For example `<paragraph>x</paragraph>[<image src=\"foo.jpg\"></image>]` will become:\n\t *\n\t * * `<paragraph>x</paragraph><paragraph>[]</paragraph>` with the option disabled (`doNotAutoparagraph == false`)\n\t * * `<paragraph>x[]</paragraph>` with the option enabled (`doNotAutoparagraph == true`).\n\t *\n\t * **Note:** if there is no valid position for the selection, the paragraph will always be created:\n\t *\n\t * `[<image src=\"foo.jpg\"></image>]` -> `<paragraph>[]</paragraph>`.\n\t *\n\t * @param {'forward'|'backward'} [options.direction='backward'] The direction in which the content is being consumed.\n\t * Deleting backward corresponds to using the <kbd>Backspace</kbd> key, while deleting content forward corresponds to\n\t * the <kbd>Shift</kbd>+<kbd>Backspace</kbd> keystroke.\n\t */\n\tdeleteContent( selection, options ) {\n\t\tdeleteContent( this, selection, options );\n\t}\n\n\t/**\n\t * Modifies the selection. Currently, the supported modifications are:\n\t *\n\t * * Extending. The selection focus is moved in the specified `options.direction` with a step specified in `options.unit`.\n\t * Possible values for `unit` are:\n\t *  * `'character'` (default) - moves selection by one user-perceived character. In most cases this means moving by one\n\t *  character in `String` sense. However, unicode also defines \"combing marks\". These are special symbols, that combines\n\t *  with a symbol before it (\"base character\") to create one user-perceived character. For example, `q̣̇` is a normal\n\t *  letter `q` with two \"combining marks\": upper dot (`Ux0307`) and lower dot (`Ux0323`). For most actions, i.e. extending\n\t *  selection by one position, it is correct to include both \"base character\" and all of it's \"combining marks\". That is\n\t *  why `'character'` value is most natural and common method of modifying selection.\n\t *  * `'codePoint'` - moves selection by one unicode code point. In contrary to, `'character'` unit, this will insert\n\t *  selection between \"base character\" and \"combining mark\", because \"combining marks\" have their own unicode code points.\n\t *  However, for technical reasons, unicode code points with values above `UxFFFF` are represented in native `String` by\n\t *  two characters, called \"surrogate pairs\". Halves of \"surrogate pairs\" have a meaning only when placed next to each other.\n\t *  For example `𨭎` is represented in `String` by `\\uD862\\uDF4E`. Both `\\uD862` and `\\uDF4E` do not have any meaning\n\t *  outside the pair (are rendered as ? when alone). Position between them would be incorrect. In this case, selection\n\t *  extension will include whole \"surrogate pair\".\n\t *  * `'word'` - moves selection by a whole word.\n\t *\n\t * **Note:** if you extend a forward selection in a backward direction you will in fact shrink it.\n\t *\n\t * @fires modifySelection\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n\t * The selection to modify.\n\t * @param {Object} [options]\n\t * @param {'forward'|'backward'} [options.direction='forward'] The direction in which the selection should be modified.\n\t * @param {'character'|'codePoint'|'word'} [options.unit='character'] The unit by which selection should be modified.\n\t */\n\tmodifySelection( selection, options ) {\n\t\tmodifySelection( this, selection, options );\n\t}\n\n\t/**\n\t * Gets a clone of the selected content.\n\t *\n\t * For example, for the following selection:\n\t *\n\t * ```html\n\t * <paragraph>x</paragraph>\n\t * <blockQuote>\n\t *\t<paragraph>y</paragraph>\n\t *\t<heading1>fir[st</heading1>\n\t * </blockQuote>\n\t * <paragraph>se]cond</paragraph>\n\t * <paragraph>z</paragraph>\n\t * ```\n\t *\n\t * It will return a document fragment with such a content:\n\t *\n\t * ```html\n\t * <blockQuote>\n\t *\t<heading1>st</heading1>\n\t * </blockQuote>\n\t * <paragraph>se</paragraph>\n\t * ```\n\t *\n\t * @fires getSelectedContent\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n\t * The selection of which content will be returned.\n\t * @returns {module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tgetSelectedContent( selection ) {\n\t\treturn getSelectedContent( this, selection );\n\t}\n\n\t/**\n\t * Checks whether the given {@link module:engine/model/range~Range range} or\n\t * {@link module:engine/model/element~Element element} has any meaningful content.\n\t *\n\t * Meaningful content is:\n\t *\n\t * * any text node (`options.ignoreWhitespaces` allows controlling whether this text node must also contain\n\t * any non-whitespace characters),\n\t * * or any {@link module:engine/model/schema~Schema#isContent content element},\n\t * * or any {@link module:engine/model/markercollection~Marker marker} which\n\t * {@link module:engine/model/markercollection~Marker#_affectsData affects data}.\n\t *\n\t * This means that a range containing an empty `<paragraph></paragraph>` is not considered to have a meaningful content.\n\t * However, a range containing an `<image></image>` (which would normally be marked in the schema as an object element)\n\t * is considered non-empty.\n\t *\n\t * @param {module:engine/model/range~Range|module:engine/model/element~Element} rangeOrElement Range or element to check.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.ignoreWhitespaces] Whether text node with whitespaces only should be considered empty.\n\t * @param {Boolean} [options.ignoreMarkers] Whether markers should be ignored.\n\t * @returns {Boolean}\n\t */\n\thasContent( rangeOrElement, options = {} ) {\n\t\tconst range = rangeOrElement instanceof ModelElement ? ModelRange._createIn( rangeOrElement ) : rangeOrElement;\n\n\t\tif ( range.isCollapsed ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst { ignoreWhitespaces = false, ignoreMarkers = false } = options;\n\n\t\t// Check if there are any markers which affects data in this given range.\n\t\tif ( !ignoreMarkers ) {\n\t\t\tfor ( const intersectingMarker of this.markers.getMarkersIntersectingRange( range ) ) {\n\t\t\t\tif ( intersectingMarker.affectsData ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor ( const item of range.getItems() ) {\n\t\t\tif ( this.schema.isContent( item ) ) {\n\t\t\t\tif ( item.is( '$textProxy' ) ) {\n\t\t\t\t\tif ( !ignoreWhitespaces ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t} else if ( item.data.search( /\\S/ ) !== -1 ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Creates a position from the given root and path in that root.\n\t *\n\t * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createPositionFromPath `Writer#createPositionFromPath()`}.\n\t *\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} root Root of the position.\n\t * @param {Array.<Number>} path Position path. See {@link module:engine/model/position~Position#path}.\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone'] Position stickiness.\n\t * See {@link module:engine/model/position~PositionStickiness}.\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tcreatePositionFromPath( root, path, stickiness ) {\n\t\treturn new ModelPosition( root, path, stickiness );\n\t}\n\n\t/**\n\t * Creates position at the given location. The location can be specified as:\n\t *\n\t * * a {@link module:engine/model/position~Position position},\n\t * * a parent element and offset in that element,\n\t * * a parent element and `'end'` (the position will be set at the end of that element),\n\t * * a {@link module:engine/model/item~Item model item} and `'before'` or `'after'`\n\t * (the position will be set before or after the given model item).\n\t *\n\t * This method is a shortcut to other factory methods such as:\n\t *\n\t * * {@link module:engine/model/model~Model#createPositionBefore `createPositionBefore()`},\n\t * * {@link module:engine/model/model~Model#createPositionAfter `createPositionAfter()`}.\n\t *\n\t * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createPositionAt `Writer#createPositionAt()`},\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\tcreatePositionAt( itemOrPosition, offset ) {\n\t\treturn ModelPosition._createAt( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Creates a new position after the given {@link module:engine/model/item~Item model item}.\n\t *\n\t * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createPositionAfter `Writer#createPositionAfter()`}.\n\t *\n\t * @param {module:engine/model/item~Item} item Item after which the position should be placed.\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tcreatePositionAfter( item ) {\n\t\treturn ModelPosition._createAfter( item );\n\t}\n\n\t/**\n\t * Creates a new position before the given {@link module:engine/model/item~Item model item}.\n\t *\n\t * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createPositionBefore `Writer#createPositionBefore()`}.\n\t *\n\t * @param {module:engine/model/item~Item} item Item before which the position should be placed.\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tcreatePositionBefore( item ) {\n\t\treturn ModelPosition._createBefore( item );\n\t}\n\n\t/**\n\t * Creates a range spanning from the `start` position to the `end` position.\n\t *\n\t * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createRange `Writer#createRange()`}:\n\t *\n\t *\t\tmodel.change( writer => {\n\t *\t\t\tconst range = writer.createRange( start, end );\n\t *\t\t} );\n\t *\n\t * @param {module:engine/model/position~Position} start Start position.\n\t * @param {module:engine/model/position~Position} [end] End position. If not set, the range will be collapsed\n\t * to the `start` position.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tcreateRange( start, end ) {\n\t\treturn new ModelRange( start, end );\n\t}\n\n\t/**\n\t * Creates a range inside the given element which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createRangeIn `Writer#createRangeIn()`}:\n\t *\n\t *\t\tmodel.change( writer => {\n\t *\t\t\tconst range = writer.createRangeIn( paragraph );\n\t *\t\t} );\n\t *\n\t * @param {module:engine/model/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tcreateRangeIn( element ) {\n\t\treturn ModelRange._createIn( element );\n\t}\n\n\t/**\n\t * Creates a range that starts before the given {@link module:engine/model/item~Item model item} and ends after it.\n\t *\n\t * Note: This method is also available on `writer` instance as\n\t * {@link module:engine/model/writer~Writer#createRangeOn `Writer.createRangeOn()`}:\n\t *\n\t *\t\tmodel.change( writer => {\n\t *\t\t\tconst range = writer.createRangeOn( paragraph );\n\t *\t\t} );\n\t *\n\t * @param {module:engine/model/item~Item} item\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tcreateRangeOn( item ) {\n\t\treturn ModelRange._createOn( item );\n\t}\n\n\t/**\n\t * Creates a new selection instance based on the given {@link module:engine/model/selection~Selectable selectable}\n\t * or creates an empty selection if no arguments were passed.\n\t *\n\t * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createSelection `Writer#createSelection()`}.\n\t *\n\t *\t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = writer.createSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tconst selection = writer.createSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t *\t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tconst selection = writer.createSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tconst selection = writer.createSelection( otherSelection );\n\t *\n\t *\t\t// Creates selection from the given document selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst documentSelection = model.document.selection;\n\t *\t\tconst selection = writer.createSelection( documentSelection );\n\t *\n\t *\t\t// Creates selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\tconst selection = writer.createSelection( position );\n\t *\n\t *\t\t// Creates selection at the given offset in the given element.\n\t *\t\tconst paragraph = writer.createElement( 'paragraph' );\n\t *\t\tconst selection = writer.createSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/model/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/model/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'on' );\n\t *\n\t *\t\t// Additional options (`'backward'`) can be specified as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = writer.createSelection( range, { backward: true } );\n\t *\n\t * @param {module:engine/model/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @returns {module:engine/model/selection~Selection}\n\t */\n\tcreateSelection( selectable, placeOrOffset, options ) {\n\t\treturn new ModelSelection( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/model/batch~Batch} instance.\n\t *\n\t * **Note:** In most cases creating a batch instance is not necessary as they are created when using:\n\t *\n\t * * {@link #change `change()`},\n\t * * {@link #enqueueChange `enqueueChange()`}.\n\t *\n\t * @param {'transparent'|'default'} [type='default'] The type of the batch.\n\t * @returns {module:engine/model/batch~Batch}\n\t */\n\tcreateBatch( type ) {\n\t\treturn new Batch( type );\n\t}\n\n\t/**\n\t * Creates an operation instance from a JSON object (parsed JSON string).\n\t *\n\t * This is an alias for {@link module:engine/model/operation/operationfactory~OperationFactory.fromJSON `OperationFactory.fromJSON()`}.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @returns {module:engine/model/operation/operation~Operation}\n\t */\n\tcreateOperationFromJSON( json ) {\n\t\treturn OperationFactory.fromJSON( json, this.document );\n\t}\n\n\t/**\n\t * Removes all events listeners set by model instance and destroys {@link module:engine/model/document~Document}.\n\t */\n\tdestroy() {\n\t\tthis.document.destroy();\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Common part of {@link module:engine/model/model~Model#change} and {@link module:engine/model/model~Model#enqueueChange}\n\t * which calls callbacks and returns array of values returned by these callbacks.\n\t *\n\t * @private\n\t * @returns {Array.<*>} Array of values returned by callbacks.\n\t */\n\t_runPendingChanges() {\n\t\tconst ret = [];\n\n\t\tthis.fire( '_beforeChanges' );\n\n\t\twhile ( this._pendingChanges.length ) {\n\t\t\t// Create a new writer using batch instance created for this chain of changes.\n\t\t\tconst currentBatch = this._pendingChanges[ 0 ].batch;\n\t\t\tthis._currentWriter = new Writer( this, currentBatch );\n\n\t\t\t// Execute changes callback and gather the returned value.\n\t\t\tconst callbackReturnValue = this._pendingChanges[ 0 ].callback( this._currentWriter );\n\t\t\tret.push( callbackReturnValue );\n\n\t\t\tthis.document._handleChangeBlock( this._currentWriter );\n\n\t\t\tthis._pendingChanges.shift();\n\t\t\tthis._currentWriter = null;\n\t\t}\n\n\t\tthis.fire( '_afterChanges' );\n\n\t\treturn ret;\n\t}\n\n\t/**\n\t * Fired when entering the outermost {@link module:engine/model/model~Model#enqueueChange} or\n\t * {@link module:engine/model/model~Model#change} block.\n\t *\n\t * @protected\n\t * @event _beforeChanges\n\t */\n\n\t/**\n\t * Fired when leaving the outermost {@link module:engine/model/model~Model#enqueueChange} or\n\t * {@link module:engine/model/model~Model#change} block.\n\t *\n\t * @protected\n\t * @event _afterChanges\n\t */\n\n\t/**\n\t * Fired every time any {@link module:engine/model/operation/operation~Operation operation} is applied on the model\n\t * using {@link #applyOperation}.\n\t *\n\t * Note that this event is suitable only for very specific use-cases. Use it if you need to listen to every single operation\n\t * applied on the document. However, in most cases {@link module:engine/model/document~Document#event:change} should\n\t * be used.\n\t *\n\t * A few callbacks are already added to this event by engine internal classes:\n\t *\n\t * * with `highest` priority operation is validated,\n\t * * with `normal` priority operation is executed,\n\t * * with `low` priority the {@link module:engine/model/document~Document} updates its version,\n\t * * with `low` priority {@link module:engine/model/liveposition~LivePosition} and {@link module:engine/model/liverange~LiveRange}\n\t * update themselves.\n\t *\n\t * @event applyOperation\n\t * @param {Array} args Arguments of the `applyOperation` which is an array with a single element - applied\n\t * {@link module:engine/model/operation/operation~Operation operation}.\n\t */\n\n\t/**\n\t * Event fired when {@link #insertContent} method is called.\n\t *\n\t * The {@link #insertContent default action of that method} is implemented as a\n\t * listener to this event so it can be fully customized by the features.\n\t *\n\t * **Note** The `selectable` parameter for the {@link #insertContent} is optional. When `undefined` value is passed the method uses\n\t * `model.document.selection`.\n\t *\n\t * @event insertContent\n\t * @param {Array} args The arguments passed to the original method.\n\t */\n\n\t/**\n\t * Event fired when {@link #deleteContent} method is called.\n\t *\n\t * The {@link #deleteContent default action of that method} is implemented as a\n\t * listener to this event so it can be fully customized by the features.\n\t *\n\t * @event deleteContent\n\t * @param {Array} args The arguments passed to the original method.\n\t */\n\n\t/**\n\t * Event fired when {@link #modifySelection} method is called.\n\t *\n\t * The {@link #modifySelection default action of that method} is implemented as a\n\t * listener to this event so it can be fully customized by the features.\n\t *\n\t * @event modifySelection\n\t * @param {Array} args The arguments passed to the original method.\n\t */\n\n\t/**\n\t * Event fired when {@link #getSelectedContent} method is called.\n\t *\n\t * The {@link #getSelectedContent default action of that method} is implemented as a\n\t * listener to this event so it can be fully customized by the features.\n\t *\n\t * @event getSelectedContent\n\t * @param {Array} args The arguments passed to the original method.\n\t */\n}\n\nmix( Model, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/keystrokehandler\n */\n\nimport DomEmitterMixin from './dom/emittermixin';\nimport { getCode, parseKeystroke } from './keyboard';\n\n/**\n * Keystroke handler allows registering callbacks for given keystrokes.\n *\n * The most frequent use of this class is through the {@link module:core/editor/editor~Editor#keystrokes `editor.keystrokes`}\n * property. It allows listening to keystrokes executed in the editing view:\n *\n *\t\teditor.keystrokes.set( 'Ctrl+A', ( keyEvtData, cancel ) => {\n *\t\t\tconsole.log( 'Ctrl+A has been pressed' );\n *\t\t\tcancel();\n *\t\t} );\n *\n * However, this utility class can be used in various part of the UI. For instance, a certain {@link module:ui/view~View}\n * can use it like this:\n *\n *\t\tclass MyView extends View {\n *\t\t\tconstructor() {\n *\t\t\t\tthis.keystrokes = new KeystrokeHandler();\n *\n * \t\t\t\tthis.keystrokes.set( 'tab', handleTabKey );\n *\t\t\t}\n *\n *\t\t\trender() {\n *\t\t\t\tsuper.render();\n *\n *\t\t\t\tthis.keystrokes.listenTo( this.element );\n *\t\t\t}\n *\t\t}\n *\n * That keystroke handler will listen to `keydown` events fired in this view's main element.\n *\n */\nexport default class KeystrokeHandler {\n\t/**\n\t * Creates an instance of the keystroke handler.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Listener used to listen to events for easier keystroke handler destruction.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:utils/dom/emittermixin~Emitter}\n\t\t */\n\t\tthis._listener = Object.create( DomEmitterMixin );\n\t}\n\n\t/**\n\t * Starts listening for `keydown` events from a given emitter.\n\t *\n\t * @param {module:utils/emittermixin~Emitter} emitter\n\t */\n\tlistenTo( emitter ) {\n\t\t// The #_listener works here as a kind of dispatcher. It groups the events coming from the same\n\t\t// keystroke so the listeners can be attached to them with different priorities.\n\t\t//\n\t\t// E.g. all the keystrokes with the `keyCode` of 42 coming from the `emitter` are propagated\n\t\t// as a `_keydown:42` event by the `_listener`. If there's a callback created by the `set`\n\t\t// method for this 42 keystroke, it listens to the `_listener#_keydown:42` event only and interacts\n\t\t// only with other listeners of this particular event, thus making it possible to prioritize\n\t\t// the listeners and safely cancel execution, when needed. Instead of duplicating the Emitter logic,\n\t\t// the KeystrokeHandler re–uses it to do its job.\n\t\tthis._listener.listenTo( emitter, 'keydown', ( evt, keyEvtData ) => {\n\t\t\tthis._listener.fire( '_keydown:' + getCode( keyEvtData ), keyEvtData );\n\t\t} );\n\t}\n\n\t/**\n\t * Registers a handler for the specified keystroke.\n\t *\n\t * @param {String|Array.<String|Number>} keystroke Keystroke defined in a format accepted by\n\t * the {@link module:utils/keyboard~parseKeystroke} function.\n\t * @param {Function} callback A function called with the\n\t * {@link module:engine/view/observer/keyobserver~KeyEventData key event data} object and\n\t * a helper funcion to call both `preventDefault()` and `stopPropagation()` on the underlying event.\n\t * @param {Object} [options={}] Additional options.\n\t * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of the keystroke\n\t * callback. The higher the priority value the sooner the callback will be executed. Keystrokes having the same priority\n\t * are called in the order they were added.\n\t */\n\tset( keystroke, callback, options = {} ) {\n\t\tconst keyCode = parseKeystroke( keystroke );\n\t\tconst priority = options.priority;\n\n\t\t// Execute the passed callback on KeystrokeHandler#_keydown.\n\t\t// TODO: https://github.com/ckeditor/ckeditor5-utils/issues/144\n\t\tthis._listener.listenTo( this._listener, '_keydown:' + keyCode, ( evt, keyEvtData ) => {\n\t\t\tcallback( keyEvtData, () => {\n\t\t\t\t// Stop the event in the DOM: no listener in the web page\n\t\t\t\t// will be triggered by this event.\n\t\t\t\tkeyEvtData.preventDefault();\n\t\t\t\tkeyEvtData.stopPropagation();\n\n\t\t\t\t// Stop the event in the KeystrokeHandler: no more callbacks\n\t\t\t\t// will be executed for this keystroke.\n\t\t\t\tevt.stop();\n\t\t\t} );\n\n\t\t\t// Mark this keystroke as handled by the callback. See: #press.\n\t\t\tevt.return = true;\n\t\t}, { priority } );\n\t}\n\n\t/**\n\t * Triggers a keystroke handler for a specified key combination, if such a keystroke was {@link #set defined}.\n\t *\n\t * @param {module:engine/view/observer/keyobserver~KeyEventData} keyEvtData Key event data.\n\t * @returns {Boolean} Whether the keystroke was handled.\n\t */\n\tpress( keyEvtData ) {\n\t\treturn !!this._listener.fire( '_keydown:' + getCode( keyEvtData ), keyEvtData );\n\t}\n\n\t/**\n\t * Destroys the keystroke handler.\n\t */\n\tdestroy() {\n\t\tthis._listener.stopListening();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module core/editingkeystrokehandler\n */\n\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\n\n/**\n * A keystroke handler for editor editing. Its instance is available\n * in {@link module:core/editor/editor~Editor#keystrokes} so plugins\n * can register their keystrokes.\n *\n * E.g. an undo plugin would do this:\n *\n *\t\teditor.keystrokes.set( 'Ctrl+Z', 'undo' );\n *\t\teditor.keystrokes.set( 'Ctrl+Shift+Z', 'redo' );\n *\t\teditor.keystrokes.set( 'Ctrl+Y', 'redo' );\n *\n * @extends module:utils/keystrokehandler~KeystrokeHandler\n */\nexport default class EditingKeystrokeHandler extends KeystrokeHandler {\n\t/**\n\t * Creates an instance of the keystroke handler.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor\n\t */\n\tconstructor( editor ) {\n\t\tsuper();\n\n\t\t/**\n\t\t * The editor instance.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editor/editor~Editor}\n\t\t */\n\t\tthis.editor = editor;\n\t}\n\n\t/**\n\t * Registers a handler for the specified keystroke.\n\t *\n\t * The handler can be specified as a command name or a callback.\n\t *\n\t * @param {String|Array.<String|Number>} keystroke Keystroke defined in a format accepted by\n\t * the {@link module:utils/keyboard~parseKeystroke} function.\n\t * @param {Function|String} callback If a string is passed, then the keystroke will\n\t * {@link module:core/editor/editor~Editor#execute execute a command}.\n\t * If a function, then it will be called with the\n\t * {@link module:engine/view/observer/keyobserver~KeyEventData key event data} object and\n\t * a `cancel()` helper to both `preventDefault()` and `stopPropagation()` of the event.\n\t * @param {Object} [options={}] Additional options.\n\t * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of the keystroke\n\t * callback. The higher the priority value the sooner the callback will be executed. Keystrokes having the same priority\n\t * are called in the order they were added.\n\t */\n\tset( keystroke, callback, options = {} ) {\n\t\tif ( typeof callback == 'string' ) {\n\t\t\tconst commandName = callback;\n\n\t\t\tcallback = ( evtData, cancel ) => {\n\t\t\t\tthis.editor.execute( commandName );\n\t\t\t\tcancel();\n\t\t\t};\n\t\t}\n\n\t\tsuper.set( keystroke, callback, options );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module core/editor/editor\n */\n\nimport Context from '../context';\nimport Config from '@ckeditor/ckeditor5-utils/src/config';\nimport EditingController from '@ckeditor/ckeditor5-engine/src/controller/editingcontroller';\nimport PluginCollection from '../plugincollection';\nimport CommandCollection from '../commandcollection';\nimport DataController from '@ckeditor/ckeditor5-engine/src/controller/datacontroller';\nimport Conversion from '@ckeditor/ckeditor5-engine/src/conversion/conversion';\nimport Model from '@ckeditor/ckeditor5-engine/src/model/model';\nimport EditingKeystrokeHandler from '../editingkeystrokehandler';\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport { StylesProcessor } from '@ckeditor/ckeditor5-engine/src/view/stylesmap';\n\n/**\n * The class representing a basic, generic editor.\n *\n * Check out the list of its subclasses to learn about specific editor implementations.\n *\n * All editor implementations (like {@link module:editor-classic/classiceditor~ClassicEditor} or\n * {@link module:editor-inline/inlineeditor~InlineEditor}) should extend this class. They can add their\n * own methods and properties.\n *\n * When you are implementing a plugin, this editor represents the API\n * which your plugin can expect to get when using its {@link module:core/plugin~Plugin#editor} property.\n *\n * This API should be sufficient in order to implement the \"editing\" part of your feature\n * (schema definition, conversion, commands, keystrokes, etc.).\n * It does not define the editor UI, which is available only if\n * the specific editor implements also the {@link module:core/editor/editorwithui~EditorWithUI} interface\n * (as most editor implementations do).\n *\n * @abstract\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Editor {\n\t/**\n\t * Creates a new instance of the editor class.\n\t *\n\t * Usually, not to be used directly. See the static {@link module:core/editor/editor~Editor.create `create()`} method.\n\t *\n\t * @param {Object} [config={}] The editor configuration.\n\t */\n\tconstructor( config = {} ) {\n\t\t/**\n\t\t * The editor context.\n\t\t * When it is not provided through the configuration, the editor creates it.\n\t\t *\n\t\t * @protected\n\t\t * @type {module:core/context~Context}\n\t\t */\n\t\tthis._context = config.context || new Context( { language: config.language } );\n\t\tthis._context._addEditor( this, !config.context );\n\n\t\t// Clone the plugins to make sure that the plugin array will not be shared\n\t\t// between editors and make the watchdog feature work correctly.\n\t\tconst availablePlugins = Array.from( this.constructor.builtinPlugins || [] );\n\n\t\t/**\n\t\t * Stores all configurations specific to this editor instance.\n\t\t *\n\t\t *\t\teditor.config.get( 'image.toolbar' );\n\t\t *\t\t// -> [ 'imageStyle:full', 'imageStyle:side', '|', 'imageTextAlternative' ]\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/config~Config}\n\t\t */\n\t\tthis.config = new Config( config, this.constructor.defaultConfig );\n\t\tthis.config.define( 'plugins', availablePlugins );\n\t\tthis.config.define( this._context._getEditorConfig() );\n\n\t\t/**\n\t\t * The plugins loaded and in use by this editor instance.\n\t\t *\n\t\t *\t\teditor.plugins.get( 'Clipboard' ); // -> An instance of the clipboard plugin.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/plugincollection~PluginCollection}\n\t\t */\n\t\tthis.plugins = new PluginCollection( this, availablePlugins, this._context.plugins );\n\n\t\t/**\n\t\t * The locale instance.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:utils/locale~Locale}\n\t\t */\n\t\tthis.locale = this._context.locale;\n\n\t\t/**\n\t\t * Shorthand for {@link module:utils/locale~Locale#t}.\n\t\t *\n\t\t * @see module:utils/locale~Locale#t\n\t\t * @method #t\n\t\t */\n\t\tthis.t = this.locale.t;\n\n\t\t/**\n\t\t * Commands registered to the editor.\n\t\t *\n\t\t * Use the shorthand {@link #execute `editor.execute()`} method to execute commands:\n\t\t *\n\t\t *\t\t// Execute the bold command:\n\t\t *\t\teditor.execute( 'bold' );\n\t\t *\n\t\t *\t\t// Check the state of the bold command:\n\t\t *\t\teditor.commands.get( 'bold' ).value;\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/commandcollection~CommandCollection}\n\t\t */\n\t\tthis.commands = new CommandCollection();\n\n\t\t/**\n\t\t * Indicates the editor life-cycle state.\n\t\t *\n\t\t * The editor is in one of the following states:\n\t\t *\n\t\t * * `initializing` &ndash; During the editor initialization (before\n\t\t * {@link module:core/editor/editor~Editor.create `Editor.create()`}) finished its job.\n\t\t * * `ready` &ndash; After the promise returned by the {@link module:core/editor/editor~Editor.create `Editor.create()`}\n\t\t * method is resolved.\n\t\t * * `destroyed` &ndash; Once the {@link #destroy `editor.destroy()`} method was called.\n\t\t *\n\t\t * @observable\n\t\t * @member {'initializing'|'ready'|'destroyed'} #state\n\t\t */\n\t\tthis.set( 'state', 'initializing' );\n\t\tthis.once( 'ready', () => ( this.state = 'ready' ), { priority: 'high' } );\n\t\tthis.once( 'destroy', () => ( this.state = 'destroyed' ), { priority: 'high' } );\n\n\t\t/**\n\t\t * Defines whether this editor is in read-only mode.\n\t\t *\n\t\t * In read-only mode the editor {@link #commands commands} are disabled so it is not possible\n\t\t * to modify the document by using them. Also, the editable element(s) become non-editable.\n\t\t *\n\t\t * In order to make the editor read-only, you can set this value directly:\n\t\t *\n\t\t *\t\teditor.isReadOnly = true;\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isReadOnly\n\t\t */\n\t\tthis.set( 'isReadOnly', false );\n\n\t\t/**\n\t\t * The editor's model.\n\t\t *\n\t\t * The central point of the editor's abstract data model.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/model~Model}\n\t\t */\n\t\tthis.model = new Model();\n\n\t\tconst stylesProcessor = new StylesProcessor();\n\n\t\t/**\n\t\t * The {@link module:engine/controller/datacontroller~DataController data controller}.\n\t\t * Used e.g. for setting and retrieving the editor data.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/controller/datacontroller~DataController}\n\t\t */\n\t\tthis.data = new DataController( this.model, stylesProcessor );\n\n\t\t/**\n\t\t * The {@link module:engine/controller/editingcontroller~EditingController editing controller}.\n\t\t * Controls user input and rendering the content for editing.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/controller/editingcontroller~EditingController}\n\t\t */\n\t\tthis.editing = new EditingController( this.model, stylesProcessor );\n\t\tthis.editing.view.document.bind( 'isReadOnly' ).to( this );\n\n\t\t/**\n\t\t * Conversion manager through which you can register model-to-view and view-to-model converters.\n\t\t *\n\t\t * See the {@link module:engine/conversion/conversion~Conversion} documentation to learn how to add converters.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/conversion~Conversion}\n\t\t */\n\t\tthis.conversion = new Conversion( [ this.editing.downcastDispatcher, this.data.downcastDispatcher ], this.data.upcastDispatcher );\n\t\tthis.conversion.addAlias( 'dataDowncast', this.data.downcastDispatcher );\n\t\tthis.conversion.addAlias( 'editingDowncast', this.editing.downcastDispatcher );\n\n\t\t/**\n\t\t * An instance of the {@link module:core/editingkeystrokehandler~EditingKeystrokeHandler}.\n\t\t *\n\t\t * It allows setting simple keystrokes:\n\t\t *\n\t\t *\t\t// Execute the bold command on Ctrl+E:\n\t\t *\t\teditor.keystrokes.set( 'Ctrl+E', 'bold' );\n\t\t *\n\t\t *\t\t// Execute your own callback:\n\t\t *\t\teditor.keystrokes.set( 'Ctrl+E', ( data, cancel ) => {\n\t\t *\t\t\tconsole.log( data.keyCode );\n\t\t *\n\t\t *\t\t\t// Prevent the default (native) action and stop the underlying keydown event\n\t\t *\t\t\t// so no other editor feature will interfere.\n\t\t *\t\t\tcancel();\n\t\t *\t\t} );\n\t\t *\n\t\t * Note: Certain typing-oriented keystrokes (like <kbd>Backspace</kbd> or <kbd>Enter</kbd>) are handled\n\t\t * by a low-level mechanism and trying to listen to them via the keystroke handler will not work reliably.\n\t\t * To handle these specific keystrokes, see the events fired by the\n\t\t * {@link module:engine/view/document~Document editing view document} (`editor.editing.view.document`).\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editingkeystrokehandler~EditingKeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new EditingKeystrokeHandler( this );\n\t\tthis.keystrokes.listenTo( this.editing.view.document );\n\t}\n\n\t/**\n\t * Loads and initializes plugins specified in the configuration.\n\t *\n\t * @returns {Promise.<module:core/plugin~LoadedPlugins>} A promise which resolves\n\t * once the initialization is completed, providing an array of loaded plugins.\n\t */\n\tinitPlugins() {\n\t\tconst config = this.config;\n\t\tconst plugins = config.get( 'plugins' );\n\t\tconst removePlugins = config.get( 'removePlugins' ) || [];\n\t\tconst extraPlugins = config.get( 'extraPlugins' ) || [];\n\n\t\treturn this.plugins.init( plugins.concat( extraPlugins ), removePlugins );\n\t}\n\n\t/**\n\t * Destroys the editor instance, releasing all resources used by it.\n\t *\n\t * **Note** The editor cannot be destroyed during the initialization phase so if it is called\n\t * while the editor {@link #state is being initialized}, it will wait for the editor initialization before destroying it.\n\t *\n\t * @fires destroy\n\t * @returns {Promise} A promise that resolves once the editor instance is fully destroyed.\n\t */\n\tdestroy() {\n\t\tlet readyPromise = Promise.resolve();\n\n\t\tif ( this.state == 'initializing' ) {\n\t\t\treadyPromise = new Promise( resolve => this.once( 'ready', resolve ) );\n\t\t}\n\n\t\treturn readyPromise\n\t\t\t.then( () => {\n\t\t\t\tthis.fire( 'destroy' );\n\t\t\t\tthis.stopListening();\n\t\t\t\tthis.commands.destroy();\n\t\t\t} )\n\t\t\t.then( () => this.plugins.destroy() )\n\t\t\t.then( () => {\n\t\t\t\tthis.model.destroy();\n\t\t\t\tthis.data.destroy();\n\t\t\t\tthis.editing.destroy();\n\t\t\t\tthis.keystrokes.destroy();\n\t\t\t} )\n\t\t\t// Remove the editor from the context.\n\t\t\t// When the context was created by this editor, the context will be destroyed.\n\t\t\t.then( () => this._context._removeEditor( this ) );\n\t}\n\n\t/**\n\t * Executes the specified command with given parameters.\n\t *\n\t * Shorthand for:\n\t *\n\t *\t\teditor.commands.get( commandName ).execute( ... );\n\t *\n\t * @param {String} commandName The name of the command to execute.\n\t * @param {*} [...commandParams] Command parameters.\n\t * @returns {*} The value returned by the {@link module:core/commandcollection~CommandCollection#execute `commands.execute()`}.\n\t */\n\texecute( ...args ) {\n\t\ttry {\n\t\t\treturn this.commands.execute( ...args );\n\t\t} catch ( err ) {\n\t\t\t// @if CK_DEBUG // throw err;\n\t\t\t/* istanbul ignore next */\n\t\t\tCKEditorError.rethrowUnexpectedError( err, this );\n\t\t}\n\t}\n\n\t/**\n\t * Focuses the editor.\n\t *\n\t * **Note** To explicitly focus the editing area of the editor, use\n\t * {@link module:engine/view/view~View#focus `editor.editing.view.focus()`} method of the editing view.\n\t *\n\t * Check out the {@glink framework/guides/deep-dive/ui/focus-tracking#focus-in-the-editor-ui \"Focus in the editor ui\"} section\n\t * of the {@glink framework/guides/deep-dive/ui/focus-tracking \"Deep dive into focus tracking\" guide} to learn more.\n\t */\n\tfocus() {\n\t\tthis.editing.view.focus();\n\t}\n\n\t/**\n\t * Creates and initializes a new editor instance.\n\t *\n\t * This is an abstract method. Every editor type needs to implement its own initialization logic.\n\t *\n\t * See the `create()` methods of the existing editor types to learn how to use them:\n\t *\n\t * * {@link module:editor-classic/classiceditor~ClassicEditor.create `ClassicEditor.create()`}\n\t * * {@link module:editor-balloon/ballooneditor~BalloonEditor.create `BalloonEditor.create()`}\n\t * * {@link module:editor-decoupled/decouplededitor~DecoupledEditor.create `DecoupledEditor.create()`}\n\t * * {@link module:editor-inline/inlineeditor~InlineEditor.create `InlineEditor.create()`}\n\t *\n\t * @abstract\n\t * @method module:core/editor/editor~Editor.create\n\t */\n}\n\nmix( Editor, ObservableMixin );\n\n/**\n * Fired when the {@link module:engine/controller/datacontroller~DataController#event:ready data} and all additional\n * editor components are ready.\n *\n * Note: This event is most useful for plugin developers. When integrating the editor with your website or\n * application, you do not have to listen to `editor#ready` because when the promise returned by the static\n * {@link module:core/editor/editor~Editor.create `Editor.create()`} event is resolved, the editor is already ready.\n * In fact, since the first moment when the editor instance is available to you is inside `then()`'s callback,\n * you cannot even add a listener to the `editor#ready` event.\n *\n * See also the {@link #state `editor.state`} property.\n *\n * @event ready\n */\n\n/**\n * Fired when this editor instance is destroyed. The editor at this point is not usable and this event should be used to\n * perform the clean-up in any plugin.\n *\n *\n * See also the {@link #state `editor.state`} property.\n *\n * @event destroy\n */\n\n/**\n * This error is thrown when trying to pass a `<textarea>` element to a `create()` function of an editor class.\n *\n * The only editor type which can be initialized on `<textarea>` elements is {@glink builds/guides/overview#classic-editor classic editor}.\n * This editor hides the passed element and inserts its own UI next to it. Other types of editors reuse the passed element as their root\n * editable element and therefore `<textarea>` is not appropriate for them. Use a `<div>` or another text container instead:\n *\n *\t\t<div id=\"editor\">\n *\t\t\t<p>Initial content.</p>\n *\t\t</div>\n *\n * @error editor-wrong-element\n */\n\n/**\n * An array of plugins built into this editor class.\n *\n * It is used in CKEditor 5 builds to provide a list of plugins which are later automatically initialized\n * during the editor initialization.\n *\n * They will be automatically initialized by the editor, unless listed in `config.removePlugins` and\n * unless `config.plugins` is passed.\n *\n *\t\t// Build some plugins into the editor class first.\n *\t\tClassicEditor.builtinPlugins = [ FooPlugin, BarPlugin ];\n *\n *\t\t// Normally, you need to define config.plugins, but since ClassicEditor.builtinPlugins was\n *\t\t// defined, now you can call create() without any configuration.\n *\t\tClassicEditor\n *\t\t\t.create( sourceElement )\n *\t\t\t.then( editor => {\n *\t\t\t\teditor.plugins.get( FooPlugin ); // -> An instance of the Foo plugin.\n *\t\t\t\teditor.plugins.get( BarPlugin ); // -> An instance of the Bar plugin.\n *\t\t\t} );\n *\n *\t\tClassicEditor\n *\t\t\t.create( sourceElement, {\n *\t\t\t\t// Do not initialize these plugins (note: it is defined by a string):\n *\t\t\t\tremovePlugins: [ 'Foo' ]\n *\t\t\t} )\n *\t\t\t.then( editor => {\n *\t\t\t\teditor.plugins.get( FooPlugin ); // -> Undefined.\n *\t\t\t\teditor.config.get( BarPlugin ); // -> An instance of the Bar plugin.\n *\t\t\t} );\n *\n *\t\tClassicEditor\n *\t\t\t.create( sourceElement, {\n *\t\t\t\t// Load only this plugin. It can also be defined by a string if\n *\t\t\t\t// this plugin was built into the editor class.\n *\t\t\t\tplugins: [ FooPlugin ]\n *\t\t\t} )\n *\t\t\t.then( editor => {\n *\t\t\t\teditor.plugins.get( FooPlugin ); // -> An instance of the Foo plugin.\n *\t\t\t\teditor.config.get( BarPlugin ); // -> Undefined.\n *\t\t\t} );\n *\n * See also {@link module:core/editor/editor~Editor.defaultConfig}.\n *\n * @static\n * @member {Array.<Function>} module:core/editor/editor~Editor.builtinPlugins\n */\n\n/**\n * The default configuration which is built into the editor class.\n *\n * It is used in CKEditor 5 builds to provide the default configuration options which are later used during the editor initialization.\n *\n *\t\tClassicEditor.defaultConfig = {\n *\t\t\tfoo: 1,\n *\t\t\tbar: 2\n *\t\t};\n *\n *\t\tClassicEditor\n *\t\t\t.create( sourceElement )\n *\t\t\t.then( editor => {\n *\t\t\t\teditor.config.get( 'foo' ); // -> 1\n *\t\t\t\teditor.config.get( 'bar' ); // -> 2\n *\t\t\t} );\n *\n *\t\t// The default options can be overridden by the configuration passed to create().\n *\t\tClassicEditor\n *\t\t\t.create( sourceElement, { bar: 3 } )\n *\t\t\t.then( editor => {\n *\t\t\t\teditor.config.get( 'foo' ); // -> 1\n *\t\t\t\teditor.config.get( 'bar' ); // -> 3\n *\t\t\t} );\n *\n * See also {@link module:core/editor/editor~Editor.builtinPlugins}.\n *\n * @static\n * @member {Object} module:core/editor/editor~Editor.defaultConfig\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module core/editor/utils/dataapimixin\n */\n\n/**\n * Implementation of the {@link module:core/editor/utils/dataapimixin~DataApi}.\n *\n * @mixin DataApiMixin\n * @implements module:core/editor/utils/dataapimixin~DataApi\n */\nconst DataApiMixin = {\n\t/**\n\t * @inheritDoc\n\t */\n\tsetData( data ) {\n\t\tthis.data.set( data );\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tgetData( options ) {\n\t\treturn this.data.get( options );\n\t}\n};\n\nexport default DataApiMixin;\n\n/**\n * Interface defining editor methods for setting and getting data to and from the editor's main root element\n * using the {@link module:core/editor/editor~Editor#data data pipeline}.\n *\n * This interface is not a part of the {@link module:core/editor/editor~Editor} class because one may want to implement\n * an editor with multiple root elements, in which case the methods for setting and getting data will need to be implemented\n * differently.\n *\n * @interface DataApi\n */\n\n/**\n * Sets the data in the editor.\n *\n *\t\teditor.setData( '<p>This is editor!</p>' );\n *\n * By default the editor accepts HTML. This can be controlled by injecting a different data processor.\n * See the {@glink features/markdown Markdown output} guide for more details.\n *\n * Note: Not only is the format of the data configurable, but the type of the `setData()`'s parameter does not\n * have to be a string either. You can e.g. accept an object or a DOM `DocumentFragment` if you consider this\n * the right format for you.\n *\n * @method #setData\n * @param {String} data Input data.\n */\n\n/**\n * Gets the data from the editor.\n *\n *\t\teditor.getData(); // -> '<p>This is editor!</p>'\n *\n * By default the editor outputs HTML. This can be controlled by injecting a different data processor.\n * See the {@glink features/markdown Markdown output} guide for more details.\n *\n * Note: Not only is the format of the data configurable, but the type of the `getData()`'s return value does not\n * have to be a string either. You can e.g. return an object or a DOM `DocumentFragment` if you consider this\n * the right format for you.\n *\n * @method #getData\n * @param {Object} [options] Additional configuration for the retrieved data.\n * Editor features may introduce more configuration options that can be set through this parameter.\n * @param {String} [options.rootName='main'] Root name.\n * @param {String} [options.trim='empty'] Whether returned data should be trimmed. This option is set to `'empty'` by default,\n * which means that whenever editor content is considered empty, an empty string is returned. To turn off trimming\n * use `'none'`. In such cases exact content will be returned (for example `'<p>&nbsp;</p>'` for an empty editor).\n * @returns {String} Output data.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport setDataInElement from '@ckeditor/ckeditor5-utils/src/dom/setdatainelement';\n\n/**\n * @module core/editor/utils/elementapimixin\n */\n\n/**\n * Implementation of the {@link module:core/editor/utils/elementapimixin~ElementApi}.\n *\n * @mixin ElementApiMixin\n * @implements module:core/editor/utils/elementapimixin~ElementApi\n */\nconst ElementApiMixin = {\n\t/**\n\t * @inheritDoc\n\t */\n\tupdateSourceElement() {\n\t\tif ( !this.sourceElement ) {\n\t\t\t/**\n\t\t\t * Cannot update the source element of a detached editor.\n\t\t\t *\n\t\t\t * The {@link ~ElementApi#updateSourceElement `updateSourceElement()`} method cannot be called if you did not\n\t\t\t * pass an element to `Editor.create()`.\n\t\t\t *\n\t\t\t * @error editor-missing-sourceelement\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'editor-missing-sourceelement',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tsetDataInElement( this.sourceElement, this.data.get() );\n\t}\n};\n\nexport default ElementApiMixin;\n\n/**\n * Interface describing an editor that replaced a DOM element (was \"initialized on an element\").\n *\n * Such an editor should provide a method to\n * {@link module:core/editor/utils/elementapimixin~ElementApi#updateSourceElement update the replaced element with the current data}.\n *\n * @interface ElementApi\n */\n\n/**\n * The element on which the editor has been initialized.\n *\n * @readonly\n * @member {HTMLElement} #sourceElement\n */\n\n/**\n * Updates the {@link #sourceElement editor source element}'s content with the data.\n *\n * @method #updateSourceElement\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/setdatainelement\n */\n\n/* globals HTMLTextAreaElement */\n\n/**\n * Sets data in a given element.\n *\n * @param {HTMLElement} el The element in which the data will be set.\n * @param {String} data The data string.\n */\nexport default function setDataInElement( el, data ) {\n\tif ( el instanceof HTMLTextAreaElement ) {\n\t\tel.value = data;\n\t}\n\n\tel.innerHTML = data;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/dataprocessor/basichtmlwriter\n */\n\n/* globals document */\n\n/**\n * Basic HTML writer. It uses the native `innerHTML` property for basic conversion\n * from a document fragment to an HTML string.\n *\n * @implements module:engine/dataprocessor/htmlwriter~HtmlWriter\n */\nexport default class BasicHtmlWriter {\n\t/**\n\t * Returns an HTML string created from the document fragment.\n\t *\n\t * @param {DocumentFragment} fragment\n\t * @returns {String}\n\t */\n\tgetHtml( fragment ) {\n\t\tconst doc = document.implementation.createHTMLDocument( '' );\n\t\tconst container = doc.createElement( 'div' );\n\t\tcontainer.appendChild( fragment );\n\n\t\treturn container.innerHTML;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/dataprocessor/htmldataprocessor\n */\n\n/* globals document, DOMParser */\n\nimport BasicHtmlWriter from './basichtmlwriter';\nimport DomConverter from '../view/domconverter';\n\n/**\n * The HTML data processor class.\n * This data processor implementation uses HTML as input and output data.\n *\n * @implements module:engine/dataprocessor/dataprocessor~DataProcessor\n */\nexport default class HtmlDataProcessor {\n\t/**\n\t * Creates a new instance of the HTML data processor class.\n\t *\n\t * @param {module:engine/view/document~Document} document The view document instance.\n\t */\n\tconstructor( document ) {\n\t\t/**\n\t\t * A DOM parser instance used to parse an HTML string to an HTML document.\n\t\t *\n\t\t * @private\n\t\t * @member {DOMParser}\n\t\t */\n\t\tthis._domParser = new DOMParser();\n\n\t\t/**\n\t\t * A DOM converter used to convert DOM elements to view elements.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/view/domconverter~DomConverter}\n\t\t */\n\t\tthis._domConverter = new DomConverter( document, { blockFillerMode: 'nbsp' } );\n\n\t\t/**\n\t\t * A basic HTML writer instance used to convert DOM elements to an HTML string.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/dataprocessor/basichtmlwriter~BasicHtmlWriter}\n\t\t */\n\t\tthis._htmlWriter = new BasicHtmlWriter();\n\t}\n\n\t/**\n\t * Converts a provided {@link module:engine/view/documentfragment~DocumentFragment document fragment}\n\t * to data format &mdash; in this case to an HTML string.\n\t *\n\t * @param {module:engine/view/documentfragment~DocumentFragment} viewFragment\n\t * @returns {String} HTML string.\n\t */\n\ttoData( viewFragment ) {\n\t\t// Convert view DocumentFragment to DOM DocumentFragment.\n\t\tconst domFragment = this._domConverter.viewToDom( viewFragment, document );\n\n\t\t// Convert DOM DocumentFragment to HTML output.\n\t\treturn this._htmlWriter.getHtml( domFragment );\n\t}\n\n\t/**\n\t * Converts the provided HTML string to a view tree.\n\t *\n\t * @param {String} data An HTML string.\n\t * @returns {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment|null} A converted view element.\n\t */\n\ttoView( data ) {\n\t\t// Convert input HTML data to DOM DocumentFragment.\n\t\tconst domFragment = this._toDom( data );\n\n\t\t// Convert DOM DocumentFragment to view DocumentFragment.\n\t\treturn this._domConverter.domToView( domFragment );\n\t}\n\n\t/**\n\t * Registers a {@link module:engine/view/matcher~MatcherPattern} for view elements whose content should be treated as a raw data\n\t * and not processed during conversion from DOM to view elements.\n\t *\n\t * The raw data can be later accessed by {@link module:engine/view/element~Element#getCustomProperty view element custom property}\n\t * `\"$rawContent\"`.\n\t *\n\t * @param {module:engine/view/matcher~MatcherPattern} pattern Pattern matching all view elements whose content should\n\t * be treated as a raw data.\n\t */\n\tregisterRawContentMatcher( pattern ) {\n\t\tthis._domConverter.registerRawContentMatcher( pattern );\n\t}\n\n\t/**\n\t * Converts an HTML string to its DOM representation. Returns a document fragment containing nodes parsed from\n\t * the provided data.\n\t *\n\t * @private\n\t * @param {String} data\n\t * @returns {DocumentFragment}\n\t */\n\t_toDom( data ) {\n\t\tconst document = this._domParser.parseFromString( data, 'text/html' );\n\t\tconst fragment = document.createDocumentFragment();\n\t\tconst nodes = document.body.childNodes;\n\n\t\twhile ( nodes.length > 0 ) {\n\t\t\tfragment.appendChild( nodes[ 0 ] );\n\t\t}\n\n\t\treturn fragment;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/componentfactory\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * A helper class implementing the UI component ({@link module:ui/view~View view}) factory.\n *\n * It allows functions producing specific UI components to be registered under their unique names\n * in the factory. A registered component can be then instantiated by providing its name.\n * Note that names are case insensitive.\n *\n *\t\t// The editor provides localization tools for the factory.\n *\t\tconst factory = new ComponentFactory( editor );\n *\n *\t\tfactory.add( 'foo', locale => new FooView( locale ) );\n *\t\tfactory.add( 'bar', locale => new BarView( locale ) );\n *\n *\t\t// An instance of FooView.\n *\t\tconst fooInstance = factory.create( 'foo' );\n *\n *\t\t// Names are case insensitive so this is also allowed:\n *\t\tconst barInstance = factory.create( 'Bar' );\n *\n * The {@link module:core/editor/editor~Editor#locale editor locale} is passed to the factory\n * function when {@link module:ui/componentfactory~ComponentFactory#create} is called.\n */\nexport default class ComponentFactory {\n\t/**\n\t * Creates an instance of the factory.\n\t *\n\t * @constructor\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t */\n\tconstructor( editor ) {\n\t\t/**\n\t\t * The editor instance that the factory belongs to.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editor/editor~Editor}\n\t\t */\n\t\tthis.editor = editor;\n\n\t\t/**\n\t\t * Registered component factories.\n\t\t *\n\t\t * @private\n\t\t * @member {Map}\n\t\t */\n\t\tthis._components = new Map();\n\t}\n\n\t/**\n\t * Returns an iterator of registered component names. Names are returned in lower case.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\t* names() {\n\t\tfor ( const value of this._components.values() ) {\n\t\t\tyield value.originalName;\n\t\t}\n\t}\n\n\t/**\n\t * Registers a component factory function that will be used by the\n\t * {@link #create create} method and called with the\n\t * {@link module:core/editor/editor~Editor#locale editor locale} as an argument,\n\t * allowing localization of the {@link module:ui/view~View view}.\n\t *\n\t * @param {String} name The name of the component.\n\t * @param {Function} callback The callback that returns the component.\n\t */\n\tadd( name, callback ) {\n\t\tthis._components.set( getNormalized( name ), { callback, originalName: name } );\n\t}\n\n\t/**\n\t * Creates an instance of a component registered in the factory under a specific name.\n\t *\n\t * When called, the {@link module:core/editor/editor~Editor#locale editor locale} is passed to\n\t * the previously {@link #add added} factory function, allowing localization of the\n\t * {@link module:ui/view~View view}.\n\t *\n\t * @param {String} name The name of the component.\n\t * @returns {module:ui/view~View} The instantiated component view.\n\t */\n\tcreate( name ) {\n\t\tif ( !this.has( name ) ) {\n\t\t\t/**\n\t\t\t * The required component is not registered in the component factory. Please make sure\n\t\t\t * the provided name is correct and the component has been correctly\n\t\t\t * {@link #add added} to the factory.\n\t\t\t *\n\t\t\t * @error componentfactory-item-missing\n\t\t\t * @param {String} name The name of the missing component.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'componentfactory-item-missing',\n\t\t\t\tthis,\n\t\t\t\t{ name }\n\t\t\t);\n\t\t}\n\n\t\treturn this._components.get( getNormalized( name ) ).callback( this.editor.locale );\n\t}\n\n\t/**\n\t * Checks if a component of a given name is registered in the factory.\n\t *\n\t * @param {String} name The name of the component.\n\t * @returns {Boolean}\n\t */\n\thas( name ) {\n\t\treturn this._components.has( getNormalized( name ) );\n\t}\n}\n\n//\n// Ensures that the component name used as the key in the internal map is in lower case.\n//\n// @private\n// @param {String} name\n// @returns {String}\nfunction getNormalized( name ) {\n\treturn String( name ).toLowerCase();\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* global setTimeout, clearTimeout */\n\n/**\n * @module utils/focustracker\n */\n\nimport DomEmitterMixin from './dom/emittermixin';\nimport ObservableMixin from './observablemixin';\nimport CKEditorError from './ckeditorerror';\nimport mix from './mix';\n\n/**\n * Allows observing a group of `HTMLElement`s whether at least one of them is focused.\n *\n * Used by the {@link module:core/editor/editor~Editor} in order to track whether the focus is still within the application,\n * or were used outside of its UI.\n *\n * **Note** `focus` and `blur` listeners use event capturing, so it is only needed to register wrapper `HTMLElement`\n * which contain other `focusable` elements. But note that this wrapper element has to be focusable too\n * (have e.g. `tabindex=\"-1\"`).\n *\n * Check out the {@glink framework/guides/deep-dive/ui/focus-tracking \"Deep dive into focus tracking\" guide} to learn more.\n *\n * @mixes module:utils/dom/emittermixin~EmitterMixin\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class FocusTracker {\n\tconstructor() {\n\t\t/**\n\t\t * True when one of the registered elements is focused.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isFocused\n\t\t */\n\t\tthis.set( 'isFocused', false );\n\n\t\t/**\n\t\t * The currently focused element.\n\t\t *\n\t\t * While {@link #isFocused `isFocused`} remains `true`, the focus can\n\t\t * move between different UI elements. This property tracks those\n\t\t * elements and tells which one is currently focused.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {HTMLElement|null} #focusedElement\n\t\t */\n\t\tthis.set( 'focusedElement', null );\n\n\t\t/**\n\t\t * List of registered elements.\n\t\t *\n\t\t * @private\n\t\t * @member {Set.<HTMLElement>}\n\t\t */\n\t\tthis._elements = new Set();\n\n\t\t/**\n\t\t * Event loop timeout.\n\t\t *\n\t\t * @private\n\t\t * @member {Number}\n\t\t */\n\t\tthis._nextEventLoopTimeout = null;\n\t}\n\n\t/**\n\t * Starts tracking the specified element.\n\t *\n\t * @param {HTMLElement} element\n\t */\n\tadd( element ) {\n\t\tif ( this._elements.has( element ) ) {\n\t\t\t/**\n\t\t\t * This element is already tracked by {@link module:utils/focustracker~FocusTracker}.\n\t\t\t *\n\t\t\t * @error focustracker-add-element-already-exist\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'focustracker-add-element-already-exist', this );\n\t\t}\n\n\t\tthis.listenTo( element, 'focus', () => this._focus( element ), { useCapture: true } );\n\t\tthis.listenTo( element, 'blur', () => this._blur(), { useCapture: true } );\n\t\tthis._elements.add( element );\n\t}\n\n\t/**\n\t * Stops tracking the specified element and stops listening on this element.\n\t *\n\t * @param {HTMLElement} element\n\t */\n\tremove( element ) {\n\t\tif ( element === this.focusedElement ) {\n\t\t\tthis._blur( element );\n\t\t}\n\n\t\tif ( this._elements.has( element ) ) {\n\t\t\tthis.stopListening( element );\n\t\t\tthis._elements.delete( element );\n\t\t}\n\t}\n\n\t/**\n\t * Destroys the focus tracker by:\n\t * - Disabling all event listeners attached to tracked elements.\n\t * - Removing all tracked elements that were previously added.\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Stores currently focused element and set {#isFocused} as `true`.\n\t *\n\t * @private\n\t * @param {HTMLElement} element Element which has been focused.\n\t */\n\t_focus( element ) {\n\t\tclearTimeout( this._nextEventLoopTimeout );\n\n\t\tthis.focusedElement = element;\n\t\tthis.isFocused = true;\n\t}\n\n\t/**\n\t * Clears currently focused element and set {@link #isFocused} as `false`.\n\t * This method uses `setTimeout` to change order of fires `blur` and `focus` events.\n\t *\n\t * @private\n\t * @fires blur\n\t */\n\t_blur() {\n\t\tclearTimeout( this._nextEventLoopTimeout );\n\n\t\tthis._nextEventLoopTimeout = setTimeout( () => {\n\t\t\tthis.focusedElement = null;\n\t\t\tthis.isFocused = false;\n\t\t}, 0 );\n\t}\n\n\t/**\n\t * @event focus\n\t */\n\n\t/**\n\t * @event blur\n\t */\n}\n\nmix( FocusTracker, DomEmitterMixin );\nmix( FocusTracker, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module core/editor/editorui\n */\n\n/* globals console */\n\nimport ComponentFactory from '@ckeditor/ckeditor5-ui/src/componentfactory';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\n\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * A class providing the minimal interface that is required to successfully bootstrap any editor UI.\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class EditorUI {\n\t/**\n\t * Creates an instance of the editor UI class.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t */\n\tconstructor( editor ) {\n\t\t/**\n\t\t * The editor that the UI belongs to.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editor/editor~Editor} #editor\n\t\t */\n\t\tthis.editor = editor;\n\n\t\t/**\n\t\t * An instance of the {@link module:ui/componentfactory~ComponentFactory}, a registry used by plugins\n\t\t * to register factories of specific UI components.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/componentfactory~ComponentFactory} #componentFactory\n\t\t */\n\t\tthis.componentFactory = new ComponentFactory( editor );\n\n\t\t/**\n\t\t * Stores the information about the editor UI focus and propagates it so various plugins and components\n\t\t * are unified as a focus group.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker} #focusTracker\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * Stores all editable elements used by the editor instance.\n\t\t *\n\t\t * @private\n\t\t * @member {Map.<String,HTMLElement>}\n\t\t */\n\t\tthis._editableElementsMap = new Map();\n\n\t\t// Informs UI components that should be refreshed after layout change.\n\t\tthis.listenTo( editor.editing.view.document, 'layoutChanged', () => this.update() );\n\t}\n\n\t/**\n\t * The main (outermost) DOM element of the editor UI.\n\t *\n\t * For example, in {@link module:editor-classic/classiceditor~ClassicEditor} it is a `<div>` which\n\t * wraps the editable element and the toolbar. In {@link module:editor-inline/inlineeditor~InlineEditor}\n\t * it is the editable element itself (as there is no other wrapper). However, in\n\t * {@link module:editor-decoupled/decouplededitor~DecoupledEditor} it is set to `null` because this editor does not\n\t * come with a single \"main\" HTML element (its editable element and toolbar are separate).\n\t *\n\t * This property can be understood as a shorthand for retrieving the element that a specific editor integration\n\t * considers to be its main DOM element.\n\t *\n\t * @readonly\n\t * @member {HTMLElement|null} #element\n\t */\n\tget element() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Fires the {@link module:core/editor/editorui~EditorUI#event:update `update`} event.\n\t *\n\t * This method should be called when the editor UI (e.g. positions of its balloons) needs to be updated due to\n\t * some environmental change which CKEditor 5 is not aware of (e.g. resize of a container in which it is used).\n\t */\n\tupdate() {\n\t\tthis.fire( 'update' );\n\t}\n\n\t/**\n\t * Destroys the UI.\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\n\t\tthis.focusTracker.destroy();\n\n\t\t// Clean–up the references to the CKEditor instance stored in the native editable DOM elements.\n\t\tfor ( const domElement of this._editableElementsMap.values() ) {\n\t\t\tdomElement.ckeditorInstance = null;\n\t\t}\n\n\t\tthis._editableElementsMap = new Map();\n\t}\n\n\t/**\n\t * Store the native DOM editable element used by the editor under\n\t * a unique name.\n\t *\n\t * @param {String} rootName The unique name of the editable element.\n\t * @param {HTMLElement} domElement The native DOM editable element.\n\t */\n\tsetEditableElement( rootName, domElement ) {\n\t\tthis._editableElementsMap.set( rootName, domElement );\n\n\t\t// Put a reference to the CKEditor instance in the editable native DOM element.\n\t\t// It helps 3rd–party software (browser extensions, other libraries) access and recognize\n\t\t// CKEditor 5 instances (editing roots) and use their API (there is no global editor\n\t\t// instance registry).\n\t\tif ( !domElement.ckeditorInstance ) {\n\t\t\tdomElement.ckeditorInstance = this.editor;\n\t\t}\n\t}\n\n\t/**\n\t * Returns the editable editor element with the given name or null if editable does not exist.\n\t *\n\t * @param {String} [rootName=main] The editable name.\n\t * @returns {HTMLElement|undefined}\n\t */\n\tgetEditableElement( rootName = 'main' ) {\n\t\treturn this._editableElementsMap.get( rootName );\n\t}\n\n\t/**\n\t * Returns array of names of all editor editable elements.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetEditableElementsNames() {\n\t\treturn this._editableElementsMap.keys();\n\t}\n\n\t/**\n\t * Stores all editable elements used by the editor instance.\n\t *\n\t * @protected\n\t * @deprecated\n\t * @member {Map.<String,HTMLElement>}\n\t */\n\tget _editableElements() {\n\t\t/**\n\t\t * The {@link module:core/editor/editorui~EditorUI#_editableElements `EditorUI#_editableElements`} property has been\n\t\t * deprecated and will be removed in the near future. Please use {@link #setEditableElement `setEditableElement()`} and\n\t\t * {@link #getEditableElement `getEditableElement()`} methods instead.\n\t\t *\n\t\t * @error editor-ui-deprecated-editable-elements\n\t\t * @param {module:core/editor/editorui~EditorUI} editorUI Editor UI instance the deprecated property belongs to.\n\t\t */\n\t\tconsole.warn(\n\t\t\t'editor-ui-deprecated-editable-elements: ' +\n\t\t\t'The EditorUI#_editableElements property has been deprecated and will be removed in the near future.',\n\t\t\t{ editorUI: this } );\n\n\t\treturn this._editableElementsMap;\n\t}\n\n\t/**\n\t * Fired when the editor UI is ready.\n\t *\n\t * Fired before {@link module:engine/controller/datacontroller~DataController#event:ready}.\n\t *\n\t * @event ready\n\t */\n\n\t/**\n\t * Fired whenever the UI (all related components) should be refreshed.\n\t *\n\t * **Note:**: The event is fired after each {@link module:engine/view/document~Document#event:layoutChanged}.\n\t * It can also be fired manually via the {@link module:core/editor/editorui~EditorUI#update} method.\n\t *\n\t * @event update\n\t */\n}\n\nmix( EditorUI, EmitterMixin );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/placeholder\n */\n\nimport '../../theme/placeholder.css';\n\n// Each document stores information about its placeholder elements and check functions.\nconst documentPlaceholders = new WeakMap();\n\n/**\n * A helper that enables a placeholder on the provided view element (also updates its visibility).\n * The placeholder is a CSS pseudo–element (with a text content) attached to the element.\n *\n * To change the placeholder text, simply call this method again with new options.\n *\n * To disable the placeholder, use {@link module:engine/view/placeholder~disablePlaceholder `disablePlaceholder()`} helper.\n *\n * @param {Object} [options] Configuration options of the placeholder.\n * @param {module:engine/view/view~View} options.view Editing view instance.\n * @param {module:engine/view/element~Element} options.element Element that will gain a placeholder.\n * See `options.isDirectHost` to learn more.\n * @param {String} options.text Placeholder text.\n * @param {Boolean} [options.isDirectHost=true] If set `false`, the placeholder will not be enabled directly\n * in the passed `element` but in one of its children (selected automatically, i.e. a first empty child element).\n * Useful when attaching placeholders to elements that can host other elements (not just text), for instance,\n * editable root elements.\n */\nexport function enablePlaceholder( options ) {\n\tconst { view, element, text, isDirectHost = true } = options;\n\tconst doc = view.document;\n\n\t// Use a single a single post fixer per—document to update all placeholders.\n\tif ( !documentPlaceholders.has( doc ) ) {\n\t\tdocumentPlaceholders.set( doc, new Map() );\n\n\t\t// If a post-fixer callback makes a change, it should return `true` so other post–fixers\n\t\t// can re–evaluate the document again.\n\t\tdoc.registerPostFixer( writer => updateDocumentPlaceholders( doc, writer ) );\n\t}\n\n\t// Store information about the element placeholder under its document.\n\tdocumentPlaceholders.get( doc ).set( element, {\n\t\ttext,\n\t\tisDirectHost\n\t} );\n\n\t// Update the placeholders right away.\n\tview.change( writer => updateDocumentPlaceholders( doc, writer ) );\n}\n\n/**\n * Disables the placeholder functionality from a given element.\n *\n * See {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`} to learn more.\n *\n * @param {module:engine/view/view~View} view\n * @param {module:engine/view/element~Element} element\n */\nexport function disablePlaceholder( view, element ) {\n\tconst doc = element.document;\n\n\tview.change( writer => {\n\t\tif ( !documentPlaceholders.has( doc ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst placeholders = documentPlaceholders.get( doc );\n\t\tconst config = placeholders.get( element );\n\n\t\twriter.removeAttribute( 'data-placeholder', config.hostElement );\n\t\thidePlaceholder( writer, config.hostElement );\n\n\t\tplaceholders.delete( element );\n\t} );\n}\n\n/**\n * Shows a placeholder in the provided element by changing related attributes and CSS classes.\n *\n * **Note**: This helper will not update the placeholder visibility nor manage the\n * it in any way in the future. What it does is a one–time state change of an element. Use\n * {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`} and\n * {@link module:engine/view/placeholder~disablePlaceholder `disablePlaceholder()`} for full\n * placeholder functionality.\n *\n * **Note**: This helper will blindly show the placeholder directly in the root editable element if\n * one is passed, which could result in a visual clash if the editable element has some children\n * (for instance, an empty paragraph). Use {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`}\n * in that case or make sure the correct element is passed to the helper.\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {module:engine/view/element~Element} element\n * @returns {Boolean} `true`, if any changes were made to the `element`.\n */\nexport function showPlaceholder( writer, element ) {\n\tif ( !element.hasClass( 'ck-placeholder' ) ) {\n\t\twriter.addClass( 'ck-placeholder', element );\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n/**\n * Hides a placeholder in the element by changing related attributes and CSS classes.\n *\n * **Note**: This helper will not update the placeholder visibility nor manage the\n * it in any way in the future. What it does is a one–time state change of an element. Use\n * {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`} and\n * {@link module:engine/view/placeholder~disablePlaceholder `disablePlaceholder()`} for full\n * placeholder functionality.\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {module:engine/view/element~Element} element\n * @returns {Boolean} `true`, if any changes were made to the `element`.\n */\nexport function hidePlaceholder( writer, element ) {\n\tif ( element.hasClass( 'ck-placeholder' ) ) {\n\t\twriter.removeClass( 'ck-placeholder', element );\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n/**\n * Checks if a placeholder should be displayed in the element.\n *\n * **Note**: This helper will blindly check the possibility of showing a placeholder directly in the\n * root editable element if one is passed, which may not be the expected result. If an element can\n * host other elements (not just text), most likely one of its children should be checked instead\n * because it will be the final host for the placeholder. Use\n * {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`} in that case or make\n * sure the correct element is passed to the helper.\n *\n * @param {module:engine/view/element~Element} element\n * @returns {Boolean}\n */\nexport function needsPlaceholder( element ) {\n\tif ( !element.isAttached() ) {\n\t\treturn false;\n\t}\n\n\t// The element is empty only as long as it contains nothing but uiElements.\n\tconst isEmptyish = !Array.from( element.getChildren() )\n\t\t.some( element => !element.is( 'uiElement' ) );\n\n\tconst doc = element.document;\n\n\t// If the element is empty and the document is blurred.\n\tif ( !doc.isFocused && isEmptyish ) {\n\t\treturn true;\n\t}\n\n\tconst viewSelection = doc.selection;\n\tconst selectionAnchor = viewSelection.anchor;\n\n\t// If document is focused and the element is empty but the selection is not anchored inside it.\n\tif ( isEmptyish && selectionAnchor && selectionAnchor.parent !== element ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n// Updates all placeholders associated with a document in a post–fixer callback.\n//\n// @private\n// @param { module:engine/view/document~Document} doc\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @returns {Boolean} True if any changes were made to the view document.\nfunction updateDocumentPlaceholders( doc, writer ) {\n\tconst placeholders = documentPlaceholders.get( doc );\n\tlet wasViewModified = false;\n\n\tfor ( const [ element, config ] of placeholders ) {\n\t\tif ( updatePlaceholder( writer, element, config ) ) {\n\t\t\twasViewModified = true;\n\t\t}\n\t}\n\n\treturn wasViewModified;\n}\n\n// Updates a single placeholder in a post–fixer callback.\n//\n// @private\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @param {module:engine/view/element~Element} element\n// @param {Object} config Configuration of the placeholder\n// @param {String} config.text\n// @param {Boolean} config.isDirectHost\n// @returns {Boolean} True if any changes were made to the view document.\nfunction updatePlaceholder( writer, element, config ) {\n\tconst { text, isDirectHost } = config;\n\n\tconst hostElement = isDirectHost ? element : getChildPlaceholderHostSubstitute( element );\n\tlet wasViewModified = false;\n\n\t// When not a direct host, it could happen that there is no child element\n\t// capable of displaying a placeholder.\n\tif ( !hostElement ) {\n\t\treturn false;\n\t}\n\n\t// Cache the host element. It will be necessary for disablePlaceholder() to know\n\t// which element should have class and attribute removed because, depending on\n\t// the config.isDirectHost value, it could be the element or one of its descendants.\n\tconfig.hostElement = hostElement;\n\n\t// This may be necessary when updating the placeholder text to something else.\n\tif ( hostElement.getAttribute( 'data-placeholder' ) !== text ) {\n\t\twriter.setAttribute( 'data-placeholder', text, hostElement );\n\t\twasViewModified = true;\n\t}\n\n\tif ( needsPlaceholder( hostElement ) ) {\n\t\tif ( showPlaceholder( writer, hostElement ) ) {\n\t\t\twasViewModified = true;\n\t\t}\n\t} else if ( hidePlaceholder( writer, hostElement ) ) {\n\t\twasViewModified = true;\n\t}\n\n\treturn wasViewModified;\n}\n\n// Gets a child element capable of displaying a placeholder if a parent element can host more\n// than just text (for instance, when it is a root editable element). The child element\n// can then be used in other placeholder helpers as a substitute of its parent.\n//\n// @private\n// @param {module:engine/view/element~Element} parent\n// @returns {module:engine/view/element~Element|null}\nfunction getChildPlaceholderHostSubstitute( parent ) {\n\tif ( parent.childCount === 1 ) {\n\t\tconst firstChild = parent.getChild( 0 );\n\n\t\tif ( firstChild.is( 'element' ) && !firstChild.is( 'uiElement' ) ) {\n\t\t\treturn firstChild;\n\t\t}\n\t}\n\n\treturn null;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/elementreplacer\n */\n\n/**\n * Utility class allowing to hide existing HTML elements or replace them with given ones in a way that doesn't remove\n * the original elements from the DOM.\n */\nexport default class ElementReplacer {\n\tconstructor() {\n\t\t/**\n\t\t * The elements replaced by {@link #replace} and their replacements.\n\t\t *\n\t\t * @private\n\t\t * @member {Array.<Object>}\n\t\t */\n\t\tthis._replacedElements = [];\n\t}\n\n\t/**\n\t * Hides the `element` and, if specified, inserts the the given element next to it.\n\t *\n\t * The effect of this method can be reverted by {@link #restore}.\n\t *\n\t * @param {HTMLElement} element The element to replace.\n\t * @param {HTMLElement} [newElement] The replacement element. If not passed, then the `element` will just be hidden.\n\t */\n\treplace( element, newElement ) {\n\t\tthis._replacedElements.push( { element, newElement } );\n\n\t\telement.style.display = 'none';\n\n\t\tif ( newElement ) {\n\t\t\telement.parentNode.insertBefore( newElement, element.nextSibling );\n\t\t}\n\t}\n\n\t/**\n\t * Restores what {@link #replace} did.\n\t */\n\trestore() {\n\t\tthis._replacedElements.forEach( ( { element, newElement } ) => {\n\t\t\telement.style.display = '';\n\n\t\t\tif ( newElement ) {\n\t\t\t\tnewElement.remove();\n\t\t\t}\n\t\t} );\n\n\t\tthis._replacedElements = [];\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module editor-classic/classiceditorui\n */\n\nimport EditorUI from '@ckeditor/ckeditor5-core/src/editor/editorui';\nimport enableToolbarKeyboardFocus from '@ckeditor/ckeditor5-ui/src/toolbar/enabletoolbarkeyboardfocus';\nimport normalizeToolbarConfig from '@ckeditor/ckeditor5-ui/src/toolbar/normalizetoolbarconfig';\nimport { enablePlaceholder } from '@ckeditor/ckeditor5-engine/src/view/placeholder';\nimport ElementReplacer from '@ckeditor/ckeditor5-utils/src/elementreplacer';\n\n/**\n * The classic editor UI class.\n *\n * @extends module:core/editor/editorui~EditorUI\n */\nexport default class ClassicEditorUI extends EditorUI {\n\t/**\n\t * Creates an instance of the classic editor UI class.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t * @param {module:ui/editorui/editoruiview~EditorUIView} view The view of the UI.\n\t */\n\tconstructor( editor, view ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The main (top–most) view of the editor UI.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/editorui/editoruiview~EditorUIView} #view\n\t\t */\n\t\tthis.view = view;\n\n\t\t/**\n\t\t * A normalized `config.toolbar` object.\n\t\t *\n\t\t * @private\n\t\t * @member {Object}\n\t\t */\n\t\tthis._toolbarConfig = normalizeToolbarConfig( editor.config.get( 'toolbar' ) );\n\n\t\t/**\n\t\t * The element replacer instance used to hide the editor's source element.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:utils/elementreplacer~ElementReplacer}\n\t\t */\n\t\tthis._elementReplacer = new ElementReplacer();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget element() {\n\t\treturn this.view.element;\n\t}\n\n\t/**\n\t * Initializes the UI.\n\t *\n\t * @param {HTMLElement|null} replacementElement The DOM element that will be the source for the created editor.\n\t */\n\tinit( replacementElement ) {\n\t\tconst editor = this.editor;\n\t\tconst view = this.view;\n\t\tconst editingView = editor.editing.view;\n\t\tconst editable = view.editable;\n\t\tconst editingRoot = editingView.document.getRoot();\n\n\t\t// The editable UI and editing root should share the same name. Then name is used\n\t\t// to recognize the particular editable, for instance in ARIA attributes.\n\t\teditable.name = editingRoot.rootName;\n\n\t\tview.render();\n\n\t\t// The editable UI element in DOM is available for sure only after the editor UI view has been rendered.\n\t\t// But it can be available earlier if a DOM element has been passed to BalloonEditor.create().\n\t\tconst editableElement = editable.element;\n\n\t\t// Register the editable UI view in the editor. A single editor instance can aggregate multiple\n\t\t// editable areas (roots) but the classic editor has only one.\n\t\tthis.setEditableElement( editable.name, editableElement );\n\n\t\t// Let the global focus tracker know that the editable UI element is focusable and\n\t\t// belongs to the editor. From now on, the focus tracker will sustain the editor focus\n\t\t// as long as the editable is focused (e.g. the user is typing).\n\t\tthis.focusTracker.add( editableElement );\n\n\t\t// Let the editable UI element respond to the changes in the global editor focus\n\t\t// tracker. It has been added to the same tracker a few lines above but, in reality, there are\n\t\t// many focusable areas in the editor, like balloons, toolbars or dropdowns and as long\n\t\t// as they have focus, the editable should act like it is focused too (although technically\n\t\t// it isn't), e.g. by setting the proper CSS class, visually announcing focus to the user.\n\t\t// Doing otherwise will result in editable focus styles disappearing, once e.g. the\n\t\t// toolbar gets focused.\n\t\tview.editable.bind( 'isFocused' ).to( this.focusTracker );\n\n\t\t// Bind the editable UI element to the editing view, making it an end– and entry–point\n\t\t// of the editor's engine. This is where the engine meets the UI.\n\t\teditingView.attachDomRoot( editableElement );\n\n\t\t// If an element containing the initial data of the editor was provided, replace it with\n\t\t// an editor instance's UI in DOM until the editor is destroyed. For instance, a <textarea>\n\t\t// can be such element.\n\t\tif ( replacementElement ) {\n\t\t\tthis._elementReplacer.replace( replacementElement, this.element );\n\t\t}\n\n\t\tthis._initPlaceholder();\n\t\tthis._initToolbar();\n\t\tthis.fire( 'ready' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tconst view = this.view;\n\t\tconst editingView = this.editor.editing.view;\n\n\t\tthis._elementReplacer.restore();\n\t\teditingView.detachDomRoot( view.editable.name );\n\t\tview.destroy();\n\n\t\tsuper.destroy();\n\t}\n\n\t/**\n\t * Initializes the editor toolbar.\n\t *\n\t * @private\n\t */\n\t_initToolbar() {\n\t\tconst editor = this.editor;\n\t\tconst view = this.view;\n\t\tconst editingView = editor.editing.view;\n\n\t\t// Set–up the sticky panel with toolbar.\n\t\tview.stickyPanel.bind( 'isActive' ).to( this.focusTracker, 'isFocused' );\n\t\tview.stickyPanel.limiterElement = view.element;\n\n\t\tif ( this._toolbarConfig.viewportTopOffset ) {\n\t\t\tview.stickyPanel.viewportTopOffset = this._toolbarConfig.viewportTopOffset;\n\t\t}\n\n\t\tview.toolbar.fillFromConfig( this._toolbarConfig.items, this.componentFactory );\n\n\t\tenableToolbarKeyboardFocus( {\n\t\t\torigin: editingView,\n\t\t\toriginFocusTracker: this.focusTracker,\n\t\t\toriginKeystrokeHandler: editor.keystrokes,\n\t\t\ttoolbar: view.toolbar\n\t\t} );\n\t}\n\n\t/**\n\t * Enable the placeholder text on the editing root, if any was configured.\n\t *\n\t * @private\n\t */\n\t_initPlaceholder() {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\t\tconst editingRoot = editingView.document.getRoot();\n\t\tconst sourceElement = editor.sourceElement;\n\n\t\tconst placeholderText = editor.config.get( 'placeholder' ) ||\n\t\t\tsourceElement && sourceElement.tagName.toLowerCase() === 'textarea' && sourceElement.getAttribute( 'placeholder' );\n\n\t\tif ( placeholderText ) {\n\t\t\tenablePlaceholder( {\n\t\t\t\tview: editingView,\n\t\t\t\telement: editingRoot,\n\t\t\t\ttext: placeholderText,\n\t\t\t\tisDirectHost: false\n\t\t\t} );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/toolbar/normalizetoolbarconfig\n */\n\n/**\n * Normalizes the toolbar configuration (`config.toolbar`), which:\n *\n * * may be defined as an `Array`:\n *\n * \t\ttoolbar: [ 'heading', 'bold', 'italic', 'link', ... ]\n *\n * * or an `Object`:\n *\n *\t\ttoolbar: {\n *\t\t\titems: [ 'heading', 'bold', 'italic', 'link', ... ],\n *\t\t\t...\n *\t\t}\n *\n * * or may not be defined at all (`undefined`)\n *\n * and returns it in the object form.\n *\n * @param {Array|Object|undefined} config The value of `config.toolbar`.\n * @returns {Object} A normalized toolbar config object.\n */\nexport default function normalizeToolbarConfig( config ) {\n\tif ( Array.isArray( config ) ) {\n\t\treturn {\n\t\t\titems: config\n\t\t};\n\t}\n\n\tif ( !config ) {\n\t\treturn {\n\t\t\titems: []\n\t\t};\n\t}\n\n\treturn Object.assign( {\n\t\titems: []\n\t}, config );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/toolbar/enabletoolbarkeyboardfocus\n */\n\n/**\n * Enables focus/blur toolbar navigation using `Alt+F10` and `Esc` keystrokes.\n *\n * @param {Object} options Options of the utility.\n * @param {*} options.origin A view to which the focus will return when `Esc` is pressed and\n * `options.toolbar` is focused.\n * @param {module:utils/keystrokehandler~KeystrokeHandler} options.originKeystrokeHandler A keystroke\n * handler to register `Alt+F10` keystroke.\n * @param {module:utils/focustracker~FocusTracker} options.originFocusTracker A focus tracker\n * for `options.origin`.\n * @param {module:ui/toolbar/toolbarview~ToolbarView} options.toolbar A toolbar which is to gain\n * focus when `Alt+F10` is pressed.\n * @param {Function} [options.beforeFocus] A callback executed before the `options.toolbar` gains focus\n * upon the `Alt+F10` keystroke.\n * @param {Function} [options.afterBlur] A callback executed after `options.toolbar` loses focus upon\n * `Esc` keystroke but before the focus goes back to `options.origin`.\n */\nexport default function enableToolbarKeyboardFocus( {\n\torigin,\n\toriginKeystrokeHandler,\n\toriginFocusTracker,\n\ttoolbar,\n\tbeforeFocus,\n\tafterBlur\n} ) {\n\t// Because toolbar items can get focus, the overall state of the toolbar must\n\t// also be tracked.\n\toriginFocusTracker.add( toolbar.element );\n\n\t// Focus the toolbar on the keystroke, if not already focused.\n\toriginKeystrokeHandler.set( 'Alt+F10', ( data, cancel ) => {\n\t\tif ( originFocusTracker.isFocused && !toolbar.focusTracker.isFocused ) {\n\t\t\tif ( beforeFocus ) {\n\t\t\t\tbeforeFocus();\n\t\t\t}\n\n\t\t\ttoolbar.focus();\n\n\t\t\tcancel();\n\t\t}\n\t} );\n\n\t// Blur the toolbar and bring the focus back to origin.\n\ttoolbar.keystrokes.set( 'Esc', ( data, cancel ) => {\n\t\tif ( toolbar.focusTracker.isFocused ) {\n\t\t\torigin.focus();\n\n\t\t\tif ( afterBlur ) {\n\t\t\t\tafterBlur();\n\t\t\t}\n\n\t\t\tcancel();\n\t\t}\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/viewcollection\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\n\n/**\n * Collects {@link module:ui/view~View} instances.\n *\n *\t\tconst parentView = new ParentView( locale );\n *\t\tconst collection = new ViewCollection( locale );\n *\n *\t\tcollection.setParent( parentView.element );\n *\n *\t\tconst viewA = new ChildView( locale );\n *\t\tconst viewB = new ChildView( locale );\n *\n * View collection renders and manages view {@link module:ui/view~View#element elements}:\n *\n *\t\tcollection.add( viewA );\n *\t\tcollection.add( viewB );\n *\n *\t\tconsole.log( parentView.element.firsChild ); // -> viewA.element\n *\t\tconsole.log( parentView.element.lastChild ); // -> viewB.element\n *\n * It {@link module:ui/viewcollection~ViewCollection#delegate propagates} DOM events too:\n *\n *\t\t// Delegate #click and #keydown events from viewA and viewB to the parentView.\n *\t\tcollection.delegate( 'click' ).to( parentView );\n *\n *\t\tparentView.on( 'click', ( evt ) => {\n *\t\t\tconsole.log( `${ evt.source } has been clicked.` );\n *\t\t} );\n *\n *\t\t// This event will be delegated to the parentView.\n *\t\tviewB.fire( 'click' );\n *\n * **Note**: A view collection can be used directly in the {@link module:ui/template~TemplateDefinition definition}\n * of a {@link module:ui/template~Template template}.\n *\n * @extends module:utils/collection~Collection\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class ViewCollection extends Collection {\n\t/**\n\t * Creates a new instance of the {@link module:ui/viewcollection~ViewCollection}.\n\t *\n\t * @param {Iterable.<module:ui/view~View>} [initialItems] The initial items of the collection.\n\t */\n\tconstructor( initialItems = [] ) {\n\t\tsuper( initialItems, {\n\t\t\t// An #id Number attribute should be legal and not break the `ViewCollection` instance.\n\t\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/93\n\t\t\tidProperty: 'viewUid'\n\t\t} );\n\n\t\t// Handle {@link module:ui/view~View#element} in DOM when a new view is added to the collection.\n\t\tthis.on( 'add', ( evt, view, index ) => {\n\t\t\tthis._renderViewIntoCollectionParent( view, index );\n\t\t} );\n\n\t\t// Handle {@link module:ui/view~View#element} in DOM when a view is removed from the collection.\n\t\tthis.on( 'remove', ( evt, view ) => {\n\t\t\tif ( view.element && this._parentElement ) {\n\t\t\t\tview.element.remove();\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * A parent element within which child views are rendered and managed in DOM.\n\t\t *\n\t\t * @protected\n\t\t * @member {HTMLElement}\n\t\t */\n\t\tthis._parentElement = null;\n\t}\n\n\t/**\n\t * Destroys the view collection along with child views.\n\t * See the view {@link module:ui/view~View#destroy} method.\n\t */\n\tdestroy() {\n\t\tthis.map( view => view.destroy() );\n\t}\n\n\t/**\n\t * Sets the parent HTML element of this collection. When parent is set, {@link #add adding} and\n\t * {@link #remove removing} views in the collection synchronizes their\n\t * {@link module:ui/view~View#element elements} in the parent element.\n\t *\n\t * @param {HTMLElement} element A new parent element.\n\t */\n\tsetParent( elementOrDocFragment ) {\n\t\tthis._parentElement = elementOrDocFragment;\n\n\t\t// Take care of the initial collection items passed to the constructor.\n\t\tfor ( const view of this ) {\n\t\t\tthis._renderViewIntoCollectionParent( view );\n\t\t}\n\t}\n\n\t/**\n\t * Delegates selected events coming from within views in the collection to any\n\t * {@link module:utils/emittermixin~Emitter}.\n\t *\n\t * For the following views and collection:\n\t *\n\t *\t\tconst viewA = new View();\n\t *\t\tconst viewB = new View();\n\t *\t\tconst viewC = new View();\n\t *\n\t *\t\tconst views = parentView.createCollection();\n\t *\n\t *\t\tviews.delegate( 'eventX' ).to( viewB );\n\t *\t\tviews.delegate( 'eventX', 'eventY' ).to( viewC );\n\t *\n\t *\t\tviews.add( viewA );\n\t *\n\t * the `eventX` is delegated (fired by) `viewB` and `viewC` along with `customData`:\n\t *\n\t *\t\tviewA.fire( 'eventX', customData );\n\t *\n\t * and `eventY` is delegated (fired by) `viewC` along with `customData`:\n\t *\n\t *\t\tviewA.fire( 'eventY', customData );\n\t *\n\t * See {@link module:utils/emittermixin~Emitter#delegate}.\n\t *\n\t * @param {...String} events {@link module:ui/view~View} event names to be delegated to another\n\t * {@link module:utils/emittermixin~Emitter}.\n\t * @returns {Object}\n\t * @returns {Function} return.to A function which accepts the destination of\n\t * {@link module:utils/emittermixin~Emitter#delegate delegated} events.\n\t */\n\tdelegate( ...events ) {\n\t\tif ( !events.length || !isStringArray( events ) ) {\n\t\t\t/**\n\t\t\t * All event names must be strings.\n\t\t\t *\n\t\t\t * @error ui-viewcollection-delegate-wrong-events\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'ui-viewcollection-delegate-wrong-events',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\t/**\n\t\t\t * Selects destination for {@link module:utils/emittermixin~Emitter#delegate} events.\n\t\t\t *\n\t\t\t * @memberOf module:ui/viewcollection~ViewCollection#delegate\n\t\t\t * @function module:ui/viewcollection~ViewCollection#delegate.to\n\t\t\t * @param {module:utils/emittermixin~Emitter} dest An `Emitter` instance which is\n\t\t\t * the destination for delegated events.\n\t\t\t */\n\t\t\tto: dest => {\n\t\t\t\t// Activate delegating on existing views in this collection.\n\t\t\t\tfor ( const view of this ) {\n\t\t\t\t\tfor ( const evtName of events ) {\n\t\t\t\t\t\tview.delegate( evtName ).to( dest );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Activate delegating on future views in this collection.\n\t\t\t\tthis.on( 'add', ( evt, view ) => {\n\t\t\t\t\tfor ( const evtName of events ) {\n\t\t\t\t\t\tview.delegate( evtName ).to( dest );\n\t\t\t\t\t}\n\t\t\t\t} );\n\n\t\t\t\t// Deactivate delegating when view is removed from this collection.\n\t\t\t\tthis.on( 'remove', ( evt, view ) => {\n\t\t\t\t\tfor ( const evtName of events ) {\n\t\t\t\t\t\tview.stopDelegating( evtName, dest );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * This method {@link module:ui/view~View#render renders} a new view added to the collection.\n\t *\n\t * If the {@link #_parentElement parent element} of the collection is set, this method also adds\n\t * the view's {@link module:ui/view~View#element} as a child of the parent in DOM at a specified index.\n\t *\n\t * **Note**: If index is not specified, the view's element is pushed as the last child\n\t * of the parent element.\n\t *\n\t * @private\n\t * @param {module:ui/view~View} view A new view added to the collection.\n\t * @param {Number} [index] An index the view holds in the collection. When not specified,\n\t * the view is added at the end.\n\t */\n\t_renderViewIntoCollectionParent( view, index ) {\n\t\tif ( !view.isRendered ) {\n\t\t\tview.render();\n\t\t}\n\n\t\tif ( view.element && this._parentElement ) {\n\t\t\tthis._parentElement.insertBefore( view.element, this._parentElement.children[ index ] );\n\t\t}\n\t}\n\n\t/**\n\t * Removes a child view from the collection. If the {@link #setParent parent element} of the\n\t * collection has been set, the {@link module:ui/view~View#element element} of the view is also removed\n\t * in DOM, reflecting the order of the collection.\n\t *\n\t * See the {@link #add} method.\n\t *\n\t * @method #remove\n\t * @param {module:ui/view~View|Number|String} subject The view to remove, its id or index in the collection.\n\t * @returns {Object} The removed view.\n\t */\n}\n\n// Check if all entries of the array are of `String` type.\n//\n// @private\n// @param {Array} arr An array to be checked.\n// @returns {Boolean}\nfunction isStringArray( arr ) {\n\treturn arr.every( a => typeof a == 'string' );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/template\n */\n\n/* global document */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport View from './view';\nimport ViewCollection from './viewcollection';\nimport isNode from '@ckeditor/ckeditor5-utils/src/dom/isnode';\nimport { isObject, cloneDeepWith } from 'lodash-es';\nimport toArray from '@ckeditor/ckeditor5-utils/src/toarray';\n\nconst xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n/**\n * A basic Template class. It renders a DOM HTML element or text from a\n * {@link module:ui/template~TemplateDefinition definition} and supports element attributes, children,\n * bindings to {@link module:utils/observablemixin~Observable observables} and DOM event propagation.\n *\n * A simple template can look like this:\n *\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\t\t\tattributes: {\n *\t\t\t\tclass: 'foo',\n *\t\t\t\tstyle: {\n *\t\t\t\t\tbackgroundColor: 'yellow'\n *\t\t\t\t}\n *\t\t\t},\n *\t\t\ton: {\n *\t\t\t\tclick: bind.to( 'clicked' )\n *\t\t\t},\n *\t\t\tchildren: [\n *\t\t\t\t'A paragraph.'\n *\t\t\t]\n *\t\t} ).render();\n *\n * and it will render the following HTML element:\n *\n *\t\t<p class=\"foo\" style=\"background-color: yellow;\">A paragraph.</p>\n *\n * Additionally, the `observable` will always fire `clicked` upon clicking `<p>` in the DOM.\n *\n * See {@link module:ui/template~TemplateDefinition} to know more about templates and complex\n * template definitions.\n *\n* @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class Template {\n\t/**\n\t * Creates an instance of the {@link ~Template} class.\n\t *\n\t * @param {module:ui/template~TemplateDefinition} def The definition of the template.\n\t */\n\tconstructor( def ) {\n\t\tObject.assign( this, normalize( clone( def ) ) );\n\n\t\t/**\n\t\t * Indicates whether this particular Template instance has been\n\t\t * {@link #render rendered}.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._isRendered = false;\n\n\t\t/**\n\t\t * The tag (`tagName`) of this template, e.g. `div`. It also indicates that the template\n\t\t * renders to an HTML element.\n\t\t *\n\t\t * @member {String} #tag\n\t\t */\n\n\t\t/**\n\t\t * The text of the template. It also indicates that the template renders to a DOM text node.\n\t\t *\n\t\t * @member {Array.<String|module:ui/template~TemplateValueSchema>} #text\n\t\t */\n\n\t\t/**\n\t\t * The attributes of the template, e.g. `{ id: [ 'ck-id' ] }`, corresponding with\n\t\t * the attributes of an HTML element.\n\t\t *\n\t\t * **Note**: This property only makes sense when {@link #tag} is defined.\n\t\t *\n\t\t * @member {Object} #attributes\n\t\t */\n\n\t\t/**\n\t\t * The children of the template. They can be either:\n\t\t * * independent instances of {@link ~Template} (sub–templates),\n\t\t * * native DOM Nodes.\n\t\t *\n\t\t * **Note**: This property only makes sense when {@link #tag} is defined.\n\t\t *\n\t\t * @member {Array.<module:ui/template~Template|Node>} #children\n\t\t */\n\n\t\t/**\n\t\t * The DOM event listeners of the template.\n\t\t *\n\t\t * @member {Object} #eventListeners\n\t\t */\n\n\t\t/**\n\t\t * The data used by the {@link #revert} method to restore a node to its original state.\n\t\t *\n\t\t * See: {@link #apply}.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/template~RenderData}\n\t\t */\n\t\tthis._revertData = null;\n\t}\n\n\t/**\n\t * Renders a DOM Node (an HTML element or text) out of the template.\n\t *\n\t *\t\tconst domNode = new Template( { ... } ).render();\n\t *\n\t * See: {@link #apply}.\n\t *\n\t * @returns {HTMLElement|Text}\n\t */\n\trender() {\n\t\tconst node = this._renderNode( {\n\t\t\tintoFragment: true\n\t\t} );\n\n\t\tthis._isRendered = true;\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Applies the template to an existing DOM Node, either HTML element or text.\n\t *\n\t * **Note:** No new DOM nodes will be created. Applying extends:\n\t *\n\t * {@link module:ui/template~TemplateDefinition attributes},\n\t * {@link module:ui/template~TemplateDefinition event listeners}, and\n\t * `textContent` of {@link module:ui/template~TemplateDefinition children} only.\n\t *\n\t * **Note:** Existing `class` and `style` attributes are extended when a template\n\t * is applied to an HTML element, while other attributes and `textContent` are overridden.\n\t *\n\t * **Note:** The process of applying a template can be easily reverted using the\n\t * {@link module:ui/template~Template#revert} method.\n\t *\n\t *\t\tconst element = document.createElement( 'div' );\n\t *\t\tconst observable = new Model( { divClass: 'my-div' } );\n\t *\t\tconst emitter = Object.create( EmitterMixin );\n\t *\t\tconst bind = Template.bind( observable, emitter );\n\t *\n\t *\t\tnew Template( {\n\t *\t\t\tattributes: {\n\t *\t\t\t\tid: 'first-div',\n\t *\t\t\t\tclass: bind.to( 'divClass' )\n\t *\t\t\t},\n\t *\t\t\ton: {\n\t *\t\t\t\tclick: bind( 'elementClicked' ) // Will be fired by the observable.\n\t *\t\t\t},\n\t *\t\t\tchildren: [\n\t *\t\t\t\t'Div text.'\n\t *\t\t\t]\n\t *\t\t} ).apply( element );\n\t *\n\t *\t\tconsole.log( element.outerHTML ); // -> '<div id=\"first-div\" class=\"my-div\"></div>'\n\t *\n\t * @see module:ui/template~Template#render\n\t * @see module:ui/template~Template#revert\n\t * @param {Node} node Root node for the template to apply.\n\t */\n\tapply( node ) {\n\t\tthis._revertData = getEmptyRevertData();\n\n\t\tthis._renderNode( {\n\t\t\tnode,\n\t\t\tisApplying: true,\n\t\t\trevertData: this._revertData\n\t\t} );\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Reverts a template {@link module:ui/template~Template#apply applied} to a DOM node.\n\t *\n\t * @param {Node} node The root node for the template to revert. In most of the cases, it is the\n\t * same node used by {@link module:ui/template~Template#apply}.\n\t */\n\trevert( node ) {\n\t\tif ( !this._revertData ) {\n\t\t\t/**\n\t\t\t * Attempting to revert a template which has not been applied yet.\n\t\t\t *\n\t\t\t * @error ui-template-revert-not-applied\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'ui-template-revert-not-applied',\n\t\t\t\t[ this, node ]\n\t\t\t);\n\t\t}\n\n\t\tthis._revertTemplateFromNode( node, this._revertData );\n\t}\n\n\t/**\n\t * Returns an iterator which traverses the template in search of {@link module:ui/view~View}\n\t * instances and returns them one by one.\n\t *\n\t *\t\tconst viewFoo = new View();\n\t *\t\tconst viewBar = new View();\n\t *\t\tconst viewBaz = new View();\n\t *\t\tconst template = new Template( {\n\t *\t\t\ttag: 'div',\n\t *\t\t\tchildren: [\n\t *\t\t\t\tviewFoo,\n\t *\t\t\t\t{\n\t *\t\t\t\t\ttag: 'div',\n\t *\t\t\t\t\tchildren: [\n\t *\t\t\t\t\t\tviewBar\n\t *\t\t\t\t\t]\n\t *\t\t\t\t},\n\t *\t\t\t\tviewBaz\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t *\t\t// Logs: viewFoo, viewBar, viewBaz\n\t *\t\tfor ( const view of template.getViews() ) {\n\t *\t\t\tconsole.log( view );\n\t *\t\t}\n\t *\n\t * @returns {Iterable.<module:ui/view~View>}\n\t */\n\t* getViews() {\n\t\tfunction* search( def ) {\n\t\t\tif ( def.children ) {\n\t\t\t\tfor ( const child of def.children ) {\n\t\t\t\t\tif ( isView( child ) ) {\n\t\t\t\t\t\tyield child;\n\t\t\t\t\t} else if ( isTemplate( child ) ) {\n\t\t\t\t\t\tyield* search( child );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tyield* search( this );\n\t}\n\n\t/**\n\t * An entry point to the interface which binds DOM nodes to\n\t * {@link module:utils/observablemixin~Observable observables}.\n\t * There are two types of bindings:\n\t *\n\t * * HTML element attributes or text `textContent` synchronized with attributes of an\n\t * {@link module:utils/observablemixin~Observable}. Learn more about {@link module:ui/template~BindChain#to}\n\t * and {@link module:ui/template~BindChain#if}.\n\t *\n\t *\t\tconst bind = Template.bind( observable, emitter );\n\t *\n\t *\t\tnew Template( {\n\t *\t\t\tattributes: {\n\t *\t\t\t\t// Binds the element \"class\" attribute to observable#classAttribute.\n\t *\t\t\t\tclass: bind.to( 'classAttribute' )\n\t *\t\t\t}\n\t *\t\t} ).render();\n\t *\n\t * * DOM events fired on HTML element propagated through\n\t * {@link module:utils/observablemixin~Observable}. Learn more about {@link module:ui/template~BindChain#to}.\n\t *\n\t *\t\tconst bind = Template.bind( observable, emitter );\n\t *\n\t *\t\tnew Template( {\n\t *\t\t\ton: {\n\t *\t\t\t\t// Will be fired by the observable.\n\t *\t\t\t\tclick: bind( 'elementClicked' )\n\t *\t\t\t}\n\t *\t\t} ).render();\n\t *\n\t * Also see {@link module:ui/view~View#bindTemplate}.\n\t *\n\t * @param {module:utils/observablemixin~Observable} observable An observable which provides boundable attributes.\n\t * @param {module:utils/emittermixin~Emitter} emitter An emitter that listens to observable attribute\n\t * changes or DOM Events (depending on the kind of the binding). Usually, a {@link module:ui/view~View} instance.\n\t * @returns {module:ui/template~BindChain}\n\t */\n\tstatic bind( observable, emitter ) {\n\t\treturn {\n\t\t\tto( eventNameOrFunctionOrAttribute, callback ) {\n\t\t\t\treturn new TemplateToBinding( {\n\t\t\t\t\teventNameOrFunction: eventNameOrFunctionOrAttribute,\n\t\t\t\t\tattribute: eventNameOrFunctionOrAttribute,\n\t\t\t\t\tobservable, emitter, callback\n\t\t\t\t} );\n\t\t\t},\n\n\t\t\tif( attribute, valueIfTrue, callback ) {\n\t\t\t\treturn new TemplateIfBinding( {\n\t\t\t\t\tobservable, emitter, attribute, valueIfTrue, callback\n\t\t\t\t} );\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Extends an existing {@link module:ui/template~Template} instance with some additional content\n\t * from another {@link module:ui/template~TemplateDefinition}.\n\t *\n\t *\t\tconst bind = Template.bind( observable, emitter );\n\t *\n\t *\t\tconst template = new Template( {\n\t *\t\t\ttag: 'p',\n\t *\t\t\tattributes: {\n\t *\t\t\t\tclass: 'a',\n\t *\t\t\t\tdata-x: bind.to( 'foo' )\n\t *\t\t\t},\n\t *\t\t\tchildren: [\n\t *\t\t\t\t{\n\t *\t\t\t\t\ttag: 'span',\n\t *\t\t\t\t\tattributes: {\n\t *\t\t\t\t\t\tclass: 'b'\n\t *\t\t\t\t\t},\n\t *\t\t\t\t\tchildren: [\n\t *\t\t\t\t\t\t'Span'\n\t *\t\t\t\t\t]\n\t *\t\t\t\t}\n\t *\t\t\t]\n\t *\t\t } );\n\t *\n\t *\t\t// Instance-level extension.\n\t *\t\tTemplate.extend( template, {\n\t *\t\t\tattributes: {\n\t *\t\t\t\tclass: 'b',\n\t *\t\t\t\tdata-x: bind.to( 'bar' )\n\t *\t\t\t},\n\t *\t\t\tchildren: [\n\t *\t\t\t\t{\n\t *\t\t\t\t\tattributes: {\n\t *\t\t\t\t\t\tclass: 'c'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t *\t\t// Child extension.\n\t *\t\tTemplate.extend( template.children[ 0 ], {\n\t *\t\t\tattributes: {\n\t *\t\t\t\tclass: 'd'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * the `outerHTML` of `template.render()` is:\n\t *\n\t *\t\t<p class=\"a b\" data-x=\"{ observable.foo } { observable.bar }\">\n\t *\t\t\t<span class=\"b c d\">Span</span>\n\t *\t\t</p>\n\t *\n\t * @param {module:ui/template~Template} template An existing template instance to be extended.\n\t * @param {module:ui/template~TemplateDefinition} def Additional definition to be applied to a template.\n\t */\n\tstatic extend( template, def ) {\n\t\tif ( template._isRendered ) {\n\t\t\t/**\n\t\t\t * Extending a template after rendering may not work as expected. To make sure\n\t\t\t * the {@link module:ui/template~Template.extend extending} works for an element,\n\t\t\t * make sure it happens before {@link #render} is called.\n\t\t\t *\n\t\t\t * @error template-extend-render\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'template-extend-render',\n\t\t\t\t[ this, template ]\n\t\t\t);\n\t\t}\n\n\t\textendTemplate( template, normalize( clone( def ) ) );\n\t}\n\n\t/**\n\t * Renders a DOM Node (either an HTML element or text) out of the template.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderNode( data ) {\n\t\tlet isInvalid;\n\n\t\tif ( data.node ) {\n\t\t\t// When applying, a definition cannot have \"tag\" and \"text\" at the same time.\n\t\t\tisInvalid = this.tag && this.text;\n\t\t} else {\n\t\t\t// When rendering, a definition must have either \"tag\" or \"text\": XOR( this.tag, this.text ).\n\t\t\tisInvalid = this.tag ? this.text : !this.text;\n\t\t}\n\n\t\tif ( isInvalid ) {\n\t\t\t/**\n\t\t\t * Node definition cannot have the \"tag\" and \"text\" properties at the same time.\n\t\t\t * Node definition must have either \"tag\" or \"text\" when rendering a new Node.\n\t\t\t *\n\t\t\t * @error ui-template-wrong-syntax\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'ui-template-wrong-syntax',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tif ( this.text ) {\n\t\t\treturn this._renderText( data );\n\t\t} else {\n\t\t\treturn this._renderElement( data );\n\t\t}\n\t}\n\n\t/**\n\t * Renders an HTML element out of the template.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderElement( data ) {\n\t\tlet node = data.node;\n\n\t\tif ( !node ) {\n\t\t\tnode = data.node = document.createElementNS( this.ns || xhtmlNs, this.tag );\n\t\t}\n\n\t\tthis._renderAttributes( data );\n\t\tthis._renderElementChildren( data );\n\t\tthis._setUpListeners( data );\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Renders a text node out of {@link module:ui/template~Template#text}.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderText( data ) {\n\t\tlet node = data.node;\n\n\t\t// Save the original textContent to revert it in #revert().\n\t\tif ( node ) {\n\t\t\tdata.revertData.text = node.textContent;\n\t\t} else {\n\t\t\tnode = data.node = document.createTextNode( '' );\n\t\t}\n\n\t\t// Check if this Text Node is bound to Observable. Cases:\n\t\t//\n\t\t//\t\ttext: [ Template.bind( ... ).to( ... ) ]\n\t\t//\n\t\t//\t\ttext: [\n\t\t//\t\t\t'foo',\n\t\t//\t\t\tTemplate.bind( ... ).to( ... ),\n\t\t//\t\t\t...\n\t\t//\t\t]\n\t\t//\n\t\tif ( hasTemplateBinding( this.text ) ) {\n\t\t\tthis._bindToObservable( {\n\t\t\t\tschema: this.text,\n\t\t\t\tupdater: getTextUpdater( node ),\n\t\t\t\tdata\n\t\t\t} );\n\t\t}\n\t\t// Simply set text. Cases:\n\t\t//\n\t\t//\t\ttext: [ 'all', 'are', 'static' ]\n\t\t//\n\t\t//\t\ttext: [ 'foo' ]\n\t\t//\n\t\telse {\n\t\t\tnode.textContent = this.text.join( '' );\n\t\t}\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Renders HTML element attributes out of {@link module:ui/template~Template#attributes}.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderAttributes( data ) {\n\t\tlet attrName, attrValue, domAttrValue, attrNs;\n\n\t\tif ( !this.attributes ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst node = data.node;\n\t\tconst revertData = data.revertData;\n\n\t\tfor ( attrName in this.attributes ) {\n\t\t\t// Current attribute value in DOM.\n\t\t\tdomAttrValue = node.getAttribute( attrName );\n\n\t\t\t// The value to be set.\n\t\t\tattrValue = this.attributes[ attrName ];\n\n\t\t\t// Save revert data.\n\t\t\tif ( revertData ) {\n\t\t\t\trevertData.attributes[ attrName ] = domAttrValue;\n\t\t\t}\n\n\t\t\t// Detect custom namespace:\n\t\t\t//\n\t\t\t//\t\tclass: {\n\t\t\t//\t\t\tns: 'abc',\n\t\t\t//\t\t\tvalue: Template.bind( ... ).to( ... )\n\t\t\t//\t\t}\n\t\t\t//\n\t\t\tattrNs = ( isObject( attrValue[ 0 ] ) && attrValue[ 0 ].ns ) ? attrValue[ 0 ].ns : null;\n\n\t\t\t// Activate binding if one is found. Cases:\n\t\t\t//\n\t\t\t//\t\tclass: [\n\t\t\t//\t\t\tTemplate.bind( ... ).to( ... )\n\t\t\t//\t\t]\n\t\t\t//\n\t\t\t//\t\tclass: [\n\t\t\t//\t\t\t'bar',\n\t\t\t//\t\t\tTemplate.bind( ... ).to( ... ),\n\t\t\t//\t\t\t'baz'\n\t\t\t//\t\t]\n\t\t\t//\n\t\t\t//\t\tclass: {\n\t\t\t//\t\t\tns: 'abc',\n\t\t\t//\t\t\tvalue: Template.bind( ... ).to( ... )\n\t\t\t//\t\t}\n\t\t\t//\n\t\t\tif ( hasTemplateBinding( attrValue ) ) {\n\t\t\t\t// Normalize attributes with additional data like namespace:\n\t\t\t\t//\n\t\t\t\t//\t\tclass: {\n\t\t\t\t//\t\t\tns: 'abc',\n\t\t\t\t//\t\t\tvalue: [ ... ]\n\t\t\t\t//\t\t}\n\t\t\t\t//\n\t\t\t\tconst valueToBind = attrNs ? attrValue[ 0 ].value : attrValue;\n\n\t\t\t\t// Extend the original value of attributes like \"style\" and \"class\",\n\t\t\t\t// don't override them.\n\t\t\t\tif ( revertData && shouldExtend( attrName ) ) {\n\t\t\t\t\tvalueToBind.unshift( domAttrValue );\n\t\t\t\t}\n\n\t\t\t\tthis._bindToObservable( {\n\t\t\t\t\tschema: valueToBind,\n\t\t\t\t\tupdater: getAttributeUpdater( node, attrName, attrNs ),\n\t\t\t\t\tdata\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t// Style attribute could be an Object so it needs to be parsed in a specific way.\n\t\t\t//\n\t\t\t//\t\tstyle: {\n\t\t\t//\t\t\twidth: '100px',\n\t\t\t//\t\t\theight: Template.bind( ... ).to( ... )\n\t\t\t//\t\t}\n\t\t\t//\n\t\t\telse if ( attrName == 'style' && typeof attrValue[ 0 ] !== 'string' ) {\n\t\t\t\tthis._renderStyleAttribute( attrValue[ 0 ], data );\n\t\t\t}\n\n\t\t\t// Otherwise simply set the static attribute:\n\t\t\t//\n\t\t\t//\t\tclass: [ 'foo' ]\n\t\t\t//\n\t\t\t//\t\tclass: [ 'all', 'are', 'static' ]\n\t\t\t//\n\t\t\t//\t\tclass: [\n\t\t\t//\t\t\t{\n\t\t\t//\t\t\t\tns: 'abc',\n\t\t\t//\t\t\t\tvalue: [ 'foo' ]\n\t\t\t//\t\t\t}\n\t\t\t//\t\t]\n\t\t\t//\n\t\t\telse {\n\t\t\t\t// Extend the original value of attributes like \"style\" and \"class\",\n\t\t\t\t// don't override them.\n\t\t\t\tif ( revertData && domAttrValue && shouldExtend( attrName ) ) {\n\t\t\t\t\tattrValue.unshift( domAttrValue );\n\t\t\t\t}\n\n\t\t\t\tattrValue = attrValue\n\t\t\t\t\t// Retrieve \"values\" from:\n\t\t\t\t\t//\n\t\t\t\t\t//\t\tclass: [\n\t\t\t\t\t//\t\t\t{\n\t\t\t\t\t//\t\t\t\tns: 'abc',\n\t\t\t\t\t//\t\t\t\tvalue: [ ... ]\n\t\t\t\t\t//\t\t\t}\n\t\t\t\t\t//\t\t]\n\t\t\t\t\t//\n\t\t\t\t\t.map( val => val ? ( val.value || val ) : val )\n\t\t\t\t\t// Flatten the array.\n\t\t\t\t\t.reduce( ( prev, next ) => prev.concat( next ), [] )\n\t\t\t\t\t// Convert into string.\n\t\t\t\t\t.reduce( arrayValueReducer, '' );\n\n\t\t\t\tif ( !isFalsy( attrValue ) ) {\n\t\t\t\t\tnode.setAttributeNS( attrNs, attrName, attrValue );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Renders the `style` attribute of an HTML element based on\n\t * {@link module:ui/template~Template#attributes}.\n\t *\n\t * A style attribute is an {Object} with static values:\n\t *\n\t *\t\tattributes: {\n\t *\t\t\tstyle: {\n\t *\t\t\t\tcolor: 'red'\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t * or values bound to {@link module:ui/model~Model} properties:\n\t *\n\t *\t\tattributes: {\n\t *\t\t\tstyle: {\n\t *\t\t\t\tcolor: bind.to( ... )\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t * Note: The `style` attribute is rendered without setting the namespace. It does not seem to be\n\t * needed.\n\t *\n\t * @private\n\t * @param {Object} styles Styles located in `attributes.style` of {@link module:ui/template~TemplateDefinition}.\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderStyleAttribute( styles, data ) {\n\t\tconst node = data.node;\n\n\t\tfor ( const styleName in styles ) {\n\t\t\tconst styleValue = styles[ styleName ];\n\n\t\t\t// Cases:\n\t\t\t//\n\t\t\t//\t\tstyle: {\n\t\t\t//\t\t\tcolor: bind.to( 'attribute' )\n\t\t\t//\t\t}\n\t\t\t//\n\t\t\tif ( hasTemplateBinding( styleValue ) ) {\n\t\t\t\tthis._bindToObservable( {\n\t\t\t\t\tschema: [ styleValue ],\n\t\t\t\t\tupdater: getStyleUpdater( node, styleName ),\n\t\t\t\t\tdata\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t// Cases:\n\t\t\t//\n\t\t\t//\t\tstyle: {\n\t\t\t//\t\t\tcolor: 'red'\n\t\t\t//\t\t}\n\t\t\t//\n\t\t\telse {\n\t\t\t\tnode.style[ styleName ] = styleValue;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Recursively renders HTML element's children from {@link module:ui/template~Template#children}.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderElementChildren( data ) {\n\t\tconst node = data.node;\n\t\tconst container = data.intoFragment ? document.createDocumentFragment() : node;\n\t\tconst isApplying = data.isApplying;\n\t\tlet childIndex = 0;\n\n\t\tfor ( const child of this.children ) {\n\t\t\tif ( isViewCollection( child ) ) {\n\t\t\t\tif ( !isApplying ) {\n\t\t\t\t\tchild.setParent( node );\n\n\t\t\t\t\t// Note: ViewCollection renders its children.\n\t\t\t\t\tfor ( const view of child ) {\n\t\t\t\t\t\tcontainer.appendChild( view.element );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if ( isView( child ) ) {\n\t\t\t\tif ( !isApplying ) {\n\t\t\t\t\tif ( !child.isRendered ) {\n\t\t\t\t\t\tchild.render();\n\t\t\t\t\t}\n\n\t\t\t\t\tcontainer.appendChild( child.element );\n\t\t\t\t}\n\t\t\t} else if ( isNode( child ) ) {\n\t\t\t\tcontainer.appendChild( child );\n\t\t\t} else {\n\t\t\t\tif ( isApplying ) {\n\t\t\t\t\tconst revertData = data.revertData;\n\t\t\t\t\tconst childRevertData = getEmptyRevertData();\n\n\t\t\t\t\trevertData.children.push( childRevertData );\n\n\t\t\t\t\tchild._renderNode( {\n\t\t\t\t\t\tnode: container.childNodes[ childIndex++ ],\n\t\t\t\t\t\tisApplying: true,\n\t\t\t\t\t\trevertData: childRevertData\n\t\t\t\t\t} );\n\t\t\t\t} else {\n\t\t\t\t\tcontainer.appendChild( child.render() );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( data.intoFragment ) {\n\t\t\tnode.appendChild( container );\n\t\t}\n\t}\n\n\t/**\n\t * Activates `on` event listeners from the {@link module:ui/template~TemplateDefinition}\n\t * on an HTML element.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_setUpListeners( data ) {\n\t\tif ( !this.eventListeners ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const key in this.eventListeners ) {\n\t\t\tconst revertBindings = this.eventListeners[ key ].map( schemaItem => {\n\t\t\t\tconst [ domEvtName, domSelector ] = key.split( '@' );\n\n\t\t\t\treturn schemaItem.activateDomEventListener( domEvtName, domSelector, data );\n\t\t\t} );\n\n\t\t\tif ( data.revertData ) {\n\t\t\t\tdata.revertData.bindings.push( revertBindings );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * For a given {@link module:ui/template~TemplateValueSchema} containing {@link module:ui/template~TemplateBinding}\n\t * activates the binding and sets its initial value.\n\t *\n\t * Note: {@link module:ui/template~TemplateValueSchema} can be for HTML element attributes or\n\t * text node `textContent`.\n\t *\n\t * @protected\n\t * @param {Object} options Binding options.\n\t * @param {module:ui/template~TemplateValueSchema} options.schema\n\t * @param {Function} options.updater A function which updates the DOM (like attribute or text).\n\t * @param {module:ui/template~RenderData} options.data Rendering data.\n\t */\n\t_bindToObservable( { schema, updater, data } ) {\n\t\tconst revertData = data.revertData;\n\n\t\t// Set initial values.\n\t\tsyncValueSchemaValue( schema, updater, data );\n\n\t\tconst revertBindings = schema\n\t\t\t// Filter \"falsy\" (false, undefined, null, '') value schema components out.\n\t\t\t.filter( item => !isFalsy( item ) )\n\t\t\t// Filter inactive bindings from schema, like static strings ('foo'), numbers (42), etc.\n\t\t\t.filter( item => item.observable )\n\t\t\t// Once only the actual binding are left, let the emitter listen to observable change:attribute event.\n\t\t\t// TODO: Reduce the number of listeners attached as many bindings may listen\n\t\t\t// to the same observable attribute.\n\t\t\t.map( templateBinding => templateBinding.activateAttributeListener( schema, updater, data ) );\n\n\t\tif ( revertData ) {\n\t\t\trevertData.bindings.push( revertBindings );\n\t\t}\n\t}\n\n\t/**\n\t * Reverts {@link module:ui/template~RenderData#revertData template data} from a node to\n\t * return it to the original state.\n\t *\n\t * @protected\n\t * @param {HTMLElement|Text} node A node to be reverted.\n\t * @param {Object} revertData An object that stores information about what changes have been made by\n\t * {@link #apply} to the node. See {@link module:ui/template~RenderData#revertData} for more information.\n\t */\n\t_revertTemplateFromNode( node, revertData ) {\n\t\tfor ( const binding of revertData.bindings ) {\n\t\t\t// Each binding may consist of several observable+observable#attribute.\n\t\t\t// like the following has 2:\n\t\t\t//\n\t\t\t//\t\tclass: [\n\t\t\t//\t\t\t'x',\n\t\t\t//\t\t\tbind.to( 'foo' ),\n\t\t\t//\t\t\t'y',\n\t\t\t//\t\t\tbind.to( 'bar' )\n\t\t\t//\t\t]\n\t\t\t//\n\t\t\tfor ( const revertBinding of binding ) {\n\t\t\t\trevertBinding();\n\t\t\t}\n\t\t}\n\n\t\tif ( revertData.text ) {\n\t\t\tnode.textContent = revertData.text;\n\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const attrName in revertData.attributes ) {\n\t\t\tconst attrValue = revertData.attributes[ attrName ];\n\n\t\t\t// When the attribute has **not** been set before #apply().\n\t\t\tif ( attrValue === null ) {\n\t\t\t\tnode.removeAttribute( attrName );\n\t\t\t} else {\n\t\t\t\tnode.setAttribute( attrName, attrValue );\n\t\t\t}\n\t\t}\n\n\t\tfor ( let i = 0; i < revertData.children.length; ++i ) {\n\t\t\tthis._revertTemplateFromNode( node.childNodes[ i ], revertData.children[ i ] );\n\t\t}\n\t}\n}\n\nmix( Template, EmitterMixin );\n\n/**\n * Describes a binding created by the {@link module:ui/template~Template.bind} interface.\n *\n * @protected\n */\nexport class TemplateBinding {\n\t/**\n\t * Creates an instance of the {@link module:ui/template~TemplateBinding} class.\n\t *\n\t * @param {module:ui/template~TemplateDefinition} def The definition of the binding.\n\t */\n\tconstructor( def ) {\n\t\tObject.assign( this, def );\n\n\t\t/**\n\t\t * An observable instance of the binding. It either:\n\t\t *\n\t\t * * provides the attribute with the value,\n\t\t * * or passes the event when a corresponding DOM event is fired.\n\t\t *\n\t\t * @member {module:utils/observablemixin~ObservableMixin} module:ui/template~TemplateBinding#observable\n\t\t */\n\n\t\t/**\n\t\t * An {@link module:utils/emittermixin~Emitter} used by the binding to:\n\t\t *\n\t\t * * listen to the attribute change in the {@link module:ui/template~TemplateBinding#observable},\n\t\t * * or listen to the event in the DOM.\n\t\t *\n\t\t * @member {module:utils/emittermixin~EmitterMixin} module:ui/template~TemplateBinding#emitter\n\t\t */\n\n\t\t/**\n\t\t * The name of the {@link module:ui/template~TemplateBinding#observable observed attribute}.\n\t\t *\n\t\t * @member {String} module:ui/template~TemplateBinding#attribute\n\t\t */\n\n\t\t/**\n\t\t * A custom function to process the value of the {@link module:ui/template~TemplateBinding#attribute}.\n\t\t *\n\t\t * @member {Function} [module:ui/template~TemplateBinding#callback]\n\t\t */\n\t}\n\n\t/**\n\t * Returns the value of the binding. It is the value of the {@link module:ui/template~TemplateBinding#attribute} in\n\t * {@link module:ui/template~TemplateBinding#observable}. The value may be processed by the\n\t * {@link module:ui/template~TemplateBinding#callback}, if such has been passed to the binding.\n\t *\n\t * @param {Node} [node] A native DOM node, passed to the custom {@link module:ui/template~TemplateBinding#callback}.\n\t * @returns {*} The value of {@link module:ui/template~TemplateBinding#attribute} in\n\t * {@link module:ui/template~TemplateBinding#observable}.\n\t */\n\tgetValue( node ) {\n\t\tconst value = this.observable[ this.attribute ];\n\n\t\treturn this.callback ? this.callback( value, node ) : value;\n\t}\n\n\t/**\n\t * Activates the listener which waits for changes of the {@link module:ui/template~TemplateBinding#attribute} in\n\t * {@link module:ui/template~TemplateBinding#observable}, then updates the DOM with the aggregated\n\t * value of {@link module:ui/template~TemplateValueSchema}.\n\t *\n\t * @param {module:ui/template~TemplateValueSchema} schema A full schema to generate an attribute or text in the DOM.\n\t * @param {Function} updater A DOM updater function used to update the native DOM attribute or text.\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t * @returns {Function} A function to sever the listener binding.\n\t */\n\tactivateAttributeListener( schema, updater, data ) {\n\t\tconst callback = () => syncValueSchemaValue( schema, updater, data );\n\n\t\tthis.emitter.listenTo( this.observable, 'change:' + this.attribute, callback );\n\n\t\t// Allows revert of the listener.\n\t\treturn () => {\n\t\t\tthis.emitter.stopListening( this.observable, 'change:' + this.attribute, callback );\n\t\t};\n\t}\n}\n\n/**\n * Describes either:\n *\n * * a binding to an {@link module:utils/observablemixin~Observable},\n * * or a native DOM event binding.\n *\n * It is created by the {@link module:ui/template~BindChain#to} method.\n *\n * @protected\n */\nexport class TemplateToBinding extends TemplateBinding {\n\t/**\n\t * Activates the listener for the native DOM event, which when fired, is propagated by\n\t * the {@link module:ui/template~TemplateBinding#emitter}.\n\t *\n\t * @param {String} domEvtName The name of the native DOM event.\n\t * @param {String} domSelector The selector in the DOM to filter delegated events.\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t * @returns {Function} A function to sever the listener binding.\n\t */\n\tactivateDomEventListener( domEvtName, domSelector, data ) {\n\t\tconst callback = ( evt, domEvt ) => {\n\t\t\tif ( !domSelector || domEvt.target.matches( domSelector ) ) {\n\t\t\t\tif ( typeof this.eventNameOrFunction == 'function' ) {\n\t\t\t\t\tthis.eventNameOrFunction( domEvt );\n\t\t\t\t} else {\n\t\t\t\t\tthis.observable.fire( this.eventNameOrFunction, domEvt );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tthis.emitter.listenTo( data.node, domEvtName, callback );\n\n\t\t// Allows revert of the listener.\n\t\treturn () => {\n\t\t\tthis.emitter.stopListening( data.node, domEvtName, callback );\n\t\t};\n\t}\n}\n\n/**\n * Describes a binding to {@link module:utils/observablemixin~ObservableMixin} created by the {@link module:ui/template~BindChain#if}\n * method.\n *\n * @protected\n */\nexport class TemplateIfBinding extends TemplateBinding {\n\t/**\n\t * @inheritDoc\n\t */\n\tgetValue( node ) {\n\t\tconst value = super.getValue( node );\n\n\t\treturn isFalsy( value ) ? false : ( this.valueIfTrue || true );\n\t}\n\n\t/**\n\t * The value of the DOM attribute or text to be set if the {@link module:ui/template~TemplateBinding#attribute} in\n\t * {@link module:ui/template~TemplateBinding#observable} is `true`.\n\t *\n\t * @member {String} [module:ui/template~TemplateIfBinding#valueIfTrue]\n\t */\n}\n\n// Checks whether given {@link module:ui/template~TemplateValueSchema} contains a\n// {@link module:ui/template~TemplateBinding}.\n//\n// @param {module:ui/template~TemplateValueSchema} schema\n// @returns {Boolean}\nfunction hasTemplateBinding( schema ) {\n\tif ( !schema ) {\n\t\treturn false;\n\t}\n\n\t// Normalize attributes with additional data like namespace:\n\t//\n\t//\t\tclass: {\n\t//\t\t\tns: 'abc',\n\t//\t\t\tvalue: [ ... ]\n\t//\t\t}\n\t//\n\tif ( schema.value ) {\n\t\tschema = schema.value;\n\t}\n\n\tif ( Array.isArray( schema ) ) {\n\t\treturn schema.some( hasTemplateBinding );\n\t} else if ( schema instanceof TemplateBinding ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n// Assembles the value using {@link module:ui/template~TemplateValueSchema} and stores it in a form of\n// an Array. Each entry of the Array corresponds to one of {@link module:ui/template~TemplateValueSchema}\n// items.\n//\n// @param {module:ui/template~TemplateValueSchema} schema\n// @param {Node} node DOM Node updated when {@link module:utils/observablemixin~ObservableMixin} changes.\n// @returns {Array}\nfunction getValueSchemaValue( schema, node ) {\n\treturn schema.map( schemaItem => {\n\t\t// Process {@link module:ui/template~TemplateBinding} bindings.\n\t\tif ( schemaItem instanceof TemplateBinding ) {\n\t\t\treturn schemaItem.getValue( node );\n\t\t}\n\n\t\t// All static values like strings, numbers, and \"falsy\" values (false, null, undefined, '', etc.) just pass.\n\t\treturn schemaItem;\n\t} );\n}\n\n// A function executed each time the bound Observable attribute changes, which updates the DOM with a value\n// constructed from {@link module:ui/template~TemplateValueSchema}.\n//\n// @param {module:ui/template~TemplateValueSchema} schema\n// @param {Function} updater A function which updates the DOM (like attribute or text).\n// @param {Node} node DOM Node updated when {@link module:utils/observablemixin~ObservableMixin} changes.\nfunction syncValueSchemaValue( schema, updater, { node } ) {\n\tlet value = getValueSchemaValue( schema, node );\n\n\t// Check if schema is a single Template.bind.if, like:\n\t//\n\t//\t\tclass: Template.bind.if( 'foo' )\n\t//\n\tif ( schema.length == 1 && schema[ 0 ] instanceof TemplateIfBinding ) {\n\t\tvalue = value[ 0 ];\n\t} else {\n\t\tvalue = value.reduce( arrayValueReducer, '' );\n\t}\n\n\tif ( isFalsy( value ) ) {\n\t\tupdater.remove();\n\t} else {\n\t\tupdater.set( value );\n\t}\n}\n\n// Returns an object consisting of `set` and `remove` functions, which\n// can be used in the context of DOM Node to set or reset `textContent`.\n// @see module:ui/view~View#_bindToObservable\n//\n// @param {Node} node DOM Node to be modified.\n// @returns {Object}\nfunction getTextUpdater( node ) {\n\treturn {\n\t\tset( value ) {\n\t\t\tnode.textContent = value;\n\t\t},\n\n\t\tremove() {\n\t\t\tnode.textContent = '';\n\t\t}\n\t};\n}\n\n// Returns an object consisting of `set` and `remove` functions, which\n// can be used in the context of DOM Node to set or reset an attribute.\n// @see module:ui/view~View#_bindToObservable\n//\n// @param {Node} node DOM Node to be modified.\n// @param {String} attrName Name of the attribute to be modified.\n// @param {String} [ns=null] Namespace to use.\n// @returns {Object}\nfunction getAttributeUpdater( el, attrName, ns ) {\n\treturn {\n\t\tset( value ) {\n\t\t\tel.setAttributeNS( ns, attrName, value );\n\t\t},\n\n\t\tremove() {\n\t\t\tel.removeAttributeNS( ns, attrName );\n\t\t}\n\t};\n}\n\n// Returns an object consisting of `set` and `remove` functions, which\n// can be used in the context of CSSStyleDeclaration to set or remove a style.\n// @see module:ui/view~View#_bindToObservable\n//\n// @param {Node} node DOM Node to be modified.\n// @param {String} styleName Name of the style to be modified.\n// @returns {Object}\nfunction getStyleUpdater( el, styleName ) {\n\treturn {\n\t\tset( value ) {\n\t\t\tel.style[ styleName ] = value;\n\t\t},\n\n\t\tremove() {\n\t\t\tel.style[ styleName ] = null;\n\t\t}\n\t};\n}\n\n// Clones definition of the template.\n//\n// @param {module:ui/template~TemplateDefinition} def\n// @returns {module:ui/template~TemplateDefinition}\nfunction clone( def ) {\n\tconst clone = cloneDeepWith( def, value => {\n\t\t// Don't clone the `Template.bind`* bindings because of the references to Observable\n\t\t// and DomEmitterMixin instances inside, which would also be traversed and cloned by greedy\n\t\t// cloneDeepWith algorithm. There's no point in cloning Observable/DomEmitterMixins\n\t\t// along with the definition.\n\t\t//\n\t\t// Don't clone Template instances if provided as a child. They're simply #render()ed\n\t\t// and nothing should interfere.\n\t\t//\n\t\t// Also don't clone View instances if provided as a child of the Template. The template\n\t\t// instance will be extracted from the View during the normalization and there's no need\n\t\t// to clone it.\n\t\tif ( value && ( value instanceof TemplateBinding || isTemplate( value ) || isView( value ) || isViewCollection( value ) ) ) {\n\t\t\treturn value;\n\t\t}\n\t} );\n\n\treturn clone;\n}\n\n// Normalizes given {@link module:ui/template~TemplateDefinition}.\n//\n// See:\n//  * {@link normalizeAttributes}\n//  * {@link normalizeListeners}\n//  * {@link normalizePlainTextDefinition}\n//  * {@link normalizeTextDefinition}\n//\n// @param {module:ui/template~TemplateDefinition} def\n// @returns {module:ui/template~TemplateDefinition} Normalized definition.\nfunction normalize( def ) {\n\tif ( typeof def == 'string' ) {\n\t\tdef = normalizePlainTextDefinition( def );\n\t} else if ( def.text ) {\n\t\tnormalizeTextDefinition( def );\n\t}\n\n\tif ( def.on ) {\n\t\tdef.eventListeners = normalizeListeners( def.on );\n\n\t\t// Template mixes EmitterMixin, so delete #on to avoid collision.\n\t\tdelete def.on;\n\t}\n\n\tif ( !def.text ) {\n\t\tif ( def.attributes ) {\n\t\t\tnormalizeAttributes( def.attributes );\n\t\t}\n\n\t\tconst children = [];\n\n\t\tif ( def.children ) {\n\t\t\tif ( isViewCollection( def.children ) ) {\n\t\t\t\tchildren.push( def.children );\n\t\t\t} else {\n\t\t\t\tfor ( const child of def.children ) {\n\t\t\t\t\tif ( isTemplate( child ) || isView( child ) || isNode( child ) ) {\n\t\t\t\t\t\tchildren.push( child );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tchildren.push( new Template( child ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tdef.children = children;\n\t}\n\n\treturn def;\n}\n\n// Normalizes \"attributes\" section of {@link module:ui/template~TemplateDefinition}.\n//\n//\t\tattributes: {\n//\t\t\ta: 'bar',\n//\t\t\tb: {@link module:ui/template~TemplateBinding},\n//\t\t\tc: {\n//\t\t\t\tvalue: 'bar'\n//\t\t\t}\n//\t\t}\n//\n// becomes\n//\n//\t\tattributes: {\n//\t\t\ta: [ 'bar' ],\n//\t\t\tb: [ {@link module:ui/template~TemplateBinding} ],\n//\t\t\tc: {\n//\t\t\t\tvalue: [ 'bar' ]\n//\t\t\t}\n//\t\t}\n//\n// @param {Object} attributes\nfunction normalizeAttributes( attributes ) {\n\tfor ( const a in attributes ) {\n\t\tif ( attributes[ a ].value ) {\n\t\t\tattributes[ a ].value = toArray( attributes[ a ].value );\n\t\t}\n\n\t\tarrayify( attributes, a );\n\t}\n}\n\n// Normalizes \"on\" section of {@link module:ui/template~TemplateDefinition}.\n//\n//\t\ton: {\n//\t\t\ta: 'bar',\n//\t\t\tb: {@link module:ui/template~TemplateBinding},\n//\t\t\tc: [ {@link module:ui/template~TemplateBinding}, () => { ... } ]\n//\t\t}\n//\n// becomes\n//\n//\t\ton: {\n//\t\t\ta: [ 'bar' ],\n//\t\t\tb: [ {@link module:ui/template~TemplateBinding} ],\n//\t\t\tc: [ {@link module:ui/template~TemplateBinding}, () => { ... } ]\n//\t\t}\n//\n// @param {Object} listeners\n// @returns {Object} Object containing normalized listeners.\nfunction normalizeListeners( listeners ) {\n\tfor ( const l in listeners ) {\n\t\tarrayify( listeners, l );\n\t}\n\n\treturn listeners;\n}\n\n// Normalizes \"string\" {@link module:ui/template~TemplateDefinition}.\n//\n//\t\t\"foo\"\n//\n// becomes\n//\n//\t\t{ text: [ 'foo' ] },\n//\n// @param {String} def\n// @returns {module:ui/template~TemplateDefinition} Normalized template definition.\nfunction normalizePlainTextDefinition( def ) {\n\treturn {\n\t\ttext: [ def ]\n\t};\n}\n\n// Normalizes text {@link module:ui/template~TemplateDefinition}.\n//\n//\t\tchildren: [\n//\t\t\t{ text: 'def' },\n//\t\t\t{ text: {@link module:ui/template~TemplateBinding} }\n//\t\t]\n//\n// becomes\n//\n//\t\tchildren: [\n//\t\t\t{ text: [ 'def' ] },\n//\t\t\t{ text: [ {@link module:ui/template~TemplateBinding} ] }\n//\t\t]\n//\n// @param {module:ui/template~TemplateDefinition} def\nfunction normalizeTextDefinition( def ) {\n\tdef.text = toArray( def.text );\n}\n\n// Wraps an entry in Object in an Array, if not already one.\n//\n//\t\t{\n//\t\t\tx: 'y',\n//\t\t\ta: [ 'b' ]\n//\t\t}\n//\n// becomes\n//\n//\t\t{\n//\t\t\tx: [ 'y' ],\n//\t\t\ta: [ 'b' ]\n//\t\t}\n//\n// @param {Object} obj\n// @param {String} key\nfunction arrayify( obj, key ) {\n\tobj[ key ] = toArray( obj[ key ] );\n}\n\n// A helper which concatenates the value avoiding unwanted\n// leading white spaces.\n//\n// @param {String} prev\n// @param {String} cur\n// @returns {String}\nfunction arrayValueReducer( prev, cur ) {\n\tif ( isFalsy( cur ) ) {\n\t\treturn prev;\n\t} else if ( isFalsy( prev ) ) {\n\t\treturn cur;\n\t} else {\n\t\treturn `${ prev } ${ cur }`;\n\t}\n}\n\n// Extends one object defined in the following format:\n//\n//\t\t{\n//\t\t\tkey1: [Array1],\n//\t\t\tkey2: [Array2],\n//\t\t\t...\n//\t\t\tkeyN: [ArrayN]\n//\t\t}\n//\n// with another object of the same data format.\n//\n// @param {Object} obj Base object.\n// @param {Object} ext Object extending base.\n// @returns {String}\nfunction extendObjectValueArray( obj, ext ) {\n\tfor ( const a in ext ) {\n\t\tif ( obj[ a ] ) {\n\t\t\tobj[ a ].push( ...ext[ a ] );\n\t\t} else {\n\t\t\tobj[ a ] = ext[ a ];\n\t\t}\n\t}\n}\n\n// A helper for {@link module:ui/template~Template#extend}. Recursively extends {@link module:ui/template~Template} instance\n// with content from {@link module:ui/template~TemplateDefinition}. See {@link module:ui/template~Template#extend} to learn more.\n//\n// @param {module:ui/template~Template} def A template instance to be extended.\n// @param {module:ui/template~TemplateDefinition} def A definition which is to extend the template instance.\n// @param {Object} Error context.\nfunction extendTemplate( template, def ) {\n\tif ( def.attributes ) {\n\t\tif ( !template.attributes ) {\n\t\t\ttemplate.attributes = {};\n\t\t}\n\n\t\textendObjectValueArray( template.attributes, def.attributes );\n\t}\n\n\tif ( def.eventListeners ) {\n\t\tif ( !template.eventListeners ) {\n\t\t\ttemplate.eventListeners = {};\n\t\t}\n\n\t\textendObjectValueArray( template.eventListeners, def.eventListeners );\n\t}\n\n\tif ( def.text ) {\n\t\ttemplate.text.push( ...def.text );\n\t}\n\n\tif ( def.children && def.children.length ) {\n\t\tif ( template.children.length != def.children.length ) {\n\t\t\t/**\n\t\t\t * The number of children in extended definition does not match.\n\t\t\t *\n\t\t\t * @error ui-template-extend-children-mismatch\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'ui-template-extend-children-mismatch',\n\t\t\t\ttemplate\n\t\t\t);\n\t\t}\n\n\t\tlet childIndex = 0;\n\n\t\tfor ( const childDef of def.children ) {\n\t\t\textendTemplate( template.children[ childIndex++ ], childDef );\n\t\t}\n\t}\n}\n\n// Checks if value is \"falsy\".\n// Note: 0 (Number) is not \"falsy\" in this context.\n//\n// @private\n// @param {*} value Value to be checked.\nfunction isFalsy( value ) {\n\treturn !value && value !== 0;\n}\n\n// Checks if the item is an instance of {@link module:ui/view~View}\n//\n// @private\n// @param {*} value Value to be checked.\nfunction isView( item ) {\n\treturn item instanceof View;\n}\n\n// Checks if the item is an instance of {@link module:ui/template~Template}\n//\n// @private\n// @param {*} value Value to be checked.\nfunction isTemplate( item ) {\n\treturn item instanceof Template;\n}\n\n// Checks if the item is an instance of {@link module:ui/viewcollection~ViewCollection}\n//\n// @private\n// @param {*} value Value to be checked.\nfunction isViewCollection( item ) {\n\treturn item instanceof ViewCollection;\n}\n\n// Creates an empty skeleton for {@link module:ui/template~Template#revert}\n// data.\n//\n// @private\nfunction getEmptyRevertData() {\n\treturn {\n\t\tchildren: [],\n\t\tbindings: [],\n\t\tattributes: {}\n\t};\n}\n\n// Checks whether an attribute should be extended when\n// {@link module:ui/template~Template#apply} is called.\n//\n// @private\n// @param {String} attrName Attribute name to check.\nfunction shouldExtend( attrName ) {\n\treturn attrName == 'class' || attrName == 'style';\n}\n\n/**\n * A definition of the {@link module:ui/template~Template}. It describes what kind of\n * node a template will render (HTML element or text), attributes of an element, DOM event\n * listeners and children.\n *\n * Also see:\n * * {@link module:ui/template~TemplateValueSchema} to learn about HTML element attributes,\n * * {@link module:ui/template~TemplateListenerSchema} to learn about DOM event listeners.\n *\n * A sample definition on an HTML element can look like this:\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\t\t\tchildren: [\n *\t\t\t\t{\n *\t\t\t\t\ttag: 'span',\n *\t\t\t\t\tattributes: { ... },\n *\t\t\t\t\tchildren: [ ... ],\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\ttext: 'static–text'\n *\t\t\t\t},\n *\t\t\t\t'also-static–text',\n *\t\t\t],\n *\t\t\tattributes: {\n *\t\t\t\tclass: {@link module:ui/template~TemplateValueSchema},\n *\t\t\t\tid: {@link module:ui/template~TemplateValueSchema},\n *\t\t\t\tstyle: {@link module:ui/template~TemplateValueSchema}\n *\n *\t\t\t\t// ...\n *\t\t\t},\n *\t\t\ton: {\n *\t\t\t\t'click': {@link module:ui/template~TemplateListenerSchema}\n *\n *\t\t\t\t// Document.querySelector format is also accepted.\n *\t\t\t\t'keyup@a.some-class': {@link module:ui/template~TemplateListenerSchema}\n *\n *\t\t\t\t// ...\n *\t\t\t}\n *\t\t} );\n *\n * A {@link module:ui/view~View}, another {@link module:ui/template~Template} or a native DOM node\n * can also become a child of a template. When a view is passed, its {@link module:ui/view~View#element} is used:\n *\n *\t\tconst view = new SomeView();\n *\t\tconst childTemplate = new Template( { ... } );\n *\t\tconst childNode = document.createElement( 'b' );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\n *\t\t\tchildren: [\n *\t\t\t\t// view#element will be added as a child of this <p>.\n *\t\t\t\tview,\n *\n * \t\t\t\t// The output of childTemplate.render() will be added here.\n *\t\t\t\tchildTemplate,\n *\n *\t\t\t\t// Native DOM nodes are included directly in the rendered output.\n *\t\t\t\tchildNode\n *\t\t\t]\n *\t\t} );\n *\n * An entire {@link module:ui/viewcollection~ViewCollection} can be used as a child in the definition:\n *\n *\t\tconst collection = new ViewCollection();\n *\t\tcollection.add( someView );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\n *\t\t\tchildren: collection\n *\t\t} );\n *\n * @typedef module:ui/template~TemplateDefinition\n * @type Object\n *\n * @property {String} tag See the template {@link module:ui/template~Template#tag} property.\n *\n * @property {Array.<module:ui/template~TemplateDefinition>} [children]\n * See the template {@link module:ui/template~Template#children} property.\n *\n * @property {Object.<String, module:ui/template~TemplateValueSchema>} [attributes]\n * See the template {@link module:ui/template~Template#attributes} property.\n *\n * @property {String|module:ui/template~TemplateValueSchema|Array.<String|module:ui/template~TemplateValueSchema>} [text]\n * See the template {@link module:ui/template~Template#text} property.\n *\n * @property {Object.<String, module:ui/template~TemplateListenerSchema>} [on]\n * See the template {@link module:ui/template~Template#eventListeners} property.\n */\n\n/**\n * Describes a value of an HTML element attribute or `textContent`. It allows combining multiple\n * data sources like static values and {@link module:utils/observablemixin~Observable} attributes.\n *\n * Also see:\n * * {@link module:ui/template~TemplateDefinition} to learn where to use it,\n * * {@link module:ui/template~Template.bind} to learn how to configure\n * {@link module:utils/observablemixin~Observable} attribute bindings,\n * * {@link module:ui/template~Template#render} to learn how to render a template,\n * * {@link module:ui/template~BindChain#to `to()`} and {@link module:ui/template~BindChain#if `if()`}\n * methods to learn more about bindings.\n *\n * Attribute values can be described in many different ways:\n *\n *\t\t// Bind helper will create bindings to attributes of the observable.\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\t\t\tattributes: {\n *\t\t\t\t// A plain string schema.\n *\t\t\t\t'class': 'static-text',\n *\n *\t\t\t\t// An object schema, binds to the \"foo\" attribute of the\n *\t\t\t\t// observable and follows its value.\n *\t\t\t\t'class': bind.to( 'foo' ),\n *\n *\t\t\t\t// An array schema, combines the above.\n *\t\t\t\t'class': [\n *\t\t\t\t\t'static-text',\n *\t\t\t\t\tbind.to( 'bar', () => { ... } ),\n *\n * \t\t\t\t\t// Bindings can also be conditional.\n *\t\t\t\t\tbind.if( 'baz', 'class-when-baz-is-true' )\n *\t\t\t\t],\n *\n *\t\t\t\t// An array schema, with a custom namespace, e.g. useful for creating SVGs.\n *\t\t\t\t'class': {\n *\t\t\t\t\tns: 'http://ns.url',\n *\t\t\t\t\tvalue: [\n *\t\t\t\t\t\tbind.if( 'baz', 'value-when-true' ),\n *\t\t\t\t\t\t'static-text'\n *\t\t\t\t\t]\n *\t\t\t\t},\n *\n *\t\t\t\t// An object schema, specific for styles.\n *\t\t\t\tstyle: {\n *\t\t\t\t\tcolor: 'red',\n *\t\t\t\t\tbackgroundColor: bind.to( 'qux', () => { ... } )\n *\t\t\t\t}\n *\t\t\t}\n *\t\t} );\n *\n * Text nodes can also have complex values:\n *\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\t// Will render a \"foo\" text node.\n *\t\tnew Template( {\n *\t\t\ttext: 'foo'\n *\t\t} );\n *\n *\t\t// Will render a \"static text: {observable.foo}\" text node.\n *\t\t// The text of the node will be updated as the \"foo\" attribute changes.\n *\t\tnew Template( {\n *\t\t\ttext: [\n *\t\t\t\t'static text: ',\n *\t\t\t\tbind.to( 'foo', () => { ... } )\n *\t\t\t]\n *\t\t} );\n *\n * @typedef module:ui/template~TemplateValueSchema\n * @type {Object|String|Array}\n */\n\n/**\n * Describes an event listener attached to an HTML element. Such listener can propagate DOM events\n * through an {@link module:utils/observablemixin~Observable} instance, execute custom callbacks\n * or both, if necessary.\n *\n * Also see:\n * * {@link module:ui/template~TemplateDefinition} to learn more about template definitions,\n * * {@link module:ui/template~BindChain#to `to()`} method to learn more about bindings.\n *\n * Check out different ways of attaching event listeners below:\n *\n *\t\t// Bind helper will propagate events through the observable.\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\t\t\ton: {\n *\t\t\t\t// An object schema. The observable will fire the \"clicked\" event upon DOM \"click\".\n *\t\t\t\tclick: bind.to( 'clicked' )\n *\n *\t\t\t\t// An object schema. It will work for \"click\" event on \"a.foo\" children only.\n *\t\t\t\t'click@a.foo': bind.to( 'clicked' )\n *\n *\t\t\t\t// An array schema, makes the observable propagate multiple events.\n *\t\t\t\tclick: [\n *\t\t\t\t\tbind.to( 'clicked' ),\n *\t\t\t\t\tbind.to( 'executed' )\n *\t\t\t\t],\n *\n *\t\t\t\t// An array schema with a custom callback.\n *\t\t\t\t'click@a.foo': {\n *\t\t\t\t\tbind.to( 'clicked' ),\n *\t\t\t\t\tbind.to( evt => {\n *\t\t\t\t\t\tconsole.log( `${ evt.target } has been clicked!` );\n *\t\t\t\t\t} }\n *\t\t\t\t}\n *\t\t\t}\n *\t\t} );\n *\n * @typedef module:ui/template~TemplateListenerSchema\n * @type {Object|String|Array}\n */\n\n/**\n * The return value of {@link ~Template.bind `Template.bind()`}. It provides `to()` and `if()`\n * methods to create the {@link module:utils/observablemixin~Observable observable} attribute and event bindings.\n *\n * @interface module:ui/template~BindChain\n */\n\n/**\n * Binds an {@link module:utils/observablemixin~Observable observable} to either:\n *\n * * an HTML element attribute or a text node `textContent`, so it remains in sync with the observable\n * attribute as it changes,\n * * or an HTML element DOM event, so the DOM events are propagated through an observable.\n *\n * Some common use cases of `to()` bindings are presented below:\n *\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\t\t\tattributes: {\n *\t\t\t\t// class=\"...\" attribute gets bound to `observable#a`\n *\t\t\t\tclass: bind.to( 'a' )\n *\t\t\t},\n *\t\t\tchildren: [\n *\t\t\t\t// <p>...</p> gets bound to observable#b; always `toUpperCase()`.\n *\t\t\t\t{\n *\t\t\t\t\ttext: bind.to( 'b', ( value, node ) => value.toUpperCase() )\n *\t\t\t\t}\n *\t\t\t],\n *\t\t\ton: {\n *\t\t\t\tclick: [\n *\t\t\t\t\t// An observable will fire \"clicked\" upon \"click\" in the DOM.\n *\t\t\t\t\tbind.to( 'clicked' ),\n *\n *\t\t\t\t\t// A custom callback will be executed upon \"click\" in the DOM.\n *\t\t\t\t\tbind.to( () => {\n *\t\t\t\t\t\t...\n *\t\t\t\t\t} )\n *\t\t\t\t]\n *\t\t\t}\n *\t\t} ).render();\n *\n * Learn more about using `to()` in the {@link module:ui/template~TemplateValueSchema} and\n * {@link module:ui/template~TemplateListenerSchema}.\n *\n * @method #to\n * @param {String|Function} eventNameOrFunctionOrAttribute An attribute name of\n * {@link module:utils/observablemixin~Observable} or a DOM event name or an event callback.\n * @param {Function} [callback] Allows for processing of the value. Accepts `Node` and `value` as arguments.\n * @returns {module:ui/template~TemplateBinding}\n */\n\n/**\n * Binds an {@link module:utils/observablemixin~Observable observable} to an HTML element attribute or a text\n * node `textContent` so it remains in sync with the observable attribute as it changes.\n *\n * Unlike {@link module:ui/template~BindChain#to}, it controls the presence of the attribute or `textContent`\n * depending on the \"falseness\" of an {@link module:utils/observablemixin~Observable} attribute.\n *\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'input',\n *\t\t\tattributes: {\n *\t\t\t\t// <input checked> when `observable#a` is not undefined/null/false/''\n *\t\t\t\t// <input> when `observable#a` is undefined/null/false\n *\t\t\t\tchecked: bind.if( 'a' )\n *\t\t\t},\n *\t\t\tchildren: [\n *\t\t\t\t{\n *\t\t\t\t\t// <input>\"b-is-not-set\"</input> when `observable#b` is undefined/null/false/''\n *\t\t\t\t\t// <input></input> when `observable#b` is not \"falsy\"\n *\t\t\t\t\ttext: bind.if( 'b', 'b-is-not-set', ( value, node ) => !value )\n *\t\t\t\t}\n *\t\t\t]\n *\t\t} ).render();\n *\n * Learn more about using `if()` in the {@link module:ui/template~TemplateValueSchema}.\n *\n * @method #if\n * @param {String} attribute An attribute name of {@link module:utils/observablemixin~Observable} used in the binding.\n * @param {String} [valueIfTrue] Value set when the {@link module:utils/observablemixin~Observable} attribute is not\n * undefined/null/false/'' (empty string).\n * @param {Function} [callback] Allows for processing of the value. Accepts `Node` and `value` as arguments.\n * @returns {module:ui/template~TemplateBinding}\n */\n\n/**\n * The {@link module:ui/template~Template#_renderNode} configuration.\n *\n * @private\n * @interface module:ui/template~RenderData\n */\n\n/**\n * Tells {@link module:ui/template~Template#_renderNode} to render\n * children into `DocumentFragment` first and then append the fragment\n * to the parent element. It is a speed optimization.\n *\n * @member {Boolean} #intoFragment\n */\n\n/**\n * A node which is being rendered.\n *\n * @member {HTMLElement|Text} #node\n */\n\n/**\n * Indicates whether the {@module:ui/template~RenderNodeOptions#node} has\n * been provided by {@module:ui/template~Template#apply}.\n *\n * @member {Boolean} #isApplying\n */\n\n/**\n * An object storing the data that helps {@module:ui/template~Template#revert}\n * bringing back an element to its initial state, i.e. before\n * {@module:ui/template~Template#apply} was called.\n *\n * @member {Object} #revertData\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/view\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport ViewCollection from './viewcollection';\nimport Template from './template';\nimport DomEmitterMixin from '@ckeditor/ckeditor5-utils/src/dom/emittermixin';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\n\nimport '../theme/globals/globals.css';\n\n/**\n * The basic view class, which represents an HTML element created out of a\n * {@link module:ui/view~View#template}. Views are building blocks of the user interface and handle\n * interaction\n *\n * Views {@link module:ui/view~View#registerChild aggregate} children in\n * {@link module:ui/view~View#createCollection collections} and manage the life cycle of DOM\n * listeners e.g. by handling rendering and destruction.\n *\n * See the {@link module:ui/template~TemplateDefinition} syntax to learn more about shaping view\n * elements, attributes and listeners.\n *\n *\t\tclass SampleView extends View {\n *\t\t\tconstructor( locale ) {\n *\t\t\t\tsuper( locale );\n *\n *\t\t\t\tconst bind = this.bindTemplate;\n *\n *\t\t\t\t// Views define their interface (state) using observable attributes.\n *\t\t\t\tthis.set( 'elementClass', 'bar' );\n *\n *\t\t\t\tthis.setTemplate( {\n *\t\t\t\t\ttag: 'p',\n *\n *\t\t\t\t\t// The element of the view can be defined with its children.\n *\t\t\t\t\tchildren: [\n *\t\t\t\t\t\t'Hello',\n *\t\t\t\t\t\t{\n *\t\t\t\t\t\t\ttag: 'b',\n *\t\t\t\t\t\t\tchildren: [ 'world!' ]\n *\t\t\t\t\t\t}\n *\t\t\t\t\t],\n *\t\t\t\t\tattributes: {\n *\t\t\t\t\t\tclass: [\n *\t\t\t\t\t\t\t'foo',\n *\n *\t\t\t\t\t\t\t// Observable attributes control the state of the view in DOM.\n *\t\t\t\t\t\t\tbind.to( 'elementClass' )\n *\t\t\t\t\t\t]\n *\t\t\t\t\t},\n *\t\t\t\t\ton: {\n *\t\t\t\t\t\t// Views listen to DOM events and propagate them.\n *\t\t\t\t\t\tclick: bind.to( 'clicked' )\n *\t\t\t\t\t}\n *\t\t\t\t} );\n *\t\t\t}\n *\t\t}\n *\n *\t\tconst view = new SampleView( locale );\n *\n *\t\tview.render();\n *\n *\t\t// Append <p class=\"foo bar\">Hello<b>world</b></p> to the <body>\n *\t\tdocument.body.appendChild( view.element );\n *\n *\t\t// Change the class attribute to <p class=\"foo baz\">Hello<b>world</b></p>\n *\t\tview.elementClass = 'baz';\n *\n *\t\t// Respond to the \"click\" event in DOM by executing a custom action.\n *\t\tview.on( 'clicked', () => {\n *\t\t\tconsole.log( 'The view has been clicked!' );\n *\t\t} );\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class View {\n\t/**\n\t * Creates an instance of the {@link module:ui/view~View} class.\n\t *\n\t * Also see {@link #render}.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The localization services instance.\n\t */\n\tconstructor( locale ) {\n\t\t/**\n\t\t * An HTML element of the view. `null` until {@link #render rendered}\n\t\t * from the {@link #template}.\n\t\t *\n\t\t *\t\tclass SampleView extends View {\n\t\t *\t\t\tconstructor() {\n\t\t *\t\t\t\tsuper();\n\t\t *\n\t\t *\t\t\t\t// A template instance the #element will be created from.\n\t\t *\t\t\t\tthis.setTemplate( {\n\t\t *\t\t\t\t\ttag: 'p'\n\t\t *\n\t\t *\t\t\t\t\t// ...\n\t\t *\t\t\t\t} );\n\t\t *\t\t\t}\n\t\t *\t\t}\n\t\t *\n\t\t *\t\tconst view = new SampleView();\n\t\t *\n\t\t *\t\t// Renders the #template.\n\t\t *\t\tview.render();\n\t\t *\n\t\t *\t\t// Append the HTML element of the view to <body>.\n\t\t *\t\tdocument.body.appendChild( view.element );\n\t\t *\n\t\t * **Note**: The element of the view can also be assigned directly:\n\t\t *\n\t\t *\t\tview.element = document.querySelector( '#my-container' );\n\t\t *\n\t\t * @member {HTMLElement}\n\t\t */\n\t\tthis.element = null;\n\n\t\t/**\n\t\t * Set `true` when the view has already been {@link module:ui/view~View#render rendered}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} #isRendered\n\t\t */\n\t\tthis.isRendered = false;\n\n\t\t/**\n\t\t * A set of tools to localize the user interface.\n\t\t *\n\t\t * Also see {@link module:core/editor/editor~Editor#locale}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/locale~Locale}\n\t\t */\n\t\tthis.locale = locale;\n\n\t\t/**\n\t\t * Shorthand for {@link module:utils/locale~Locale#t}.\n\t\t *\n\t\t * Note: If {@link #locale} instance hasn't been passed to the view this method may not\n\t\t * be available.\n\t\t *\n\t\t * @see module:utils/locale~Locale#t\n\t\t * @method\n\t\t */\n\t\tthis.t = locale && locale.t;\n\n\t\t/**\n\t\t * Collections registered with {@link #createCollection}.\n\t\t *\n\t\t * @protected\n\t\t * @member {Set.<module:ui/viewcollection~ViewCollection>}\n\t\t */\n\t\tthis._viewCollections = new Collection();\n\n\t\t/**\n\t\t * A collection of view instances, which have been added directly\n\t\t * into the {@link module:ui/template~Template#children}.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis._unboundChildren = this.createCollection();\n\n\t\t// Pass parent locale to its children.\n\t\tthis._viewCollections.on( 'add', ( evt, collection ) => {\n\t\t\tcollection.locale = locale;\n\t\t} );\n\n\t\t/**\n\t\t * Template of this view. It provides the {@link #element} representing\n\t\t * the view in DOM, which is {@link #render rendered}.\n\t\t *\n\t\t * @member {module:ui/template~Template} #template\n\t\t */\n\n\t\t/**\n\t\t * Cached {@link module:ui/template~BindChain bind chain} object created by the\n\t\t * {@link #template}. See {@link #bindTemplate}.\n\t\t *\n\t\t * @private\n\t\t * @member {Object} #_bindTemplate\n\t\t */\n\n\t\tthis.decorate( 'render' );\n\t}\n\n\t/**\n\t * Shorthand for {@link module:ui/template~Template.bind}, a binding\n\t * {@link module:ui/template~BindChain interface} pre–configured for the view instance.\n\t *\n\t * It provides {@link module:ui/template~BindChain#to `to()`} and\n\t * {@link module:ui/template~BindChain#if `if()`} methods that initialize bindings with\n\t * observable attributes and attach DOM listeners.\n\t *\n\t *\t\tclass SampleView extends View {\n\t *\t\t\tconstructor( locale ) {\n\t *\t\t\t\tsuper( locale );\n\t *\n\t *\t\t\t\tconst bind = this.bindTemplate;\n\t *\n\t *\t\t\t\t// These {@link module:utils/observablemixin~Observable observable} attributes will control\n\t *\t\t\t\t// the state of the view in DOM.\n\t *\t\t\t\tthis.set( {\n\t *\t\t\t\t\telementClass: 'foo',\n\t *\t\t\t\t \tisEnabled: true\n\t *\t\t\t\t } );\n\t *\n\t *\t\t\t\tthis.setTemplate( {\n\t *\t\t\t\t\ttag: 'p',\n\t *\n\t *\t\t\t\t\tattributes: {\n\t *\t\t\t\t\t\t// The class HTML attribute will follow elementClass\n\t *\t\t\t\t\t\t// and isEnabled view attributes.\n\t *\t\t\t\t\t\tclass: [\n\t *\t\t\t\t\t\t\tbind.to( 'elementClass' )\n\t *\t\t\t\t\t\t\tbind.if( 'isEnabled', 'present-when-enabled' )\n\t *\t\t\t\t\t\t]\n\t *\t\t\t\t\t},\n\t *\n\t *\t\t\t\t\ton: {\n\t *\t\t\t\t\t\t// The view will fire the \"clicked\" event upon clicking <p> in DOM.\n\t *\t\t\t\t\t\tclick: bind.to( 'clicked' )\n\t *\t\t\t\t\t}\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t * @method #bindTemplate\n\t */\n\tget bindTemplate() {\n\t\tif ( this._bindTemplate ) {\n\t\t\treturn this._bindTemplate;\n\t\t}\n\n\t\treturn ( this._bindTemplate = Template.bind( this, this ) );\n\t}\n\n\t/**\n\t * Creates a new collection of views, which can be used as\n\t * {@link module:ui/template~Template#children} of this view.\n\t *\n\t *\t\tclass SampleView extends View {\n\t *\t\t\tconstructor( locale ) {\n\t *\t\t\t\tsuper( locale );\n\t *\n\t *\t\t\t\tconst child = new ChildView( locale );\n\t *\t\t\t\tthis.items = this.createCollection( [ child ] );\n \t *\n\t *\t\t\t\tthis.setTemplate( {\n\t *\t\t\t\t\ttag: 'p',\n\t *\n\t *\t\t\t\t\t// `items` collection will render here.\n\t *\t\t\t\t\tchildren: this.items\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t *\t\tconst view = new SampleView( locale );\n\t *\t\tview.render();\n\t *\n\t *\t\t// It will append <p><child#element></p> to the <body>.\n\t *\t\tdocument.body.appendChild( view.element );\n\t *\n\t * @param {Iterable.<module:ui/view~View>} [views] Initial views of the collection.\n\t * @returns {module:ui/viewcollection~ViewCollection} A new collection of view instances.\n\t */\n\tcreateCollection( views ) {\n\t\tconst collection = new ViewCollection( views );\n\n\t\tthis._viewCollections.add( collection );\n\n\t\treturn collection;\n\t}\n\n\t/**\n\t * Registers a new child view under the view instance. Once registered, a child\n\t * view is managed by its parent, including {@link #render rendering}\n\t * and {@link #destroy destruction}.\n\t *\n\t * To revert this, use {@link #deregisterChild}.\n\t *\n\t *\t\tclass SampleView extends View {\n\t *\t\t\tconstructor( locale ) {\n\t *\t\t\t\tsuper( locale );\n\t *\n\t *\t\t\t\tthis.childA = new SomeChildView( locale );\n\t *\t\t\t\tthis.childB = new SomeChildView( locale );\n\t *\n\t *\t\t\t\tthis.setTemplate( { tag: 'p' } );\n\t *\n\t *\t\t\t\t// Register the children.\n\t *\t\t\t\tthis.registerChild( [ this.childA, this.childB ] );\n\t *\t\t\t}\n\t *\n\t *\t\t\trender() {\n\t *\t\t\t\tsuper.render();\n\t *\n\t *\t\t\t\tthis.element.appendChild( this.childA.element );\n\t *\t\t\t\tthis.element.appendChild( this.childB.element );\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t *\t\tconst view = new SampleView( locale );\n\t *\n\t *\t\tview.render();\n\t *\n\t *\t\t// Will append <p><childA#element><b></b><childB#element></p>.\n\t *\t\tdocument.body.appendChild( view.element );\n\t *\n\t * **Note**: There's no need to add child views if they're already referenced in the\n\t * {@link #template}:\n\t *\n\t *\t\tclass SampleView extends View {\n\t *\t\t\tconstructor( locale ) {\n\t *\t\t\t\tsuper( locale );\n\t *\n\t *\t\t\t\tthis.childA = new SomeChildView( locale );\n\t *\t\t\t\tthis.childB = new SomeChildView( locale );\n\t *\n\t *\t\t\t\tthis.setTemplate( {\n\t *\t\t\t\t\ttag: 'p',\n\t *\n \t *\t\t\t\t\t// These children will be added automatically. There's no\n \t *\t\t\t\t\t// need to call {@link #registerChild} for any of them.\n\t *\t\t\t\t\tchildren: [ this.childA, this.childB ]\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\n\t *\t\t\t// ...\n\t *\t\t}\n\t *\n\t * @param {module:ui/view~View|Iterable.<module:ui/view~View>} children Children views to be registered.\n\t */\n\tregisterChild( children ) {\n\t\tif ( !isIterable( children ) ) {\n\t\t\tchildren = [ children ];\n\t\t}\n\n\t\tfor ( const child of children ) {\n\t\t\tthis._unboundChildren.add( child );\n\t\t}\n\t}\n\n\t/**\n\t * The opposite of {@link #registerChild}. Removes a child view from this view instance.\n\t * Once removed, the child is no longer managed by its parent, e.g. it can safely\n\t * become a child of another parent view.\n\t *\n\t * @see #registerChild\n\t * @param {module:ui/view~View|Iterable.<module:ui/view~View>} children Child views to be removed.\n\t */\n\tderegisterChild( children ) {\n\t\tif ( !isIterable( children ) ) {\n\t\t\tchildren = [ children ];\n\t\t}\n\n\t\tfor ( const child of children ) {\n\t\t\tthis._unboundChildren.remove( child );\n\t\t}\n\t}\n\n\t/**\n\t * Sets the {@link #template} of the view with with given definition.\n\t *\n\t * A shorthand for:\n\t *\n\t *\t\tview.setTemplate( definition );\n\t *\n\t * @param {module:ui/template~TemplateDefinition} definition Definition of view's template.\n\t */\n\tsetTemplate( definition ) {\n\t\tthis.template = new Template( definition );\n\t}\n\n\t/**\n\t * {@link module:ui/template~Template.extend Extends} the {@link #template} of the view with\n\t * with given definition.\n\t *\n\t * A shorthand for:\n\t *\n\t *\t\tTemplate.extend( view.template, definition );\n\t *\n\t * **Note**: Is requires the {@link #template} to be already set. See {@link #setTemplate}.\n\t *\n\t * @param {module:ui/template~TemplateDefinition} definition Definition which\n\t * extends the {@link #template}.\n\t */\n\textendTemplate( definition ) {\n\t\tTemplate.extend( this.template, definition );\n\t}\n\n\t/**\n\t * Recursively renders the view.\n\t *\n\t * Once the view is rendered:\n\t * * the {@link #element} becomes an HTML element out of {@link #template},\n\t * * the {@link #isRendered} flag is set `true`.\n\t *\n\t * **Note**: The children of the view:\n\t * * defined directly in the {@link #template}\n\t * * residing in collections created by the {@link #createCollection} method,\n\t * * and added by {@link #registerChild}\n\t * are also rendered in the process.\n\t *\n\t * In general, `render()` method is the right place to keep the code which refers to the\n\t * {@link #element} and should be executed at the very beginning of the view's life cycle.\n\t *\n\t * It is possible to {@link module:ui/template~Template.extend} the {@link #template} before\n\t * the view is rendered. To allow an early customization of the view (e.g. by its parent),\n\t * such references should be done in `render()`.\n\t *\n\t *\t\tclass SampleView extends View {\n\t *\t\t\tconstructor() {\n\t *\t\t\t\tthis.setTemplate( {\n\t *\t\t\t\t\t// ...\n\t *\t\t\t\t} );\n\t *\t\t\t},\n\t *\n\t *\t\t\trender() {\n\t *\t\t\t\t// View#element becomes available.\n\t *\t\t\t\tsuper.render();\n\t *\n\t *\t\t\t\t// The \"scroll\" listener depends on #element.\n\t *\t\t\t\tthis.listenTo( window, 'scroll', () => {\n\t *\t\t\t\t\t// A reference to #element would render the #template and make it non-extendable.\n\t *\t\t\t\t\tif ( window.scrollY > 0 ) {\n\t *\t\t\t\t\t\tthis.element.scrollLeft = 100;\n\t *\t\t\t\t\t} else {\n\t *\t\t\t\t\t\tthis.element.scrollLeft = 0;\n\t *\t\t\t\t\t}\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t *\t\tconst view = new SampleView();\n\t *\n\t *\t\t// Let's customize the view before it gets rendered.\n\t *\t\tview.extendTemplate( {\n\t *\t\t\tattributes: {\n\t *\t\t\t\tclass: [\n\t *\t\t\t\t\t'additional-class'\n\t *\t\t\t\t]\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Late rendering allows customization of the view.\n\t *\t\tview.render();\n\t */\n\trender() {\n\t\tif ( this.isRendered ) {\n\t\t\t/**\n\t\t\t * This View has already been rendered.\n\t\t\t *\n\t\t\t * @error ui-view-render-already-rendered\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'ui-view-render-already-rendered', this );\n\t\t}\n\n\t\t// Render #element of the view.\n\t\tif ( this.template ) {\n\t\t\tthis.element = this.template.render();\n\n\t\t\t// Auto–register view children from #template.\n\t\t\tthis.registerChild( this.template.getViews() );\n\t\t}\n\n\t\tthis.isRendered = true;\n\t}\n\n\t/**\n\t * Recursively destroys the view instance and child views added by {@link #registerChild} and\n\t * residing in collections created by the {@link #createCollection}.\n\t *\n\t * Destruction disables all event listeners:\n\t * * created on the view, e.g. `view.on( 'event', () => {} )`,\n\t * * defined in the {@link #template} for DOM events.\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\n\t\tthis._viewCollections.map( c => c.destroy() );\n\n\t\t// Template isn't obligatory for views.\n\t\tif ( this.template && this.template._revertData ) {\n\t\t\tthis.template.revert( this.element );\n\t\t}\n\t}\n\n\t/**\n\t * Event fired by the {@link #render} method. Actual rendering is executed as a listener to\n\t * this event with the default priority.\n\t *\n\t * See {@link module:utils/observablemixin~ObservableMixin#decorate} for more information and samples.\n\t *\n\t * @event render\n\t */\n}\n\nmix( View, DomEmitterMixin );\nmix( View, ObservableMixin );\n","import baseGetTag from './_baseGetTag.js';\nimport isArray from './isArray.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar stringTag = '[object String]';\n\n/**\n * Checks if `value` is classified as a `String` primitive or object.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a string, else `false`.\n * @example\n *\n * _.isString('abc');\n * // => true\n *\n * _.isString(1);\n * // => false\n */\nfunction isString(value) {\n  return typeof value == 'string' ||\n    (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag);\n}\n\nexport default isString;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/editorui/bodycollection\n */\n\n/* globals document */\n\nimport Template from '../template';\nimport ViewCollection from '../viewcollection';\n\nimport createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement';\n\n/**\n * This is a special {@link module:ui/viewcollection~ViewCollection} dedicated to elements that are detached\n * from the DOM structure of the editor, like panels, icons, etc.\n *\n * The body collection is available in the {@link module:ui/editorui/editoruiview~EditorUIView#body `editor.ui.view.body`} property.\n * Any plugin can add a {@link module:ui/view~View view} to this collection.\n * These views will render in a container placed directly in the `<body>` element.\n * The editor will detach and destroy this collection when the editor will be {@link module:core/editor/editor~Editor#destroy destroyed}.\n *\n * If you need to control the life cycle of the body collection on your own, you can create your own instance of this class.\n *\n * A body collection will render itself automatically in the DOM body element as soon as you call {@link ~BodyCollection#attachToDom}.\n * If you create multiple body collections, this class will create a special wrapper element in the DOM to limit the number of\n * elements created directly in the body and remove it when the last body collection will be\n * {@link ~BodyCollection#detachFromDom detached}.\n *\n * @extends module:ui/viewcollection~ViewCollection\n */\nexport default class BodyCollection extends ViewCollection {\n\t/**\n\t * Creates a new instance of the {@link module:ui/editorui/bodycollection~BodyCollection}.\n\t *\n\t * @param {module:utils/locale~Locale} locale The {@link module:core/editor/editor~Editor editor's locale} instance.\n\t * @param {Iterable.<module:ui/view~View>} [initialItems] The initial items of the collection.\n\t */\n\tconstructor( locale, initialItems = [] ) {\n\t\tsuper( initialItems );\n\n\t\t/**\n\t\t * The {@link module:core/editor/editor~Editor#locale editor's locale} instance.\n\t\t * See the view {@link module:ui/view~View#locale locale} property.\n\t\t *\n\t\t * @member {module:utils/locale~Locale}\n\t\t */\n\t\tthis.locale = locale;\n\t}\n\n\t/**\n\t * Attaches the body collection to the DOM body element. You need to execute this method to render the content of\n\t * the body collection.\n\t */\n\tattachToDom() {\n\t\t/**\n\t\t * The element holding elements of the body region.\n\t\t *\n\t\t * @protected\n\t\t * @member {HTMLElement} #_bodyCollectionContainer\n\t\t */\n\t\tthis._bodyCollectionContainer = new Template( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-reset_all',\n\t\t\t\t\t'ck-body',\n\t\t\t\t\t'ck-rounded-corners'\n\t\t\t\t],\n\t\t\t\tdir: this.locale.uiLanguageDirection\n\t\t\t},\n\t\t\tchildren: this\n\t\t} ).render();\n\n\t\tlet wrapper = document.querySelector( '.ck-body-wrapper' );\n\n\t\tif ( !wrapper ) {\n\t\t\twrapper = createElement( document, 'div', { class: 'ck-body-wrapper' } );\n\t\t\tdocument.body.appendChild( wrapper );\n\t\t}\n\n\t\twrapper.appendChild( this._bodyCollectionContainer );\n\t}\n\n\t/**\n\t * Detaches the collection from the DOM structure. Use this method when you do not need to use the body collection\n\t * anymore to clean-up the DOM structure.\n\t */\n\tdetachFromDom() {\n\t\tsuper.destroy();\n\n\t\tif ( this._bodyCollectionContainer ) {\n\t\t\tthis._bodyCollectionContainer.remove();\n\t\t}\n\n\t\tconst wrapper = document.querySelector( '.ck-body-wrapper' );\n\n\t\tif ( wrapper && wrapper.childElementCount == 0 ) {\n\t\t\twrapper.remove();\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/createelement\n */\n\nimport isIterable from '../isiterable';\nimport { isString } from 'lodash-es';\n\n/**\n * Creates element with attributes and children.\n *\n *\t\tcreateElement( document, 'p' ); // <p>\n *\t\tcreateElement( document, 'p', { class: 'foo' } ); // <p class=\"foo\">\n *\t\tcreateElement( document, 'p', null, 'foo' ); // <p>foo</p>\n *\t\tcreateElement( document, 'p', null, [ 'foo', createElement( document, 'img' ) ] ); // <p>foo<img></p>\n *\n * @param {Document} doc Document used to create element.\n * @param {String} name Name of the element.\n * @param {Object} [attributes] Object keys will become attributes keys and object values will became attributes values.\n * @param {Node|String|Array.<Node|String>} [children] Child or array of children. Strings will be automatically turned\n * into Text nodes.\n * @returns {Element} Created element.\n */\nexport default function createElement( doc, name, attributes = {}, children = [] ) {\n\tconst namespace = attributes && attributes.xmlns;\n\tconst element = namespace ? doc.createElementNS( namespace, name ) : doc.createElement( name );\n\n\tfor ( const key in attributes ) {\n\t\telement.setAttribute( key, attributes[ key ] );\n\t}\n\n\tif ( isString( children ) || !isIterable( children ) ) {\n\t\tchildren = [ children ];\n\t}\n\n\tfor ( let child of children ) {\n\t\tif ( isString( child ) ) {\n\t\t\tchild = doc.createTextNode( child );\n\t\t}\n\n\t\telement.appendChild( child );\n\t}\n\n\treturn element;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/editorui/editoruiview\n */\n\nimport View from '../view';\nimport BodyCollection from './bodycollection';\n\nimport '../../theme/components/editorui/editorui.css';\n\n/**\n * The editor UI view class. Base class for the editor main views.\n *\n * @extends module:ui/view~View\n */\nexport default class EditorUIView extends View {\n\t/**\n\t * Creates an instance of the editor UI view class.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The locale instance.\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * Collection of the child views, detached from the DOM\n\t\t * structure of the editor, like panels, icons etc.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection} #body\n\t\t */\n\t\tthis.body = new BodyCollection( locale );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.body.attachToDom();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tthis.body.detachFromDom();\n\n\t\treturn super.destroy();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/label/labelview\n */\n\nimport View from '../view';\nimport uid from '@ckeditor/ckeditor5-utils/src/uid';\n\nimport '../../theme/components/label/label.css';\n\n/**\n * The label view class.\n *\n * @extends module:ui/view~View\n */\nexport default class LabelView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * The text of the label.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #text\n\t\t */\n\t\tthis.set( 'text' );\n\n\t\t/**\n\t\t * The `for` attribute of the label (i.e. to pair with an `<input>` element).\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #for\n\t\t */\n\t\tthis.set( 'for' );\n\n\t\t/**\n\t\t * An unique id of the label. It can be used by other UI components to reference\n\t\t * the label, for instance, using the `aria-describedby` DOM attribute.\n\t\t *\n\t\t * @member {String} #id\n\t\t */\n\t\tthis.id = `ck-editor__label_${ uid() }`;\n\n\t\tconst bind = this.bindTemplate;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'label',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-label'\n\t\t\t\t],\n\t\t\t\tid: this.id,\n\t\t\t\tfor: bind.to( 'for' )\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttext: bind.to( 'text' )\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/editorui/boxed/boxededitoruiview\n */\n\nimport EditorUIView from '../../editorui/editoruiview';\nimport LabelView from '../../label/labelview';\n\n/**\n * The boxed editor UI view class. This class represents an editor interface\n * consisting of a toolbar and an editable area, enclosed within a box.\n *\n * @extends module:ui/editorui/editoruiview~EditorUIView\n */\nexport default class BoxedEditorUIView extends EditorUIView {\n\t/**\n\t * Creates an instance of the boxed editor UI view class.\n\t *\n\t * @param {module:utils/locale~Locale} locale The locale instance..\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * Collection of the child views located in the top (`.ck-editor__top`)\n\t\t * area of the UI.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.top = this.createCollection();\n\n\t\t/**\n\t\t * Collection of the child views located in the main (`.ck-editor__main`)\n\t\t * area of the UI.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.main = this.createCollection();\n\n\t\t/**\n\t\t * Voice label of the UI.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @member {module:ui/view~View} #_voiceLabelView\n\t\t */\n\t\tthis._voiceLabelView = this._createVoiceLabel();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-reset',\n\t\t\t\t\t'ck-editor',\n\t\t\t\t\t'ck-rounded-corners'\n\t\t\t\t],\n\t\t\t\trole: 'application',\n\t\t\t\tdir: locale.uiLanguageDirection,\n\t\t\t\tlang: locale.uiLanguage,\n\t\t\t\t'aria-labelledby': this._voiceLabelView.id\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\tthis._voiceLabelView,\n\t\t\t\t{\n\t\t\t\t\ttag: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [\n\t\t\t\t\t\t\t'ck',\n\t\t\t\t\t\t\t'ck-editor__top',\n\t\t\t\t\t\t\t'ck-reset_all'\n\t\t\t\t\t\t],\n\t\t\t\t\t\trole: 'presentation'\n\t\t\t\t\t},\n\t\t\t\t\tchildren: this.top\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttag: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [\n\t\t\t\t\t\t\t'ck',\n\t\t\t\t\t\t\t'ck-editor__main'\n\t\t\t\t\t\t],\n\t\t\t\t\t\trole: 'presentation'\n\t\t\t\t\t},\n\t\t\t\t\tchildren: this.main\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\t}\n\n\t/**\n\t * Creates a voice label view instance.\n\t *\n\t * @private\n\t * @returns {module:ui/label/labelview~LabelView}\n\t */\n\t_createVoiceLabel() {\n\t\tconst t = this.t;\n\t\tconst voiceLabel = new LabelView();\n\n\t\tvoiceLabel.text = t( 'Rich Text Editor' );\n\n\t\tvoiceLabel.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-voice-label'\n\t\t\t}\n\t\t} );\n\n\t\treturn voiceLabel;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/editableui/editableuiview\n */\n\nimport View from '../view';\n\n/**\n * The editable UI view class.\n *\n * @extends module:ui/view~View\n */\nexport default class EditableUIView extends View {\n\t/**\n\t * Creates an instance of EditableUIView class.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The locale instance.\n\t * @param {module:engine/view/view~View} editingView The editing view instance the editable is related to.\n\t * @param {HTMLElement} [editableElement] The editable element. If not specified, this view\n\t * should create it. Otherwise, the existing element should be used.\n\t */\n\tconstructor( locale, editingView, editableElement ) {\n\t\tsuper( locale );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-content',\n\t\t\t\t\t'ck-editor__editable',\n\t\t\t\t\t'ck-rounded-corners'\n\t\t\t\t],\n\t\t\t\tlang: locale.contentLanguage,\n\t\t\t\tdir: locale.contentLanguageDirection\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * The name of the editable UI view.\n\t\t *\n\t\t * @member {String} #name\n\t\t */\n\t\tthis.name = null;\n\n\t\t/**\n\t\t * Controls whether the editable is focused, i.e. the user is typing in it.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isFocused\n\t\t */\n\t\tthis.set( 'isFocused', false );\n\n\t\t/**\n\t\t * The element which is the main editable element (usually the one with `contentEditable=\"true\"`).\n\t\t *\n\t\t * @private\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis._editableElement = editableElement;\n\n\t\t/**\n\t\t * Whether an external {@link #_editableElement} was passed into the constructor, which also means\n\t\t * the view will not render its {@link #template}.\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._hasExternalElement = !!this._editableElement;\n\n\t\t/**\n\t\t * The editing view instance the editable is related to. Editable uses the editing\n\t\t * view to dynamically modify its certain DOM attributes after {@link #render rendering}.\n\t\t *\n\t\t * **Note**: The DOM attributes are performed by the editing view and not UI\n\t\t * {@link module:ui/view~View#bindTemplate template bindings} because once rendered,\n\t\t * the editable DOM element must remain under the full control of the engine to work properly.\n\t\t *\n\t\t * @protected\n\t\t * @type {module:engine/view/view~View}\n\t\t */\n\t\tthis._editingView = editingView;\n\t}\n\n\t/**\n\t * Renders the view by either applying the {@link #template} to the existing\n\t * {@link #_editableElement} or assigning {@link #element} as {@link #_editableElement}.\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tif ( this._hasExternalElement ) {\n\t\t\tthis.template.apply( this.element = this._editableElement );\n\t\t} else {\n\t\t\tthis._editableElement = this.element;\n\t\t}\n\n\t\tthis.on( 'change:isFocused', () => this._updateIsFocusedClasses() );\n\t\tthis._updateIsFocusedClasses();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tif ( this._hasExternalElement ) {\n\t\t\tthis.template.revert( this._editableElement );\n\t\t}\n\n\t\tsuper.destroy();\n\t}\n\n\t/**\n\t * Updates the `ck-focused` and `ck-blurred` CSS classes on the {@link #element} according to\n\t * the {@link #isFocused} property value using the {@link #_editingView editing view} API.\n\t *\n\t * @private\n\t */\n\t_updateIsFocusedClasses() {\n\t\tconst editingView = this._editingView;\n\n\t\tif ( editingView.isRenderingInProgress ) {\n\t\t\tupdateAfterRender( this );\n\t\t} else {\n\t\t\tupdate( this );\n\t\t}\n\n\t\tfunction update( view ) {\n\t\t\teditingView.change( writer => {\n\t\t\t\tconst viewRoot = editingView.document.getRoot( view.name );\n\n\t\t\t\twriter.addClass( view.isFocused ? 'ck-focused' : 'ck-blurred', viewRoot );\n\t\t\t\twriter.removeClass( view.isFocused ? 'ck-blurred' : 'ck-focused', viewRoot );\n\t\t\t} );\n\t\t}\n\n\t\t// In a case of a multi-root editor, a callback will be attached more than once (one callback for each root).\n\t\t// While executing one callback the `isRenderingInProgress` observable is changing what causes executing another\n\t\t// callback and render is called inside the already pending render.\n\t\t// We need to be sure that callback is executed only when the value has changed from `true` to `false`.\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/1676.\n\t\tfunction updateAfterRender( view ) {\n\t\t\teditingView.once( 'change:isRenderingInProgress', ( evt, name, value ) => {\n\t\t\t\tif ( !value ) {\n\t\t\t\t\tupdate( view );\n\t\t\t\t} else {\n\t\t\t\t\tupdateAfterRender( view );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/editableui/inline/inlineeditableuiview\n */\n\nimport EditableUIView from '../../editableui/editableuiview';\n\n/**\n * The inline editable UI class implementing an inline {@link module:ui/editableui/editableuiview~EditableUIView}.\n *\n * @extends module:ui/editableui/editableuiview~EditableUIView\n */\nexport default class InlineEditableUIView extends EditableUIView {\n\t/**\n\t * Creates an instance of the InlineEditableUIView class.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The locale instance.\n\t * @param {module:engine/view/view~View} editingView The editing view instance the editable is related to.\n\t * @param {HTMLElement} [editableElement] The editable element. If not specified, the\n\t * {@link module:ui/editableui/editableuiview~EditableUIView}\n\t * will create it. Otherwise, the existing element will be used.\n\t */\n\tconstructor( locale, editingView, editableElement ) {\n\t\tsuper( locale, editingView, editableElement );\n\n\t\tthis.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\trole: 'textbox',\n\t\t\t\tclass: 'ck-editor__editable_inline'\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tconst editingView = this._editingView;\n\t\tconst t = this.t;\n\n\t\teditingView.change( writer => {\n\t\t\tconst viewRoot = editingView.document.getRoot( this.name );\n\n\t\t\twriter.setAttribute( 'aria-label', t( 'Rich Text Editor, %0', this.name ), viewRoot );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/tounit\n */\n\n/**\n * Returns a helper function, which adds a desired trailing\n * `unit` to the passed value.\n *\n * @param {String} unit An unit like \"px\" or \"em\".\n * @returns {module:utils/dom/tounit~helper}\n */\nexport default function toUnit( unit ) {\n\t/**\n\t * A function, which adds a pre–defined trailing `unit`\n\t * to the passed `value`.\n\t *\n\t * @function helper\n \t * @param {*} value A value to be given the unit.\n \t * @returns {String} A value with the trailing unit.\n\t */\n\treturn value => value + unit;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/panel/sticky/stickypanelview\n */\n\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport View from '../../view';\nimport Template from '../../template';\nimport toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';\n\nimport '../../../theme/components/panel/stickypanel.css';\n\nconst toPx = toUnit( 'px' );\n\n/**\n * The sticky panel view class.\n */\nexport default class StickyPanelView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * Controls whether the sticky panel should be active.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isActive\n\t\t */\n\t\tthis.set( 'isActive', false );\n\n\t\t/**\n\t\t * Controls whether the sticky panel is in the \"sticky\" state.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isSticky\n\t\t */\n\t\tthis.set( 'isSticky', false );\n\n\t\t/**\n\t\t * The limiter element for the sticky panel instance. Its bounding rect limits\n\t\t * the \"stickyness\" of the panel, i.e. when the panel reaches the bottom\n\t\t * edge of the limiter, it becomes sticky to that edge and does not float\n\t\t * off the limiter. It is mandatory for the panel to work properly and once\n\t\t * set, it cannot be changed.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {HTMLElement} #limiterElement\n\t\t */\n\t\tthis.set( 'limiterElement', null );\n\n\t\t/**\n\t\t * The offset from the bottom edge of {@link #limiterElement}\n\t\t * which stops the panel from stickying any further to prevent limiter's content\n\t\t * from being completely covered.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @default 50\n\t\t * @member {Number} #limiterBottomOffset\n\t\t */\n\t\tthis.set( 'limiterBottomOffset', 50 );\n\n\t\t/**\n\t\t * The offset from the top edge of the web browser's viewport which makes the\n\t\t * panel become sticky. The default value is `0`, which means the panel becomes\n\t\t * sticky when it's upper edge touches the top of the page viewport.\n\t\t *\n\t\t * This attribute is useful when the web page has UI elements positioned to the top\n\t\t * either using `position: fixed` or `position: sticky`, which would cover the\n\t\t * sticky panel or vice–versa (depending on the `z-index` hierarchy).\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @default 0\n\t\t * @member {Number} #viewportTopOffset\n\t\t */\n\t\tthis.set( 'viewportTopOffset', 0 );\n\n\t\t/**\n\t\t * Controls the `margin-left` CSS style of the panel.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {String} #_marginLeft\n\t\t */\n\t\tthis.set( '_marginLeft', null );\n\n\t\t/**\n\t\t * Set `true` if the sticky panel reached the bottom edge of the\n\t\t * {@link #limiterElement}.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #_isStickyToTheLimiter\n\t\t */\n\t\tthis.set( '_isStickyToTheLimiter', false );\n\n\t\t/**\n\t\t * Set `true` if the sticky panel uses the {@link #viewportTopOffset},\n\t\t * i.e. not {@link #_isStickyToTheLimiter} and the {@link #viewportTopOffset}\n\t\t * is not `0`.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #_hasViewportTopOffset\n\t\t */\n\t\tthis.set( '_hasViewportTopOffset', false );\n\n\t\t/**\n\t\t * Collection of the child views which creates balloon panel contents.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.content = this.createCollection();\n\n\t\t/**\n\t\t * The DOM bounding client rect of the {@link module:ui/view~View#element} of the panel.\n\t\t *\n\t\t * @protected\n\t\t * @member {Object} #_panelRect\n\t\t */\n\n\t\t/**\n\t\t * The DOM bounding client rect of the {@link #limiterElement}\n\t\t * of the panel.\n\t\t *\n\t\t * @protected\n\t\t * @member {Object} #_limiterRect\n\t\t */\n\n\t\t/**\n\t\t * A dummy element which visually fills the space as long as the\n\t\t * actual panel is sticky. It prevents flickering of the UI.\n\t\t *\n\t\t * @protected\n\t\t * @property {HTMLElement}\n\t\t */\n\t\tthis._contentPanelPlaceholder = new Template( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-sticky-panel__placeholder'\n\t\t\t\t],\n\t\t\t\tstyle: {\n\t\t\t\t\tdisplay: bind.to( 'isSticky', isSticky => isSticky ? 'block' : 'none' ),\n\t\t\t\t\theight: bind.to( 'isSticky', isSticky => {\n\t\t\t\t\t\treturn isSticky ? toPx( this._panelRect.height ) : null;\n\t\t\t\t\t} )\n\t\t\t\t}\n\t\t\t}\n\t\t} ).render();\n\n\t\t/**\n\t\t * The panel which accepts children into {@link #content} collection.\n\t\t * Also an element which is positioned when {@link #isSticky}.\n\t\t *\n\t\t * @protected\n\t\t * @property {HTMLElement}\n\t\t */\n\t\tthis._contentPanel = new Template( {\n\t\t\ttag: 'div',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-sticky-panel__content',\n\t\t\t\t\t// Toggle class of the panel when \"sticky\" state changes in the view.\n\t\t\t\t\tbind.if( 'isSticky', 'ck-sticky-panel__content_sticky' ),\n\t\t\t\t\tbind.if( '_isStickyToTheLimiter', 'ck-sticky-panel__content_sticky_bottom-limit' )\n\t\t\t\t],\n\t\t\t\tstyle: {\n\t\t\t\t\twidth: bind.to( 'isSticky', isSticky => {\n\t\t\t\t\t\treturn isSticky ? toPx( this._contentPanelPlaceholder.getBoundingClientRect().width ) : null;\n\t\t\t\t\t} ),\n\n\t\t\t\t\ttop: bind.to( '_hasViewportTopOffset', _hasViewportTopOffset => {\n\t\t\t\t\t\treturn _hasViewportTopOffset ? toPx( this.viewportTopOffset ) : null;\n\t\t\t\t\t} ),\n\n\t\t\t\t\tbottom: bind.to( '_isStickyToTheLimiter', _isStickyToTheLimiter => {\n\t\t\t\t\t\treturn _isStickyToTheLimiter ? toPx( this.limiterBottomOffset ) : null;\n\t\t\t\t\t} ),\n\n\t\t\t\t\tmarginLeft: bind.to( '_marginLeft' )\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tchildren: this.content\n\t\t} ).render();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-sticky-panel'\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\tthis._contentPanelPlaceholder,\n\t\t\t\tthis._contentPanel\n\t\t\t]\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Check if the panel should go into the sticky state immediately.\n\t\tthis._checkIfShouldBeSticky();\n\n\t\t// Update sticky state of the panel as the window is being scrolled.\n\t\tthis.listenTo( global.window, 'scroll', () => {\n\t\t\tthis._checkIfShouldBeSticky();\n\t\t} );\n\n\t\t// Synchronize with `model.isActive` because sticking an inactive panel is pointless.\n\t\tthis.listenTo( this, 'change:isActive', () => {\n\t\t\tthis._checkIfShouldBeSticky();\n\t\t} );\n\t}\n\n\t/**\n\t * Analyzes the environment to decide whether the panel should\n\t * be sticky or not.\n\t *\n\t * @protected\n\t */\n\t_checkIfShouldBeSticky() {\n\t\tconst panelRect = this._panelRect = this._contentPanel.getBoundingClientRect();\n\t\tlet limiterRect;\n\n\t\tif ( !this.limiterElement ) {\n\t\t\tthis.isSticky = false;\n\t\t} else {\n\t\t\tlimiterRect = this._limiterRect = this.limiterElement.getBoundingClientRect();\n\n\t\t\t// The panel must be active to become sticky.\n\t\t\tthis.isSticky = this.isActive &&\n\t\t\t\t// The limiter's top edge must be beyond the upper edge of the visible viewport (+the viewportTopOffset).\n\t\t\t\tlimiterRect.top < this.viewportTopOffset &&\n\t\t\t\t// The model#limiterElement's height mustn't be smaller than the panel's height and model#limiterBottomOffset.\n\t\t\t\t// There's no point in entering the sticky mode if the model#limiterElement is very, very small, because\n\t\t\t\t// it would immediately set model#_isStickyToTheLimiter true and, given model#limiterBottomOffset, the panel\n\t\t\t\t// would be positioned before the model#limiterElement.\n\t\t\t\tthis._panelRect.height + this.limiterBottomOffset < limiterRect.height;\n\t\t}\n\n\t\t// Stick the panel to the top edge of the viewport simulating CSS position:sticky.\n\t\t// TODO: Possibly replaced by CSS in the future http://caniuse.com/#feat=css-sticky\n\t\tif ( this.isSticky ) {\n\t\t\tthis._isStickyToTheLimiter =\n\t\t\t\tlimiterRect.bottom < panelRect.height + this.limiterBottomOffset + this.viewportTopOffset;\n\t\t\tthis._hasViewportTopOffset = !this._isStickyToTheLimiter && !!this.viewportTopOffset;\n\t\t\tthis._marginLeft = this._isStickyToTheLimiter ? null : toPx( -global.window.scrollX );\n\t\t}\n\t\t// Detach the panel from the top edge of the viewport.\n\t\telse {\n\t\t\tthis._isStickyToTheLimiter = false;\n\t\t\tthis._hasViewportTopOffset = false;\n\t\t\tthis._marginLeft = null;\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/focuscycler\n */\n\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\n\n/**\n * A utility class that helps cycling over focusable {@link module:ui/view~View views} in a\n * {@link module:ui/viewcollection~ViewCollection} when the focus is tracked by the\n * {@link module:utils/focustracker~FocusTracker} instance. It helps implementing keyboard\n * navigation in HTML forms, toolbars, lists and the like.\n *\n * To work properly it requires:\n * * a collection of focusable (HTML `tabindex` attribute) views that implement the `focus()` method,\n * * an associated focus tracker to determine which view is focused.\n *\n * A simple cycler setup can look like this:\n *\n *\t\tconst focusables = new ViewCollection();\n *\t\tconst focusTracker = new FocusTracker();\n *\n *\t\t// Add focusable views to the focus tracker.\n *\t\tfocusTracker.add( ... );\n *\n * Then, the cycler can be used manually:\n *\n *\t\tconst cycler = new FocusCycler( { focusables, focusTracker } );\n *\n *\t\t// Will focus the first focusable view in #focusables.\n *\t\tcycler.focusFirst();\n *\n *\t\t// Will log the next focusable item in #focusables.\n *\t\tconsole.log( cycler.next );\n *\n * Alternatively, it can work side by side with the {@link module:utils/keystrokehandler~KeystrokeHandler}:\n *\n *\t\tconst keystrokeHandler = new KeystrokeHandler();\n *\n *\t\t// Activate the keystroke handler.\n *\t\tkeystrokeHandler.listenTo( sourceOfEvents );\n *\n *\t\tconst cycler = new FocusCycler( {\n *\t\t\tfocusables, focusTracker, keystrokeHandler,\n *\t\t\tactions: {\n *\t\t\t\t// When arrowup of arrowleft is detected by the #keystrokeHandler,\n *\t\t\t\t// focusPrevious() will be called on the cycler.\n *\t\t\t\tfocusPrevious: [ 'arrowup', 'arrowleft' ],\n *\t\t\t}\n *\t\t} );\n *\n * Check out the {@glink framework/guides/deep-dive/ui/focus-tracking \"Deep dive into focus tracking\" guide} to learn more.\n */\nexport default class FocusCycler {\n\t/**\n\t * Creates an instance of the focus cycler utility.\n\t *\n\t * @param {Object} options Configuration options.\n\t * @param {module:utils/collection~Collection|Object} options.focusables\n\t * @param {module:utils/focustracker~FocusTracker} options.focusTracker\n\t * @param {module:utils/keystrokehandler~KeystrokeHandler} [options.keystrokeHandler]\n\t * @param {Object} [options.actions]\n\t */\n\tconstructor( options ) {\n\t\tObject.assign( this, options );\n\n\t\t/**\n\t\t * A {@link module:ui/view~View view} collection that the cycler operates on.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/collection~Collection} #focusables\n\t\t */\n\n\t\t/**\n\t\t * A focus tracker instance that the cycler uses to determine the current focus\n\t\t * state in {@link #focusables}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker} #focusTracker\n\t\t */\n\n\t\t/**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}\n\t\t * which can respond to certain keystrokes and cycle the focus.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler} #keystrokeHandler\n\t\t */\n\n\t\t/**\n\t\t * Actions that the cycler can take when a keystroke is pressed. Requires\n\t\t * `options.keystrokeHandler` to be passed and working. When an action is\n\t\t * performed, `preventDefault` and `stopPropagation` will be called on the event\n\t\t * the keystroke fired in the DOM.\n\t\t *\n\t\t *\t\tactions: {\n\t\t *\t\t\t// Will call #focusPrevious() when arrowleft or arrowup is pressed.\n\t\t *\t\t\tfocusPrevious: [ 'arrowleft', 'arrowup' ],\n\t\t *\n\t\t *\t\t\t// Will call #focusNext() when arrowdown is pressed.\n\t\t *\t\t\tfocusNext: 'arrowdown'\n\t\t *\t\t}\n\t\t *\n\t\t * @readonly\n\t\t * @member {Object} #actions\n\t\t */\n\n\t\tif ( options.actions && options.keystrokeHandler ) {\n\t\t\tfor ( const methodName in options.actions ) {\n\t\t\t\tlet actions = options.actions[ methodName ];\n\n\t\t\t\tif ( typeof actions == 'string' ) {\n\t\t\t\t\tactions = [ actions ];\n\t\t\t\t}\n\n\t\t\t\tfor ( const keystroke of actions ) {\n\t\t\t\t\toptions.keystrokeHandler.set( keystroke, ( data, cancel ) => {\n\t\t\t\t\t\tthis[ methodName ]();\n\t\t\t\t\t\tcancel();\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns the first focusable view in {@link #focusables}.\n\t * Returns `null` if there is none.\n\t *\n\t * @readonly\n\t * @member {module:ui/view~View|null} #first\n\t */\n\tget first() {\n\t\treturn this.focusables.find( isFocusable ) || null;\n\t}\n\n\t/**\n\t * Returns the last focusable view in {@link #focusables}.\n\t * Returns `null` if there is none.\n\t *\n\t * @readonly\n\t * @member {module:ui/view~View|null} #last\n\t */\n\tget last() {\n\t\treturn this.focusables.filter( isFocusable ).slice( -1 )[ 0 ] || null;\n\t}\n\n\t/**\n\t * Returns the next focusable view in {@link #focusables} based on {@link #current}.\n\t * Returns `null` if there is none.\n\t *\n\t * @readonly\n\t * @member {module:ui/view~View|null} #next\n\t */\n\tget next() {\n\t\treturn this._getFocusableItem( 1 );\n\t}\n\n\t/**\n\t * Returns the previous focusable view in {@link #focusables} based on {@link #current}.\n\t * Returns `null` if there is none.\n\t *\n\t * @readonly\n\t * @member {module:ui/view~View|null} #previous\n\t */\n\tget previous() {\n\t\treturn this._getFocusableItem( -1 );\n\t}\n\n\t/**\n\t * An index of the view in the {@link #focusables} which is focused according\n\t * to {@link #focusTracker}. Returns `null` when there is no such view.\n\t *\n\t * @readonly\n\t * @member {Number|null} #current\n\t */\n\tget current() {\n\t\tlet index = null;\n\n\t\t// There's no focused view in the focusables.\n\t\tif ( this.focusTracker.focusedElement === null ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tthis.focusables.find( ( view, viewIndex ) => {\n\t\t\tconst focused = view.element === this.focusTracker.focusedElement;\n\n\t\t\tif ( focused ) {\n\t\t\t\tindex = viewIndex;\n\t\t\t}\n\n\t\t\treturn focused;\n\t\t} );\n\n\t\treturn index;\n\t}\n\n\t/**\n\t * Focuses the {@link #first} item in {@link #focusables}.\n\t */\n\tfocusFirst() {\n\t\tthis._focus( this.first );\n\t}\n\n\t/**\n\t * Focuses the {@link #last} item in {@link #focusables}.\n\t */\n\tfocusLast() {\n\t\tthis._focus( this.last );\n\t}\n\n\t/**\n\t * Focuses the {@link #next} item in {@link #focusables}.\n\t */\n\tfocusNext() {\n\t\tthis._focus( this.next );\n\t}\n\n\t/**\n\t * Focuses the {@link #previous} item in {@link #focusables}.\n\t */\n\tfocusPrevious() {\n\t\tthis._focus( this.previous );\n\t}\n\n\t/**\n\t * Focuses the given view if it exists.\n\t *\n\t * @protected\n\t * @param {module:ui/view~View} view\n\t */\n\t_focus( view ) {\n\t\tif ( view ) {\n\t\t\tview.focus();\n\t\t}\n\t}\n\n\t/**\n\t * Returns the next or previous focusable view in {@link #focusables} with respect\n\t * to {@link #current}.\n\t *\n\t * @protected\n\t * @param {Number} step Either `1` for checking forward from {@link #current} or\n\t * `-1` for checking backwards.\n\t * @returns {module:ui/view~View|null}\n\t */\n\t_getFocusableItem( step ) {\n\t\t// Cache for speed.\n\t\tconst current = this.current;\n\t\tconst collectionLength = this.focusables.length;\n\n\t\tif ( !collectionLength ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Start from the beginning if no view is focused.\n\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/206\n\t\tif ( current === null ) {\n\t\t\treturn this[ step === 1 ? 'first' : 'last' ];\n\t\t}\n\n\t\t// Cycle in both directions.\n\t\tlet index = ( current + collectionLength + step ) % collectionLength;\n\n\t\tdo {\n\t\t\tconst view = this.focusables.get( index );\n\n\t\t\t// TODO: Check if view is visible.\n\t\t\tif ( isFocusable( view ) ) {\n\t\t\t\treturn view;\n\t\t\t}\n\n\t\t\t// Cycle in both directions.\n\t\t\tindex = ( index + collectionLength + step ) % collectionLength;\n\t\t} while ( index !== current );\n\n\t\treturn null;\n\t}\n}\n\n// Checks whether a view is focusable.\n//\n// @private\n// @param {module:ui/view~View} view A view to be checked.\n// @returns {Boolean}\nfunction isFocusable( view ) {\n\treturn !!( view.focus && global.window.getComputedStyle( view.element ).display != 'none' );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/toolbar/toolbarseparatorview\n */\n\nimport View from '../view';\n\n/**\n * The toolbar separator view class.\n *\n * @extends module:ui/view~View\n */\nexport default class ToolbarSeparatorView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'span',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-toolbar__separator'\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/toolbar/toolbarlinebreakview\n */\n\nimport View from '../view';\n\n/**\n * The toolbar line break view class.\n *\n * @extends module:ui/view~View\n */\nexport default class ToolbarLineBreakView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'span',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-toolbar__line-break'\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/resizeobserver\n */\n\n/* globals setTimeout, clearTimeout */\n\nimport mix from '../mix';\nimport global from './global';\nimport Rect from './rect';\nimport DomEmitterMixin from './emittermixin';\n\nconst RESIZE_CHECK_INTERVAL = 100;\n\n/**\n * A helper class which instances allow performing custom actions when native DOM elements are resized.\n *\n *\t\tconst editableElement = editor.editing.view.getDomRoot();\n *\n *\t\tconst observer = new ResizeObserver( editableElement, entry => {\n *\t\t\tconsole.log( 'The editable element has been resized in DOM.' );\n *\t\t\tconsole.log( entry.target ); // -> editableElement\n *\t\t\tconsole.log( entry.contentRect.width ); // -> e.g. '423px'\n *\t\t} );\n *\n * By default, it uses the [native DOM resize observer](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver)\n * under the hood and in browsers that do not support the native API yet, a polyfilled observer is\n * used instead.\n */\nexport default class ResizeObserver {\n\t/**\n\t * Creates an instance of the `ResizeObserver` class.\n\t *\n\t * @param {HTMLElement} element A DOM element that is to be observed for resizing. Note that\n\t * the element must be visible (i.e. not detached from DOM) for the observer to work.\n\t * @param {Function} callback A function called when the observed element was resized. It passes\n\t * the [`ResizeObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry)\n\t * object with information about the resize event.\n\t */\n\tconstructor( element, callback ) {\n\t\t// **Note**: For the maximum performance, this class ensures only a single instance of the native\n\t\t// (or polyfilled) observer is used no matter how many instances of this class were created.\n\t\tif ( !ResizeObserver._observerInstance ) {\n\t\t\tResizeObserver._createObserver();\n\t\t}\n\n\t\t/**\n\t\t * The element observer by this observer.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @member {HTMLElement}\n\t\t */\n\t\tthis._element = element;\n\n\t\t/**\n\t\t * The callback executed each time {@link #_element} is resized.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @member {Function}\n\t\t */\n\t\tthis._callback = callback;\n\n\t\tResizeObserver._addElementCallback( element, callback );\n\t\tResizeObserver._observerInstance.observe( element );\n\t}\n\n\t/**\n\t * Destroys the observer which disables the `callback` passed to the {@link #constructor}.\n\t */\n\tdestroy() {\n\t\tResizeObserver._deleteElementCallback( this._element, this._callback );\n\t}\n\n\t/**\n\t * Registers a new resize callback for the DOM element.\n\t *\n\t * @private\n\t * @static\n\t * @param {HTMLElement} element\n\t * @param {Function} callback\n\t */\n\tstatic _addElementCallback( element, callback ) {\n\t\tif ( !ResizeObserver._elementCallbacks ) {\n\t\t\tResizeObserver._elementCallbacks = new Map();\n\t\t}\n\n\t\tlet callbacks = ResizeObserver._elementCallbacks.get( element );\n\n\t\tif ( !callbacks ) {\n\t\t\tcallbacks = new Set();\n\t\t\tResizeObserver._elementCallbacks.set( element, callbacks );\n\t\t}\n\n\t\tcallbacks.add( callback );\n\t}\n\n\t/**\n\t * Removes a resize callback from the DOM element. If no callbacks are left\n\t * for the element, it removes the element from the native observer.\n\t *\n\t * @private\n\t * @static\n\t * @param {HTMLElement} element\n\t * @param {Function} callback\n\t */\n\tstatic _deleteElementCallback( element, callback ) {\n\t\tconst callbacks = ResizeObserver._getElementCallbacks( element );\n\n\t\t// Remove the element callback. Check if exist first in case someone\n\t\t// called destroy() twice.\n\t\tif ( callbacks ) {\n\t\t\tcallbacks.delete( callback );\n\n\t\t\t// If no callbacks left for the element, also remove the element.\n\t\t\tif ( !callbacks.size ) {\n\t\t\t\tResizeObserver._elementCallbacks.delete( element );\n\t\t\t\tResizeObserver._observerInstance.unobserve( element );\n\t\t\t}\n\t\t}\n\n\t\tif ( ResizeObserver._elementCallbacks && !ResizeObserver._elementCallbacks.size ) {\n\t\t\tResizeObserver._observerInstance = null;\n\t\t\tResizeObserver._elementCallbacks = null;\n\t\t}\n\t}\n\n\t/**\n\t * Returns are registered resize callbacks for the DOM element.\n\t *\n\t * @private\n\t * @static\n\t * @param {HTMLElement} element\n\t * @returns {Set.<HTMLElement>|null}\n\t */\n\tstatic _getElementCallbacks( element ) {\n\t\tif ( !ResizeObserver._elementCallbacks ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn ResizeObserver._elementCallbacks.get( element );\n\t}\n\n\t/**\n\t * Creates the single native observer shared across all `ResizeObserver` instances.\n\t * If the browser does not support the native API, it creates a polyfill.\n\t *\n\t * @private\n\t * @static\n\t */\n\tstatic _createObserver() {\n\t\tlet ObserverConstructor;\n\n\t\t// TODO: One day, the `ResizeObserver` API will be supported in all modern web browsers.\n\t\t// When it happens, this module will no longer make sense and should be removed and\n\t\t// the native implementation should be used across the project to save bytes.\n\t\t// Check out https://caniuse.com/#feat=resizeobserver.\n\t\tif ( typeof global.window.ResizeObserver === 'function' ) {\n\t\t\tObserverConstructor = global.window.ResizeObserver;\n\t\t} else {\n\t\t\tObserverConstructor = ResizeObserverPolyfill;\n\t\t}\n\n\t\tResizeObserver._observerInstance = new ObserverConstructor( entries => {\n\t\t\tfor ( const entry of entries ) {\n\t\t\t\tconst callbacks = ResizeObserver._getElementCallbacks( entry.target );\n\n\t\t\t\tif ( callbacks ) {\n\t\t\t\t\tfor ( const callback of callbacks ) {\n\t\t\t\t\t\tcallback( entry );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n}\n\n/**\n * The single native observer instance (or polyfill in browsers that do not support the API)\n * shared across all {@link module:utils/dom/resizeobserver~ResizeObserver} instances.\n *\n * @static\n * @protected\n * @readonly\n * @property {Object|null} module:utils/dom/resizeobserver~ResizeObserver#_observerInstance\n */\nResizeObserver._observerInstance = null;\n\n/**\n * A mapping of native DOM elements and their callbacks shared across all\n * {@link module:utils/dom/resizeobserver~ResizeObserver} instances.\n *\n * @static\n * @private\n * @readonly\n * @property {Map.<HTMLElement,Set>|null} module:utils/dom/resizeobserver~ResizeObserver#_elementCallbacks\n */\nResizeObserver._elementCallbacks = null;\n\n/**\n * A polyfill class for the native [`ResizeObserver`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver).\n *\n * @private\n * @mixes module:utils/domemittermixin~DomEmitterMixin\n */\nclass ResizeObserverPolyfill {\n\t/**\n\t * Creates an instance of the {@link module:utils/dom/resizeobserver~ResizeObserverPolyfill} class.\n\t *\n\t * It synchronously reacts to resize of the window to check if observed elements' geometry changed.\n\t *\n\t * Additionally, the polyfilled observer uses a timeout to check if observed elements' geometry has changed\n\t * in some other way (dynamic layouts, scrollbars showing up, etc.), so its response can also be asynchronous.\n\t *\n\t * @param {Function} callback A function called when any observed element was resized. Refer to the\n\t * native [`ResizeObserver`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver) API to\n\t * learn more.\n\t */\n\tconstructor( callback ) {\n\t\t/**\n\t\t * A function called when any observed {@link #_elements element} was resized.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {Function}\n\t\t */\n\t\tthis._callback = callback;\n\n\t\t/**\n\t\t * DOM elements currently observed by the observer instance.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {Set}\n\t\t */\n\t\tthis._elements = new Set();\n\n\t\t/**\n\t\t * Cached DOM {@link #_elements elements} bounding rects to compare to upon the next check.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {Map.<HTMLElement,module:utils/dom/rect~Rect>}\n\t\t */\n\t\tthis._previousRects = new Map();\n\n\t\t/**\n\t\t * An UID of the current timeout upon which the observed elements rects\n\t\t * will be compared to the {@link #_previousRects previous rects} from the past.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {Map.<HTMLElement,module:utils/dom/rect~Rect>}\n\t\t */\n\t\tthis._periodicCheckTimeout = null;\n\t}\n\n\t/**\n\t * Starts observing a DOM element.\n\t *\n\t * Learn more in the\n\t * [native method documentation](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/observe).\n\t *\n\t * @param {HTMLElement} element\n\t */\n\tobserve( element ) {\n\t\tthis._elements.add( element );\n\n\t\tthis._checkElementRectsAndExecuteCallback();\n\n\t\tif ( this._elements.size === 1 ) {\n\t\t\tthis._startPeriodicCheck();\n\t\t}\n\t}\n\n\t/**\n\t * Stops observing a DOM element.\n\t *\n\t * Learn more in the\n\t * [native method documentation](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/unobserve).\n\t *\n\t * @param {HTMLElement} element\n\t */\n\tunobserve( element ) {\n\t\tthis._elements.delete( element );\n\t\tthis._previousRects.delete( element );\n\n\t\tif ( !this._elements.size ) {\n\t\t\tthis._stopPeriodicCheck();\n\t\t}\n\t}\n\n\t/**\n\t * When called, the observer calls the {@link #_callback resize callback} for all observed\n\t * {@link #_elements elements} but also starts checking periodically for changes in the elements' geometry.\n\t * If some are detected, {@link #_callback resize callback} is called for relevant elements that were resized.\n\t *\n\t * @protected\n\t */\n\t_startPeriodicCheck() {\n\t\tconst periodicCheck = () => {\n\t\t\tthis._checkElementRectsAndExecuteCallback();\n\t\t\tthis._periodicCheckTimeout = setTimeout( periodicCheck, RESIZE_CHECK_INTERVAL );\n\t\t};\n\n\t\tthis.listenTo( global.window, 'resize', () => {\n\t\t\tthis._checkElementRectsAndExecuteCallback();\n\t\t} );\n\n\t\tthis._periodicCheckTimeout = setTimeout( periodicCheck, RESIZE_CHECK_INTERVAL );\n\t}\n\n\t/**\n\t * Stops checking for changes in all observed {@link #_elements elements} geometry.\n\t *\n\t * @protected\n\t */\n\t_stopPeriodicCheck() {\n\t\tclearTimeout( this._periodicCheckTimeout );\n\t\tthis.stopListening();\n\t\tthis._previousRects.clear();\n\t}\n\n\t/**\n\t * Checks if the geometry of any of the {@link #_elements element} has changed. If so, executes\n\t * the {@link #_callback resize callback} with element geometry data.\n\t *\n\t * @protected\n\t */\n\t_checkElementRectsAndExecuteCallback() {\n\t\tconst entries = [];\n\n\t\tfor ( const element of this._elements ) {\n\t\t\tif ( this._hasRectChanged( element ) ) {\n\t\t\t\tentries.push( {\n\t\t\t\t\ttarget: element,\n\t\t\t\t\tcontentRect: this._previousRects.get( element )\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\n\t\tif ( entries.length ) {\n\t\t\tthis._callback( entries );\n\t\t}\n\t}\n\n\t/**\n\t * Compares the DOM element geometry to the {@link #_previousRects cached geometry} from the past.\n\t * Returns `true` if geometry has changed or the element is checked for the first time.\n\t *\n\t * @protected\n\t * @param {HTMLElement} element\n\t * @returns {Boolean}\n\t */\n\t_hasRectChanged( element ) {\n\t\tif ( !element.ownerDocument.body.contains( element ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst currentRect = new Rect( element );\n\t\tconst previousRect = this._previousRects.get( element );\n\n\t\t// The first check should always yield true despite no Previous rect to compare to.\n\t\t// The native ResizeObserver does that and... that makes sense. Sort of.\n\t\tconst hasChanged = !previousRect || !previousRect.isEqual( currentRect );\n\n\t\tthis._previousRects.set( element, currentRect );\n\n\t\treturn hasChanged;\n\t}\n}\n\nmix( ResizeObserverPolyfill, DomEmitterMixin );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/dropdown/dropdownpanelview\n */\n\nimport View from '../view';\n\n/**\n * The dropdown panel view class.\n *\n * See {@link module:ui/dropdown/dropdownview~DropdownView} to learn about the common usage.\n *\n * @extends module:ui/view~View\n */\nexport default class DropdownPanelView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * Controls whether the panel is visible.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isVisible\n\t\t */\n\t\tthis.set( 'isVisible', false );\n\n\t\t/**\n\t\t * The position of the panel, relative to the parent.\n\t\t *\n\t\t * This property is reflected in the CSS class set to {@link #element} that controls\n\t\t * the position of the panel.\n\t\t *\n\t\t * @observable\n\t\t * @default 'se'\n\t\t * @member {'se'|'sw'|'ne'|'nw'} #position\n\t\t */\n\t\tthis.set( 'position', 'se' );\n\n\t\t/**\n\t\t * Collection of the child views in this panel.\n\t\t *\n\t\t * A common child type is the {@link module:ui/list/listview~ListView} and {@link module:ui/toolbar/toolbarview~ToolbarView}.\n\t\t * See {@link module:ui/dropdown/utils~addListToDropdown} and\n\t\t * {@link module:ui/dropdown/utils~addToolbarToDropdown} to learn more about child views of dropdowns.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-reset',\n\t\t\t\t\t'ck-dropdown__panel',\n\t\t\t\t\tbind.to( 'position', value => `ck-dropdown__panel_${ value }` ),\n\t\t\t\t\tbind.if( 'isVisible', 'ck-dropdown__panel-visible' )\n\t\t\t\t]\n\t\t\t},\n\n\t\t\tchildren: this.children,\n\n\t\t\ton: {\n\t\t\t\t// Drag and drop in the panel should not break the selection in the editor.\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/228\n\t\t\t\tselectstart: bind.to( evt => evt.preventDefault() )\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Focuses the view element or first item in view collection on opening dropdown's panel.\n\t *\n\t * See also {@link module:ui/dropdown/dropdownpanelfocusable~DropdownPanelFocusable}.\n\t */\n\tfocus() {\n\t\tif ( this.children.length ) {\n\t\t\tthis.children.first.focus();\n\t\t}\n\t}\n\n\t/**\n\t * Focuses the view element or last item in view collection on opening dropdown's panel.\n\t *\n\t * See also {@link module:ui/dropdown/dropdownpanelfocusable~DropdownPanelFocusable}.\n\t */\n\tfocusLast() {\n\t\tif ( this.children.length ) {\n\t\t\tconst lastChild = this.children.last;\n\n\t\t\tif ( typeof lastChild.focusLast === 'function' ) {\n\t\t\t\tlastChild.focusLast();\n\t\t\t} else {\n\t\t\t\tlastChild.focus();\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/position\n */\n\nimport global from './global';\nimport Rect from './rect';\nimport getPositionedAncestor from './getpositionedancestor';\nimport getBorderWidths from './getborderwidths';\nimport { isFunction } from 'lodash-es';\n\n/**\n * Calculates the `position: absolute` coordinates of a given element so it can be positioned with respect to the\n * target in the visually most efficient way, taking various restrictions like viewport or limiter geometry\n * into consideration.\n *\n *\t\t// The element which is to be positioned.\n *\t\tconst element = document.body.querySelector( '#toolbar' );\n *\n *\t\t// A target to which the element is positioned relatively.\n *\t\tconst target = document.body.querySelector( '#container' );\n *\n *\t\t// Finding the optimal coordinates for the positioning.\n *\t\tconst { left, top, name } = getOptimalPosition( {\n *\t\t\telement: element,\n *\t\t\ttarget: target,\n *\n * \t\t\t// The algorithm will chose among these positions to meet the requirements such\n * \t\t\t// as \"limiter\" element or \"fitInViewport\", set below. The positions are considered\n * \t\t\t// in the order of the array.\n *\t\t\tpositions: [\n *\t\t\t\t//\n *\t\t\t \t//\t[ Target ]\n *\t\t\t\t//\t+-----------------+\n *\t\t\t\t//\t|     Element     |\n *\t\t\t\t//\t+-----------------+\n *\t\t\t\t//\n *\t\t\t\ttargetRect => ( {\n *\t\t\t\t\ttop: targetRect.bottom,\n *\t\t\t\t\tleft: targetRect.left,\n *\t\t\t\t\tname: 'mySouthEastPosition'\n *\t\t\t\t} ),\n *\n *\t\t\t\t//\n *\t\t\t\t//\t+-----------------+\n *\t\t\t\t//\t|     Element     |\n *\t\t\t\t//\t+-----------------+\n *\t\t\t\t//\t[ Target ]\n *\t\t\t\t//\n *\t\t\t\t( targetRect, elementRect ) => ( {\n *\t\t\t\t\ttop: targetRect.top - elementRect.height,\n *\t\t\t\t\tleft: targetRect.left,\n *\t\t\t\t\tname: 'myNorthEastPosition'\n *\t\t\t\t} )\n *\t\t\t],\n *\n *\t\t\t// Find a position such guarantees the element remains within visible boundaries of <body>.\n *\t\t\tlimiter: document.body,\n *\n *\t\t\t// Find a position such guarantees the element remains within visible boundaries of the browser viewport.\n *\t\t\tfitInViewport: true\n *\t\t} );\n *\n *\t\t// The best position which fits into document.body and the viewport. May be useful\n *\t\t// to set proper class on the `element`.\n *\t\tconsole.log( name ); // -> \"myNorthEastPosition\"\n *\n *\t\t// Using the absolute coordinates which has been found to position the element\n *\t\t// as in the diagram depicting the \"myNorthEastPosition\" position.\n *\t\telement.style.top = top;\n *\t\telement.style.left = left;\n *\n * @param {module:utils/dom/position~Options} options Positioning options object.\n * @returns {module:utils/dom/position~Position}\n */\nexport function getOptimalPosition( { element, target, positions, limiter, fitInViewport } ) {\n\t// If the {@link module:utils/dom/position~Options#target} is a function, use what it returns.\n\t// https://github.com/ckeditor/ckeditor5-utils/issues/157\n\tif ( isFunction( target ) ) {\n\t\ttarget = target();\n\t}\n\n\t// If the {@link module:utils/dom/position~Options#limiter} is a function, use what it returns.\n\t// https://github.com/ckeditor/ckeditor5-ui/issues/260\n\tif ( isFunction( limiter ) ) {\n\t\tlimiter = limiter();\n\t}\n\n\tconst positionedElementAncestor = getPositionedAncestor( element );\n\tconst elementRect = new Rect( element );\n\tconst targetRect = new Rect( target );\n\n\tlet bestPositionRect;\n\tlet bestPositionName;\n\n\t// If there are no limits, just grab the very first position and be done with that drama.\n\tif ( !limiter && !fitInViewport ) {\n\t\t[ bestPositionName, bestPositionRect ] = getPositionNameAndRect( positions[ 0 ], targetRect, elementRect );\n\t} else {\n\t\tconst limiterRect = limiter && new Rect( limiter ).getVisible();\n\t\tconst viewportRect = fitInViewport && new Rect( global.window );\n\t\tconst bestPosition = getBestPositionNameAndRect( positions, { targetRect, elementRect, limiterRect, viewportRect } );\n\n\t\t// If there's no best position found, i.e. when all intersections have no area because\n\t\t// rects have no width or height, then just use the first available position.\n\t\t[ bestPositionName, bestPositionRect ] = bestPosition || getPositionNameAndRect( positions[ 0 ], targetRect, elementRect );\n\t}\n\n\tlet absoluteRectCoordinates = getAbsoluteRectCoordinates( bestPositionRect );\n\n\tif ( positionedElementAncestor ) {\n\t\tabsoluteRectCoordinates = shiftRectCoordinatesDueToPositionedAncestor( absoluteRectCoordinates, positionedElementAncestor );\n\t}\n\n\treturn {\n\t\tleft: absoluteRectCoordinates.left,\n\t\ttop: absoluteRectCoordinates.top,\n\t\tname: bestPositionName\n\t};\n}\n\n// For given position function, returns a corresponding `Rect` instance.\n//\n// @private\n// @param {Function} position A function returning {@link module:utils/dom/position~Position}.\n// @param {utils/dom/rect~Rect} targetRect A rect of the target.\n// @param {utils/dom/rect~Rect} elementRect A rect of positioned element.\n// @returns {Array|null} An array containing position name and its Rect (or null if position should be ignored).\nfunction getPositionNameAndRect( position, targetRect, elementRect ) {\n\tconst positionData = position( targetRect, elementRect );\n\n\tif ( !positionData ) {\n\t\treturn null;\n\t}\n\n\tconst { left, top, name } = positionData;\n\n\treturn [ name, elementRect.clone().moveTo( left, top ) ];\n}\n\n// For a given array of positioning functions, returns such that provides the best\n// fit of the `elementRect` into the `limiterRect` and `viewportRect`.\n//\n// @private\n//\n// @param {Object} options\n// @param {module:utils/dom/position~Options#positions} positions Functions returning {@link module:utils/dom/position~Position}\n// to be checked, in the order of preference.\n// @param {Object} options\n// @param {utils/dom/rect~Rect} options.targetRect A rect of the {@link module:utils/dom/position~Options#target}.\n// @param {utils/dom/rect~Rect} options.elementRect A rect of positioned {@link module:utils/dom/position~Options#element}.\n// @param {utils/dom/rect~Rect} options.limiterRect A rect of the {@link module:utils/dom/position~Options#limiter}.\n// @param {utils/dom/rect~Rect} options.viewportRect A rect of the viewport.\n//\n// @returns {Array} An array containing the name of the position and it's rect.\nfunction getBestPositionNameAndRect( positions, options ) {\n\tconst { elementRect, viewportRect } = options;\n\n\t// This is when element is fully visible.\n\tconst elementRectArea = elementRect.getArea();\n\n\t// Let's calculate intersection areas for positions. It will end early if best match is found.\n\tconst processedPositions = processPositionsToAreas( positions, options );\n\n\t// First let's check all positions that fully fit in the viewport.\n\tif ( viewportRect ) {\n\t\tconst processedPositionsInViewport = processedPositions.filter( ( { viewportIntersectArea } ) => {\n\t\t\treturn viewportIntersectArea === elementRectArea;\n\t\t} );\n\n\t\t// Try to find best position from those which fit completely in viewport.\n\t\tconst bestPositionData = getBestOfProcessedPositions( processedPositionsInViewport, elementRectArea );\n\n\t\tif ( bestPositionData ) {\n\t\t\treturn bestPositionData;\n\t\t}\n\t}\n\n\t// Either there is no viewportRect or there is no position that fits completely in the viewport.\n\treturn getBestOfProcessedPositions( processedPositions, elementRectArea );\n}\n\n// For a given array of positioning functions, calculates intersection areas for them.\n//\n// Note: If some position fully fits into the `limiterRect`, it will be returned early, without further consideration\n// of other positions.\n//\n// @private\n//\n// @param {module:utils/dom/position~Options#positions} positions Functions returning {@link module:utils/dom/position~Position}\n// to be checked, in the order of preference.\n// @param {Object} options\n// @param {utils/dom/rect~Rect} options.targetRect A rect of the {@link module:utils/dom/position~Options#target}.\n// @param {utils/dom/rect~Rect} options.elementRect A rect of positioned {@link module:utils/dom/position~Options#element}.\n// @param {utils/dom/rect~Rect} options.limiterRect A rect of the {@link module:utils/dom/position~Options#limiter}.\n// @param {utils/dom/rect~Rect} options.viewportRect A rect of the viewport.\n//\n// @returns {Array.<Object>} Array of positions with calculated intersection areas. Each item is an object containing:\n// * {String} positionName Name of position.\n// * {utils/dom/rect~Rect} positionRect Rect of position.\n// * {Number} limiterIntersectArea Area of intersection of the position with limiter part that is in the viewport.\n// * {Number} viewportIntersectArea Area of intersection of the position with viewport.\nfunction processPositionsToAreas( positions, { targetRect, elementRect, limiterRect, viewportRect } ) {\n\tconst processedPositions = [];\n\n\t// This is when element is fully visible.\n\tconst elementRectArea = elementRect.getArea();\n\n\tfor ( const position of positions ) {\n\t\tconst positionData = getPositionNameAndRect( position, targetRect, elementRect );\n\n\t\tif ( !positionData ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst [ positionName, positionRect ] = positionData;\n\t\tlet limiterIntersectArea = 0;\n\t\tlet viewportIntersectArea = 0;\n\n\t\tif ( limiterRect ) {\n\t\t\tif ( viewportRect ) {\n\t\t\t\t// Consider only the part of the limiter which is visible in the viewport. So the limiter is getting limited.\n\t\t\t\tconst limiterViewportIntersectRect = limiterRect.getIntersection( viewportRect );\n\n\t\t\t\tif ( limiterViewportIntersectRect ) {\n\t\t\t\t\t// If the limiter is within the viewport, then check the intersection between that part of the\n\t\t\t\t\t// limiter and actual position.\n\t\t\t\t\tlimiterIntersectArea = limiterViewportIntersectRect.getIntersectionArea( positionRect );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlimiterIntersectArea = limiterRect.getIntersectionArea( positionRect );\n\t\t\t}\n\t\t}\n\n\t\tif ( viewportRect ) {\n\t\t\tviewportIntersectArea = viewportRect.getIntersectionArea( positionRect );\n\t\t}\n\n\t\tconst processedPosition = {\n\t\t\tpositionName,\n\t\t\tpositionRect,\n\t\t\tlimiterIntersectArea,\n\t\t\tviewportIntersectArea\n\t\t};\n\n\t\t// If a such position is found that element is fully contained by the limiter then, obviously,\n\t\t// there will be no better one, so finishing.\n\t\tif ( limiterIntersectArea === elementRectArea ) {\n\t\t\treturn [ processedPosition ];\n\t\t}\n\n\t\tprocessedPositions.push( processedPosition );\n\t}\n\n\treturn processedPositions;\n}\n\n// For a given array of processed position data (with calculated Rects for positions and intersection areas)\n// returns such that provides the best fit of the `elementRect` into the `limiterRect` and `viewportRect` at the same time.\n//\n// **Note**: It will return early if some position fully fits into the `limiterRect`.\n//\n// @private\n// @param {Array.<Object>} Array of positions with calculated intersection areas (in order of preference).\n// Each item is an object containing:\n//\n//\t* {String} positionName Name of position.\n//\t* {utils/dom/rect~Rect} positionRect Rect of position.\n//\t* {Number} limiterIntersectArea Area of intersection of the position with limiter part that is in the viewport.\n//\t* {Number} viewportIntersectArea Area of intersection of the position with viewport.\n//\n// @param {Number} elementRectArea Area of positioned {@link module:utils/dom/position~Options#element}.\n// @returns {Array|null} An array containing the name of the position and it's rect, or null if not found.\nfunction getBestOfProcessedPositions( processedPositions, elementRectArea ) {\n\tlet maxFitFactor = 0;\n\tlet bestPositionRect;\n\tlet bestPositionName;\n\n\tfor ( const { positionName, positionRect, limiterIntersectArea, viewportIntersectArea } of processedPositions ) {\n\t\t// If a such position is found that element is fully container by the limiter then, obviously,\n\t\t// there will be no better one, so finishing.\n\t\tif ( limiterIntersectArea === elementRectArea ) {\n\t\t\treturn [ positionName, positionRect ];\n\t\t}\n\n\t\t// To maximize both viewport and limiter intersection areas we use distance on viewportIntersectArea\n\t\t// and limiterIntersectArea plane (without sqrt because we are looking for max value).\n\t\tconst fitFactor = viewportIntersectArea ** 2 + limiterIntersectArea ** 2;\n\n\t\tif ( fitFactor > maxFitFactor ) {\n\t\t\tmaxFitFactor = fitFactor;\n\t\t\tbestPositionRect = positionRect;\n\t\t\tbestPositionName = positionName;\n\t\t}\n\t}\n\n\treturn bestPositionRect ? [ bestPositionName, bestPositionRect ] : null;\n}\n\n// For a given absolute Rect coordinates object and a positioned element ancestor, it returns an object with\n// new Rect coordinates that make up for the position and the scroll of the ancestor.\n//\n// This is necessary because while Rects (and DOMRects) are relative to the browser's viewport, their coordinates\n// are used in real–life to position elements with `position: absolute`, which are scoped by any positioned\n// (and scrollable) ancestors.\n//\n// @private\n//\n// @param {Object} absoluteRectCoordinates An object with absolute rect coordinates.\n// @param {Object} absoluteRectCoordinates.top\n// @param {Object} absoluteRectCoordinates.left\n// @param {HTMLElement} positionedElementAncestor An ancestor element that should be considered.\n//\n// @returns {Object} An object corresponding to `absoluteRectCoordinates` input but with values shifted\n// to make up for the positioned element ancestor.\nfunction shiftRectCoordinatesDueToPositionedAncestor( { left, top }, positionedElementAncestor ) {\n\tconst ancestorPosition = getAbsoluteRectCoordinates( new Rect( positionedElementAncestor ) );\n\tconst ancestorBorderWidths = getBorderWidths( positionedElementAncestor );\n\n\t// (https://github.com/ckeditor/ckeditor5-ui-default/issues/126)\n\t// If there's some positioned ancestor of the panel, then its `Rect` must be taken into\n\t// consideration. `Rect` is always relative to the viewport while `position: absolute` works\n\t// with respect to that positioned ancestor.\n\tleft -= ancestorPosition.left;\n\ttop -= ancestorPosition.top;\n\n\t// (https://github.com/ckeditor/ckeditor5-utils/issues/139)\n\t// If there's some positioned ancestor of the panel, not only its position must be taken into\n\t// consideration (see above) but also its internal scrolls. Scroll have an impact here because `Rect`\n\t// is relative to the viewport (it doesn't care about scrolling), while `position: absolute`\n\t// must compensate that scrolling.\n\tleft += positionedElementAncestor.scrollLeft;\n\ttop += positionedElementAncestor.scrollTop;\n\n\t// (https://github.com/ckeditor/ckeditor5-utils/issues/139)\n\t// If there's some positioned ancestor of the panel, then its `Rect` includes its CSS `borderWidth`\n\t// while `position: absolute` positioning does not consider it.\n\t// E.g. `{ position: absolute, top: 0, left: 0 }` means upper left corner of the element,\n\t// not upper-left corner of its border.\n\tleft -= ancestorBorderWidths.left;\n\ttop -= ancestorBorderWidths.top;\n\n\treturn { left, top };\n}\n\n// DOMRect (also Rect) works in a scroll–independent geometry but `position: absolute` doesn't.\n// This function converts Rect to `position: absolute` coordinates.\n//\n// @private\n// @param {utils/dom/rect~Rect} rect A rect to be converted.\n// @returns {Object} Object containing `left` and `top` properties, in absolute coordinates.\nfunction getAbsoluteRectCoordinates( { left, top } ) {\n\tconst { scrollX, scrollY } = global.window;\n\n\treturn {\n\t\tleft: left + scrollX,\n\t\ttop: top + scrollY\n\t};\n}\n\n/**\n * The `getOptimalPosition()` helper options.\n *\n * @interface module:utils/dom/position~Options\n */\n\n/**\n * Element that is to be positioned.\n *\n * @member {HTMLElement} #element\n */\n\n/**\n * Target with respect to which the `element` is to be positioned.\n *\n * @member {HTMLElement|Range|ClientRect|Rect|Function} #target\n */\n\n/**\n * An array of functions which return {@link module:utils/dom/position~Position} relative\n * to the `target`, in the order of preference.\n *\n * **Note**: If a function returns `null`, it is ignored by the `getOptimalPosition()`.\n *\n * @member {Array.<Function>} #positions\n */\n\n/**\n * When set, the algorithm will chose position which fits the most in the\n * limiter's bounding rect.\n *\n * @member {HTMLElement|Range|ClientRect|Rect|Function} #limiter\n */\n\n/**\n * When set, the algorithm will chose such a position which fits `element`\n * the most inside visible viewport.\n *\n * @member {Boolean} #fitInViewport\n */\n\n/**\n * An object describing a position in `position: absolute` coordinate\n * system, along with position name.\n *\n * @typedef {Object} module:utils/dom/position~Position\n *\n * @property {Number} top Top position offset.\n * @property {Number} left Left position offset.\n * @property {String} name Name of the position.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/getpositionedancestor\n */\n\nimport global from './global';\n\n/**\n * For a given element, returns the nearest ancestor element which CSS position is not \"static\".\n *\n * @param {HTMLElement} element The native DOM element to be checked.\n * @returns {HTMLElement|null}\n */\nexport default function getPositionedAncestor( element ) {\n\tif ( !element || !element.parentNode ) {\n\t\treturn null;\n\t}\n\n\tif ( element.offsetParent === global.document.body ) {\n\t\treturn null;\n\t}\n\n\treturn element.offsetParent;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/dropdown/dropdownview\n */\n\nimport View from '../view';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\n\nimport '../../theme/components/dropdown/dropdown.css';\n\nimport { getOptimalPosition } from '@ckeditor/ckeditor5-utils/src/dom/position';\n\n/**\n * The dropdown view class. It manages the dropdown button and dropdown panel.\n *\n * In most cases, the easiest way to create a dropdown is by using the {@link module:ui/dropdown/utils~createDropdown}\n * util:\n *\n *\t\tconst dropdown = createDropdown( locale );\n *\n *\t\t// Configure dropdown's button properties:\n *\t\tdropdown.buttonView.set( {\n *\t\t\tlabel: 'A dropdown',\n *\t\t\twithText: true\n *\t\t} );\n *\n *\t\tdropdown.render();\n *\n *\t\tdropdown.panelView.element.textContent = 'Content of the panel';\n *\n *\t\t// Will render a dropdown with a panel containing a \"Content of the panel\" text.\n *\t\tdocument.body.appendChild( dropdown.element );\n *\n * If you want to add a richer content to the dropdown panel, you can use the {@link module:ui/dropdown/utils~addListToDropdown}\n * and {@link module:ui/dropdown/utils~addToolbarToDropdown} helpers. See more examples in\n * {@link module:ui/dropdown/utils~createDropdown} documentation.\n *\n * If you want to create a completely custom dropdown, then you can compose it manually:\n *\n *\t\tconst button = new DropdownButtonView( locale );\n *\t\tconst panel = new DropdownPanelView( locale );\n *\t\tconst dropdown = new DropdownView( locale, button, panel );\n *\n *\t\tbutton.set( {\n *\t\t\tlabel: 'A dropdown',\n *\t\t\twithText: true\n *\t\t} );\n *\n *\t\tdropdown.render();\n *\n *\t\tpanel.element.textContent = 'Content of the panel';\n *\n *\t\t// Will render a dropdown with a panel containing a \"Content of the panel\" text.\n *\t\tdocument.body.appendChild( dropdown.element );\n *\n * However, dropdown created this way will contain little behavior. You will need to implement handlers for actions\n * such as {@link module:ui/bindings/clickoutsidehandler~clickOutsideHandler clicking outside an open dropdown}\n * (which should close it) and support for arrow keys inside the panel. Therefore, unless you really know what\n * you do and you really need to do it, it is recommended to use the {@link module:ui/dropdown/utils~createDropdown} helper.\n *\n * @extends module:ui/view~View\n */\nexport default class DropdownView extends View {\n\t/**\n\t * Creates an instance of the dropdown.\n\t *\n\t * Also see {@link #render}.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The localization services instance.\n\t * @param {module:ui/dropdown/button/dropdownbutton~DropdownButton} buttonView\n\t * @param {module:ui/dropdown/dropdownpanelview~DropdownPanelView} panelView\n\t */\n\tconstructor( locale, buttonView, panelView ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * Button of the dropdown view. Clicking the button opens the {@link #panelView}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/button/buttonview~ButtonView} #buttonView\n\t\t */\n\t\tthis.buttonView = buttonView;\n\n\t\t/**\n\t\t * Panel of the dropdown. It opens when the {@link #buttonView} is\n\t\t * {@link module:ui/button/buttonview~ButtonView#event:execute executed} (i.e. clicked).\n\t\t *\n\t\t * Child views can be added to the panel's `children` collection:\n\t\t *\n\t\t *\t\tdropdown.panelView.children.add( childView );\n\t\t *\n\t\t * See {@link module:ui/dropdown/dropdownpanelview~DropdownPanelView#children} and\n\t\t * {@link module:ui/viewcollection~ViewCollection#add}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/dropdown/dropdownpanelview~DropdownPanelView} #panelView\n\t\t */\n\t\tthis.panelView = panelView;\n\n\t\t/**\n\t\t * Controls whether the dropdown view is open, i.e. shows or hides the {@link #panelView panel}.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isOpen\n\t\t */\n\t\tthis.set( 'isOpen', false );\n\n\t\t/**\n\t\t * Controls whether the dropdown is enabled, i.e. it can be clicked and execute an action.\n\t\t *\n\t\t * See {@link module:ui/button/buttonview~ButtonView#isEnabled}.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isEnabled\n\t\t */\n\t\tthis.set( 'isEnabled', true );\n\n\t\t/**\n\t\t * (Optional) The additional CSS class set on the dropdown {@link #element}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #class\n\t\t */\n\t\tthis.set( 'class' );\n\n\t\t/**\n\t\t * (Optional) The `id` attribute of the dropdown (i.e. to pair with a `<label>` element).\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #id\n\t\t */\n\t\tthis.set( 'id' );\n\n\t\t/**\n\t\t * The position of the panel, relative to the dropdown.\n\t\t *\n\t\t * **Note**: When `'auto'`, the panel will use one of the remaining positions to stay\n\t\t * in the viewport, visible to the user. The positions correspond directly to\n\t\t * {@link module:ui/dropdown/dropdownview~DropdownView.defaultPanelPositions default panel positions}.\n\t\t *\n\t\t * **Note**: This value has an impact on the\n\t\t * {@link module:ui/dropdown/dropdownpanelview~DropdownPanelView#position} property\n\t\t * each time the panel becomes {@link #isOpen open}.\n\t\t *\n\t\t * @observable\n\t\t * @default 'auto'\n\t\t * @member {'auto'|'se'|'sw'|'ne'|'nw'} #panelPosition\n\t\t */\n\t\tthis.set( 'panelPosition', 'auto' );\n\n\t\t/**\n\t\t * Instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}. It manages\n\t\t * keystrokes of the dropdown:\n\t\t *\n\t\t * * <kbd>▼</kbd> opens the dropdown,\n\t\t * * <kbd>◀</kbd> and <kbd>Esc</kbd> closes the dropdown.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-dropdown',\n\t\t\t\t\tbind.to( 'class' ),\n\t\t\t\t\tbind.if( 'isEnabled', 'ck-disabled', value => !value )\n\t\t\t\t],\n\t\t\t\tid: bind.to( 'id' ),\n\t\t\t\t'aria-describedby': bind.to( 'ariaDescribedById' )\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\tbuttonView,\n\t\t\t\tpanelView\n\t\t\t]\n\t\t} );\n\n\t\tbuttonView.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck-dropdown__button'\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * A child {@link module:ui/list/listview~ListView list view} of the dropdown located\n\t\t * in its {@link module:ui/dropdown/dropdownview~DropdownView#panelView panel}.\n\t\t *\n\t\t * **Note**: Only supported when dropdown has list view added using {@link module:ui/dropdown/utils~addListToDropdown}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/list/listview~ListView} #listView\n\t\t */\n\n\t\t/**\n\t\t * A child toolbar of the dropdown located in the\n\t\t * {@link module:ui/dropdown/dropdownview~DropdownView#panelView panel}.\n\t\t *\n\t\t * **Note**: Only supported when dropdown has list view added using {@link module:ui/dropdown/utils~addToolbarToDropdown}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ToolbarView} #toolbarView\n\t\t */\n\n\t\t/**\n\t\t * Fired when the toolbar button or list item is executed.\n\t\t *\n\t\t * For {@link #listView} It fires when a child of some {@link module:ui/list/listitemview~ListItemView}\n\t\t * fired `execute`.\n\t\t *\n\t\t * For {@link #toolbarView} It fires when one of the buttons has been\n\t\t * {@link module:ui/button/buttonview~ButtonView#event:execute executed}.\n\t\t *\n\t\t * **Note**: Only supported when dropdown has list view added using {@link module:ui/dropdown/utils~addListToDropdown}\n\t\t * or {@link module:ui/dropdown/utils~addToolbarToDropdown}.\n\t\t *\n\t\t * @event execute\n\t\t */\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Toggle the dropdown when its button has been clicked.\n\t\tthis.listenTo( this.buttonView, 'open', () => {\n\t\t\tthis.isOpen = !this.isOpen;\n\t\t} );\n\n\t\t// Toggle the visibility of the panel when the dropdown becomes open.\n\t\tthis.panelView.bind( 'isVisible' ).to( this, 'isOpen' );\n\n\t\t// Let the dropdown control the position of the panel. The position must\n\t\t// be updated every time the dropdown is open.\n\t\tthis.on( 'change:isOpen', () => {\n\t\t\tif ( !this.isOpen ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If \"auto\", find the best position of the panel to fit into the viewport.\n\t\t\t// Otherwise, simply assign the static position.\n\t\t\tif ( this.panelPosition === 'auto' ) {\n\t\t\t\tthis.panelView.position = DropdownView._getOptimalPosition( {\n\t\t\t\t\telement: this.panelView.element,\n\t\t\t\t\ttarget: this.buttonView.element,\n\t\t\t\t\tfitInViewport: true,\n\t\t\t\t\tpositions: this._panelPositions\n\t\t\t\t} ).name;\n\t\t\t} else {\n\t\t\t\tthis.panelView.position = this.panelPosition;\n\t\t\t}\n\t\t} );\n\n\t\t// Listen for keystrokes coming from within #element.\n\t\tthis.keystrokes.listenTo( this.element );\n\n\t\tconst closeDropdown = ( data, cancel ) => {\n\t\t\tif ( this.isOpen ) {\n\t\t\t\tthis.buttonView.focus();\n\t\t\t\tthis.isOpen = false;\n\t\t\t\tcancel();\n\t\t\t}\n\t\t};\n\n\t\t// Open the dropdown panel using the arrow down key, just like with return or space.\n\t\tthis.keystrokes.set( 'arrowdown', ( data, cancel ) => {\n\t\t\t// Don't open if the dropdown is disabled or already open.\n\t\t\tif ( this.buttonView.isEnabled && !this.isOpen ) {\n\t\t\t\tthis.isOpen = true;\n\t\t\t\tcancel();\n\t\t\t}\n\t\t} );\n\n\t\t// Block the right arrow key (until nested dropdowns are implemented).\n\t\tthis.keystrokes.set( 'arrowright', ( data, cancel ) => {\n\t\t\tif ( this.isOpen ) {\n\t\t\t\tcancel();\n\t\t\t}\n\t\t} );\n\n\t\t// Close the dropdown using the arrow left/escape key.\n\t\tthis.keystrokes.set( 'arrowleft', closeDropdown );\n\t\tthis.keystrokes.set( 'esc', closeDropdown );\n\t}\n\n\t/**\n\t * Focuses the {@link #buttonView}.\n\t */\n\tfocus() {\n\t\tthis.buttonView.focus();\n\t}\n\n\t/**\n\t * Returns {@link #panelView panel} positions to be used by the\n\t * {@link module:utils/dom/position~getOptimalPosition `getOptimalPosition()`}\n\t * utility considering the direction of the language the UI of the editor is displayed in.\n\t *\n\t * @type {module:utils/dom/position~Options#positions}\n\t * @private\n\t */\n\tget _panelPositions() {\n\t\tconst { southEast, southWest, northEast, northWest } = DropdownView.defaultPanelPositions;\n\n\t\tif ( this.locale.uiLanguageDirection === 'ltr' ) {\n\t\t\treturn [ southEast, southWest, northEast, northWest ];\n\t\t} else {\n\t\t\treturn [ southWest, southEast, northWest, northEast ];\n\t\t}\n\t}\n}\n\n/**\n * A set of positioning functions used by the dropdown view to determine\n * the optimal position (i.e. fitting into the browser viewport) of its\n * {@link module:ui/dropdown/dropdownview~DropdownView#panelView panel} when\n * {@link module:ui/dropdown/dropdownview~DropdownView#panelPosition} is set to 'auto'`.\n *\n * The available positioning functions are as follow:\n *\n * **South**\n *\n * * `southEast`\n *\n *\t\t[ Button ]\n *\t\t+-----------------+\n *\t\t|      Panel      |\n *\t\t+-----------------+\n *\n * * `southWest`\n *\n *\t\t         [ Button ]\n *\t\t+-----------------+\n *\t\t|      Panel      |\n *\t\t+-----------------+\n *\n * **North**\n *\n * * `northEast`\n *\n *\t\t+-----------------+\n *\t\t|      Panel      |\n *\t\t+-----------------+\n *\t\t[ Button ]\n *\n * * `northWest`\n *\n *\t\t+-----------------+\n *\t\t|      Panel      |\n *\t\t+-----------------+\n *\t\t         [ Button ]\n *\n * Positioning functions are compatible with {@link module:utils/dom/position~Position}.\n *\n * The name that position function returns will be reflected in dropdown panel's class that\n * controls its placement. See {@link module:ui/dropdown/dropdownview~DropdownView#panelPosition}\n * to learn more.\n *\n * @member {Object} module:ui/dropdown/dropdownview~DropdownView.defaultPanelPositions\n */\nDropdownView.defaultPanelPositions = {\n\tsouthEast: buttonRect => {\n\t\treturn {\n\t\t\ttop: buttonRect.bottom,\n\t\t\tleft: buttonRect.left,\n\t\t\tname: 'se'\n\t\t};\n\t},\n\tsouthWest: ( buttonRect, panelRect ) => {\n\t\treturn {\n\t\t\ttop: buttonRect.bottom,\n\t\t\tleft: buttonRect.left - panelRect.width + buttonRect.width,\n\t\t\tname: 'sw'\n\t\t};\n\t},\n\tnorthEast: ( buttonRect, panelRect ) => {\n\t\treturn {\n\t\t\ttop: buttonRect.top - panelRect.height,\n\t\t\tleft: buttonRect.left,\n\t\t\tname: 'ne'\n\t\t};\n\t},\n\tnorthWest: ( buttonRect, panelRect ) => {\n\t\treturn {\n\t\t\ttop: buttonRect.bottom - panelRect.height,\n\t\t\tleft: buttonRect.left - panelRect.width + buttonRect.width,\n\t\t\tname: 'nw'\n\t\t};\n\t}\n};\n\n/**\n * A function used to calculate the optimal position for the dropdown panel.\n *\n * @protected\n * @member {Function} module:ui/dropdown/dropdownview~DropdownView._getOptimalPosition\n */\nDropdownView._getOptimalPosition = getOptimalPosition;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* global DOMParser */\n\n/**\n * @module ui/icon/iconview\n */\n\nimport View from '../view';\n\nimport '../../theme/components/icon/icon.css';\n\n/**\n * The icon view class.\n *\n * @extends module:ui/view~View\n */\nexport default class IconView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor() {\n\t\tsuper();\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * The SVG source of the icon.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #content\n\t\t */\n\t\tthis.set( 'content', '' );\n\n\t\t/**\n\t\t * This attribute specifies the boundaries to which the\n\t\t * icon content should stretch.\n\t\t *\n\t\t * @observable\n\t\t * @default '0 0 20 20'\n\t\t * @member {String} #viewBox\n\t\t */\n\t\tthis.set( 'viewBox', '0 0 20 20' );\n\n\t\t/**\n\t\t * The fill color of the child `path.ck-icon__fill`.\n\t\t *\n\t\t * @observable\n\t\t * @default ''\n\t\t * @member {String} #fillColor\n\t\t */\n\t\tthis.set( 'fillColor', '' );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'svg',\n\t\t\tns: 'http://www.w3.org/2000/svg',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-icon'\n\t\t\t\t],\n\t\t\t\tviewBox: bind.to( 'viewBox' )\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis._updateXMLContent();\n\t\tthis._colorFillPaths();\n\n\t\t// This is a hack for lack of innerHTML binding.\n\t\t// See: https://github.com/ckeditor/ckeditor5-ui/issues/99.\n\t\tthis.on( 'change:content', () => {\n\t\t\tthis._updateXMLContent();\n\t\t\tthis._colorFillPaths();\n\t\t} );\n\n\t\tthis.on( 'change:fillColor', () => {\n\t\t\tthis._colorFillPaths();\n\t\t} );\n\t}\n\n\t/**\n\t * Updates the {@link #element} with the value of {@link #content}.\n\t *\n\t * @private\n\t */\n\t_updateXMLContent() {\n\t\tif ( this.content ) {\n\t\t\tconst parsed = new DOMParser().parseFromString( this.content.trim(), 'image/svg+xml' );\n\t\t\tconst svg = parsed.querySelector( 'svg' );\n\t\t\tconst viewBox = svg.getAttribute( 'viewBox' );\n\n\t\t\tif ( viewBox ) {\n\t\t\t\tthis.viewBox = viewBox;\n\t\t\t}\n\n\t\t\tthis.element.innerHTML = '';\n\n\t\t\twhile ( svg.childNodes.length > 0 ) {\n\t\t\t\tthis.element.appendChild( svg.childNodes[ 0 ] );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Fills all child `path.ck-icon__fill` with the `#fillColor`.\n\t *\n\t * @private\n\t */\n\t_colorFillPaths() {\n\t\tif ( this.fillColor ) {\n\t\t\tthis.element.querySelectorAll( '.ck-icon__fill' ).forEach( path => {\n\t\t\t\tpath.style.fill = this.fillColor;\n\t\t\t} );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/tooltip/tooltipview\n */\n\nimport View from '../view';\n\nimport '../../theme/components/tooltip/tooltip.css';\n\n/**\n * The tooltip view class.\n *\n * @extends module:ui/view~View\n */\nexport default class TooltipView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * The text of the tooltip visible to the user.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #text\n\t\t */\n\t\tthis.set( 'text', '' );\n\n\t\t/**\n\t\t * The position of the tooltip (south, south-west, south-east, or north).\n\t\t *\n\t\t *\t\t+-----------+\n\t\t *\t\t|   north   |\n\t\t *\t\t+-----------+\n\t\t *\t\t      V\n\t\t *\t\t  [element]\n\t\t *\n\t\t *\t\t  [element]\n\t\t *\t\t      ^\n\t\t *\t\t+-----------+\n\t\t *\t\t|   south   |\n\t\t *\t\t+-----------+\n\t\t *\n\t\t *                +----------+\n\t\t *    [element] < |   east   |\n\t\t *                +----------+\n\t\t *\n\t\t *    +----------+\n\t\t *    |   west   | > [element]\n\t\t *    +----------+\n\t\t *\n\t\t *\t\t         [element]\n\t\t *\t\t             ^\n\t\t *\t\t+--------------+\n\t\t *\t\t|  south west  |\n\t\t *\t\t+--------------+\n\t\t *\n\t\t *\t  [element]\n\t\t *\t\t  ^\n\t\t *\t\t+--------------+\n\t\t *\t\t|  south east  |\n\t\t *\t\t+--------------+\n\n\t\t * @observable\n\t\t * @default 's'\n\t\t * @member {'s'|'n'|'e'|'w'|'sw'|'se'} #position\n\t\t */\n\t\tthis.set( 'position', 's' );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'span',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-tooltip',\n\t\t\t\t\tbind.to( 'position', position => 'ck-tooltip_' + position ),\n\t\t\t\t\tbind.if( 'text', 'ck-hidden', value => !value.trim() )\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'span',\n\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [\n\t\t\t\t\t\t\t'ck',\n\t\t\t\t\t\t\t'ck-tooltip__text'\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttext: bind.to( 'text' )\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/button/buttonview\n */\n\nimport View from '../view';\nimport IconView from '../icon/iconview';\nimport TooltipView from '../tooltip/tooltipview';\n\nimport uid from '@ckeditor/ckeditor5-utils/src/uid';\nimport { getEnvKeystrokeText } from '@ckeditor/ckeditor5-utils/src/keyboard';\n\nimport '../../theme/components/button/button.css';\n\n/**\n * The button view class.\n *\n *\t\tconst view = new ButtonView();\n *\n *\t\tview.set( {\n *\t\t\tlabel: 'A button',\n *\t\t\tkeystroke: 'Ctrl+B',\n *\t\t\ttooltip: true,\n *\t\t\twithText: true\n *\t\t} );\n *\n *\t\tview.render();\n *\n *\t\tdocument.body.append( view.element );\n *\n * @extends module:ui/view~View\n * @implements module:ui/button/button~Button\n */\nexport default class ButtonView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\t\tconst ariaLabelUid = uid();\n\n\t\t// Implement the Button interface.\n\t\tthis.set( 'class' );\n\t\tthis.set( 'labelStyle' );\n\t\tthis.set( 'icon' );\n\t\tthis.set( 'isEnabled', true );\n\t\tthis.set( 'isOn', false );\n\t\tthis.set( 'isVisible', true );\n\t\tthis.set( 'isToggleable', false );\n\t\tthis.set( 'keystroke' );\n\t\tthis.set( 'label' );\n\t\tthis.set( 'tabindex', -1 );\n\t\tthis.set( 'tooltip' );\n\t\tthis.set( 'tooltipPosition', 's' );\n\t\tthis.set( 'type', 'button' );\n\t\tthis.set( 'withText', false );\n\t\tthis.set( 'withKeystroke', false );\n\n\t\t/**\n\t\t * Collection of the child views inside of the button {@link #element}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\n\t\t/**\n\t\t * Tooltip of the button view. It is configurable using the {@link #tooltip tooltip attribute}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/tooltip/tooltipview~TooltipView} #tooltipView\n\t\t */\n\t\tthis.tooltipView = this._createTooltipView();\n\n\t\t/**\n\t\t * Label of the button view. It is configurable using the {@link #label label attribute}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/view~View} #labelView\n\t\t */\n\t\tthis.labelView = this._createLabelView( ariaLabelUid );\n\n\t\t/**\n\t\t * The icon view of the button. Will be added to {@link #children} when the\n\t\t * {@link #icon icon attribute} is defined.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/icon/iconview~IconView} #iconView\n\t\t */\n\t\tthis.iconView = new IconView();\n\n\t\tthis.iconView.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-button__icon'\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * A view displaying the keystroke of the button next to the {@link #labelView label}.\n\t\t * Added to {@link #children} when the {@link #withKeystroke `withKeystroke` attribute}\n\t\t * is defined.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/view/view~View} #keystrokeView\n\t\t */\n\t\tthis.keystrokeView = this._createKeystrokeView();\n\n\t\t/**\n\t\t * Tooltip of the button bound to the template.\n\t\t *\n\t\t * @see #tooltip\n\t\t * @see #_getTooltipString\n\t\t * @private\n\t\t * @observable\n\t\t * @member {Boolean} #_tooltipString\n\t\t */\n\t\tthis.bind( '_tooltipString' ).to(\n\t\t\tthis, 'tooltip',\n\t\t\tthis, 'label',\n\t\t\tthis, 'keystroke',\n\t\t\tthis._getTooltipString.bind( this )\n\t\t);\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'button',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-button',\n\t\t\t\t\tbind.to( 'class' ),\n\t\t\t\t\tbind.if( 'isEnabled', 'ck-disabled', value => !value ),\n\t\t\t\t\tbind.if( 'isVisible', 'ck-hidden', value => !value ),\n\t\t\t\t\tbind.to( 'isOn', value => value ? 'ck-on' : 'ck-off' ),\n\t\t\t\t\tbind.if( 'withText', 'ck-button_with-text' ),\n\t\t\t\t\tbind.if( 'withKeystroke', 'ck-button_with-keystroke' )\n\t\t\t\t],\n\t\t\t\ttype: bind.to( 'type', value => value ? value : 'button' ),\n\t\t\t\ttabindex: bind.to( 'tabindex' ),\n\t\t\t\t'aria-labelledby': `ck-editor__aria-label_${ ariaLabelUid }`,\n\t\t\t\t'aria-disabled': bind.if( 'isEnabled', true, value => !value ),\n\t\t\t\t'aria-pressed': bind.to( 'isOn', value => this.isToggleable ? String( value ) : false )\n\t\t\t},\n\n\t\t\tchildren: this.children,\n\n\t\t\ton: {\n\t\t\t\tmousedown: bind.to( evt => {\n\t\t\t\t\tevt.preventDefault();\n\t\t\t\t} ),\n\n\t\t\t\tclick: bind.to( evt => {\n\t\t\t\t\t// We can't make the button disabled using the disabled attribute, because it won't be focusable.\n\t\t\t\t\t// Though, shouldn't this condition be moved to the button controller?\n\t\t\t\t\tif ( this.isEnabled ) {\n\t\t\t\t\t\tthis.fire( 'execute' );\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Prevent the default when button is disabled, to block e.g.\n\t\t\t\t\t\t// automatic form submitting. See ckeditor/ckeditor5-link#74.\n\t\t\t\t\t\tevt.preventDefault();\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tif ( this.icon ) {\n\t\t\tthis.iconView.bind( 'content' ).to( this, 'icon' );\n\t\t\tthis.children.add( this.iconView );\n\t\t}\n\n\t\tthis.children.add( this.tooltipView );\n\t\tthis.children.add( this.labelView );\n\n\t\tif ( this.withKeystroke ) {\n\t\t\tthis.children.add( this.keystrokeView );\n\t\t}\n\t}\n\n\t/**\n\t * Focuses the {@link #element} of the button.\n\t */\n\tfocus() {\n\t\tthis.element.focus();\n\t}\n\n\t/**\n\t * Creates a {@link module:ui/tooltip/tooltipview~TooltipView} instance and binds it with button\n\t * attributes.\n\t *\n\t * @private\n\t * @returns {module:ui/tooltip/tooltipview~TooltipView}\n\t */\n\t_createTooltipView() {\n\t\tconst tooltipView = new TooltipView();\n\n\t\ttooltipView.bind( 'text' ).to( this, '_tooltipString' );\n\t\ttooltipView.bind( 'position' ).to( this, 'tooltipPosition' );\n\n\t\treturn tooltipView;\n\t}\n\n\t/**\n\t * Creates a label view instance and binds it with button attributes.\n\t *\n\t * @private\n\t * @param {String} ariaLabelUid The aria label UID.\n\t * @returns {module:ui/view~View}\n\t */\n\t_createLabelView( ariaLabelUid ) {\n\t\tconst labelView = new View();\n\t\tconst bind = this.bindTemplate;\n\n\t\tlabelView.setTemplate( {\n\t\t\ttag: 'span',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-button__label'\n\t\t\t\t],\n\t\t\t\tstyle: bind.to( 'labelStyle' ),\n\t\t\t\tid: `ck-editor__aria-label_${ ariaLabelUid }`\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttext: this.bindTemplate.to( 'label' )\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\treturn labelView;\n\t}\n\n\t/**\n\t * Creates a view that displays a keystroke next to a {@link #labelView label }\n\t * and binds it with button attributes.\n\t *\n\t * @private\n\t * @returns {module:ui/view~View}\n\t */\n\t_createKeystrokeView() {\n\t\tconst keystrokeView = new View();\n\n\t\tkeystrokeView.setTemplate( {\n\t\t\ttag: 'span',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-button__keystroke'\n\t\t\t\t]\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttext: this.bindTemplate.to( 'keystroke', text => getEnvKeystrokeText( text ) )\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\treturn keystrokeView;\n\t}\n\n\t/**\n\t * Gets the text for the {@link #tooltipView} from the combination of\n\t * {@link #tooltip}, {@link #label} and {@link #keystroke} attributes.\n\t *\n\t * @private\n\t * @see #tooltip\n\t * @see #_tooltipString\n\t * @param {Boolean|String|Function} tooltip Button tooltip.\n\t * @param {String} label Button label.\n\t * @param {String} keystroke Button keystroke.\n\t * @returns {String}\n\t */\n\t_getTooltipString( tooltip, label, keystroke ) {\n\t\tif ( tooltip ) {\n\t\t\tif ( typeof tooltip == 'string' ) {\n\t\t\t\treturn tooltip;\n\t\t\t} else {\n\t\t\t\tif ( keystroke ) {\n\t\t\t\t\tkeystroke = getEnvKeystrokeText( keystroke );\n\t\t\t\t}\n\n\t\t\t\tif ( tooltip instanceof Function ) {\n\t\t\t\t\treturn tooltip( label, keystroke );\n\t\t\t\t} else {\n\t\t\t\t\treturn `${ label }${ keystroke ? ` (${ keystroke })` : '' }`;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn '';\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 10 10\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M.941 4.523a.75.75 0 1 1 1.06-1.06l3.006 3.005 3.005-3.005a.75.75 0 1 1 1.06 1.06l-3.549 3.55a.75.75 0 0 1-1.168-.136L.941 4.523z\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/dropdown/button/dropdownbuttonview\n */\n\nimport ButtonView from '../../button/buttonview';\n\nimport dropdownArrowIcon from '../../../theme/icons/dropdown-arrow.svg';\nimport IconView from '../../icon/iconview';\n\n/**\n * The default dropdown button view class.\n *\n *\t\tconst view = new DropdownButtonView();\n *\n *\t\tview.set( {\n *\t\t\tlabel: 'A button',\n *\t\t\tkeystroke: 'Ctrl+B',\n *\t\t\ttooltip: true\n *\t\t} );\n *\n *\t\tview.render();\n *\n *\t\tdocument.body.append( view.element );\n *\n * Also see the {@link module:ui/dropdown/utils~createDropdown `createDropdown()` util}.\n *\n * @implements module:ui/dropdown/button/dropdownbutton~DropdownButton\n * @extends module:ui/button/buttonview~ButtonView\n */\nexport default class DropdownButtonView extends ButtonView {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * An icon that displays arrow to indicate a dropdown button.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/icon/iconview~IconView}\n\t\t */\n\t\tthis.arrowView = this._createArrowView();\n\n\t\tthis.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\t'aria-haspopup': true\n\t\t\t}\n\t\t} );\n\n\t\t// The DropdownButton interface expects the open event upon which will open the dropdown.\n\t\tthis.delegate( 'execute' ).to( this, 'open' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.children.add( this.arrowView );\n\t}\n\n\t/**\n\t * Creates a {@link module:ui/icon/iconview~IconView} instance as {@link #arrowView}.\n\t *\n\t * @private\n\t * @returns {module:ui/icon/iconview~IconView}\n\t */\n\t_createArrowView() {\n\t\tconst arrowView = new IconView();\n\n\t\tarrowView.content = dropdownArrowIcon;\n\n\t\tarrowView.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-dropdown__arrow'\n\t\t\t}\n\t\t} );\n\n\t\treturn arrowView;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/list/listview\n */\n\nimport View from '../view';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport FocusCycler from '../focuscycler';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\n\nimport '../../theme/components/list/list.css';\n\n/**\n * The list view class.\n *\n * @extends module:ui/view~View\n * @implements module:ui/dropdown/dropdownpanelfocusable~DropdownPanelFocusable\n */\nexport default class ListView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor() {\n\t\tsuper();\n\n\t\t/**\n\t\t * Collection of the child list views.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.items = this.createCollection();\n\n\t\t/**\n\t\t * Tracks information about DOM focus in the list.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * Instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * Helps cycling over focusable {@link #items} in the list.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this.items,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate list items backwards using the arrowup key.\n\t\t\t\tfocusPrevious: 'arrowup',\n\n\t\t\t\t// Navigate toolbar items forwards using the arrowdown key.\n\t\t\t\tfocusNext: 'arrowdown'\n\t\t\t}\n\t\t} );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'ul',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-reset',\n\t\t\t\t\t'ck-list'\n\t\t\t\t]\n\t\t\t},\n\n\t\t\tchildren: this.items\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Items added before rendering should be known to the #focusTracker.\n\t\tfor ( const item of this.items ) {\n\t\t\tthis.focusTracker.add( item.element );\n\t\t}\n\n\t\tthis.items.on( 'add', ( evt, item ) => {\n\t\t\tthis.focusTracker.add( item.element );\n\t\t} );\n\n\t\tthis.items.on( 'remove', ( evt, item ) => {\n\t\t\tthis.focusTracker.remove( item.element );\n\t\t} );\n\n\t\t// Start listening for the keystrokes coming from #element.\n\t\tthis.keystrokes.listenTo( this.element );\n\t}\n\n\t/**\n\t * Focuses the first focusable in {@link #items}.\n\t */\n\tfocus() {\n\t\tthis._focusCycler.focusFirst();\n\t}\n\n\t/**\n\t * Focuses the last focusable in {@link #items}.\n\t */\n\tfocusLast() {\n\t\tthis._focusCycler.focusLast();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/list/listitemview\n */\n\nimport View from '../view';\n\n/**\n * The list item view class.\n *\n * @extends module:ui/view~View\n */\nexport default class ListItemView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * Collection of the child views inside of the list item {@link #element}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'li',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-list__item'\n\t\t\t\t]\n\t\t\t},\n\n\t\t\tchildren: this.children\n\t\t} );\n\t}\n\n\t/**\n\t * Focuses the list item.\n\t */\n\tfocus() {\n\t\tthis.children.first.focus();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/list/listseparatorview\n */\n\nimport View from '../view';\n\n/**\n * The list separator view class.\n *\n * @extends module:ui/view~View\n */\nexport default class ListSeparatorView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'li',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-list__separator'\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/button/switchbuttonview\n */\n\nimport View from '../view';\nimport ButtonView from './buttonview';\n\nimport '../../theme/components/button/switchbutton.css';\n\n/**\n * The switch button view class.\n *\n *\t\tconst view = new SwitchButtonView();\n *\n *\t\tview.set( {\n *\t\t\twithText: true,\n *\t\t\tlabel: 'Switch me!'\n *\t\t} );\n *\n *\t\tview.render();\n *\n *\t\tdocument.body.append( view.element );\n *\n * @extends module:ui/button/buttonview~ButtonView\n */\nexport default class SwitchButtonView extends ButtonView {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tthis.isToggleable = true;\n\n\t\t/**\n\t\t * The toggle switch of the button.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/view~View} #toggleSwitchView\n\t\t */\n\t\tthis.toggleSwitchView = this._createToggleView();\n\n\t\tthis.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-switchbutton'\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.children.add( this.toggleSwitchView );\n\t}\n\n\t/**\n\t * Creates a toggle child view.\n\t *\n\t * @private\n\t * @returns {module:ui/view~View}\n\t */\n\t_createToggleView() {\n\t\tconst toggleSwitchView = new View();\n\n\t\ttoggleSwitchView.setTemplate( {\n\t\t\ttag: 'span',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-button__toggle'\n\t\t\t\t]\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'span',\n\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [\n\t\t\t\t\t\t\t'ck',\n\t\t\t\t\t\t\t'ck-button__toggle__inner'\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\treturn toggleSwitchView;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/bindings/clickoutsidehandler\n */\n\n/* global document */\n\n/**\n * Handles clicking **outside** of a specified set of elements, then fires an action.\n *\n * **Note**: Actually, the action is executed upon `mousedown`, not `click`. It prevents\n * certain issues when the user keeps holding the mouse button and the UI cannot react\n * properly.\n *\n * @param {Object} options Configuration options.\n * @param {module:utils/dom/emittermixin~Emitter} options.emitter The emitter to which this behavior\n * should be added.\n * @param {Function} options.activator Function returning a `Boolean`, to determine whether the handler is active.\n * @param {Array.<HTMLElement>} options.contextElements HTML elements that determine the scope of the\n * handler. Clicking any of them or their descendants will **not** fire the callback.\n * @param {Function} options.callback An action executed by the handler.\n */\nexport default function clickOutsideHandler( { emitter, activator, callback, contextElements } ) {\n\temitter.listenTo( document, 'mousedown', ( evt, domEvt ) => {\n\t\tif ( !activator() ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if `composedPath` is `undefined` in case the browser does not support native shadow DOM.\n\t\t// Can be removed when all supported browsers support native shadow DOM.\n\t\tconst path = typeof domEvt.composedPath == 'function' ? domEvt.composedPath() : [];\n\n\t\tfor ( const contextElement of contextElements ) {\n\t\t\tif ( contextElement.contains( domEvt.target ) || path.includes( contextElement ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tcallback();\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/dropdown/utils\n */\n\nimport DropdownPanelView from './dropdownpanelview';\nimport DropdownView from './dropdownview';\nimport DropdownButtonView from './button/dropdownbuttonview';\nimport ToolbarView from '../toolbar/toolbarview';\nimport ListView from '../list/listview';\nimport ListItemView from '../list/listitemview';\nimport ListSeparatorView from '../list/listseparatorview';\nimport ButtonView from '../button/buttonview';\nimport SwitchButtonView from '../button/switchbuttonview';\n\nimport clickOutsideHandler from '../bindings/clickoutsidehandler';\n\nimport '../../theme/components/dropdown/toolbardropdown.css';\nimport '../../theme/components/dropdown/listdropdown.css';\n\n/**\n * A helper for creating dropdowns. It creates an instance of a {@link module:ui/dropdown/dropdownview~DropdownView dropdown},\n * with a {@link module:ui/dropdown/button/dropdownbutton~DropdownButton button},\n * {@link module:ui/dropdown/dropdownpanelview~DropdownPanelView panel} and all standard dropdown's behaviors.\n *\n * # Creating dropdowns\n *\n * By default, the default {@link module:ui/dropdown/button/dropdownbuttonview~DropdownButtonView} class is used as\n * definition of the button:\n *\n *\t\tconst dropdown = createDropdown( model );\n *\n *\t\t// Configure dropdown's button properties:\n *\t\tdropdown.buttonView.set( {\n *\t\t\tlabel: 'A dropdown',\n *\t\t\twithText: true\n *\t\t} );\n *\n *\t\tdropdown.render();\n *\n *\t\t// Will render a dropdown labeled \"A dropdown\" with an empty panel.\n *\t\tdocument.body.appendChild( dropdown.element );\n *\n * You can also provide other button views (they need to implement the\n * {@link module:ui/dropdown/button/dropdownbutton~DropdownButton} interface). For instance, you can use\n * {@link module:ui/dropdown/button/splitbuttonview~SplitButtonView} to create a dropdown with a split button.\n *\n *\t\tconst dropdown = createDropdown( model, SplitButtonView );\n *\n *\t\t// Configure dropdown's button properties:\n *\t\tdropdown.buttonView.set( {\n *\t\t\tlabel: 'A dropdown',\n *\t\t\twithText: true\n *\t\t} );\n *\n *\t\tdropdown.buttonView.on( 'execute', () => {\n *\t\t\t// Add the behavior of the \"action part\" of the split button.\n *\t\t\t// Split button consists of the \"action part\" and \"arrow part\".\n *\t\t\t// The arrow opens the dropdown while the action part can have some other behavior.\n * \t\t} );\n *\n *\t\tdropdown.render();\n *\n *\t\t// Will render a dropdown labeled \"A dropdown\" with an empty panel.\n *\t\tdocument.body.appendChild( dropdown.element );\n *\n * # Adding content to the dropdown's panel\n *\n * The content of the panel can be inserted directly into the `dropdown.panelView.element`:\n *\n *\t\tdropdown.panelView.element.textContent = 'Content of the panel';\n *\n * However, most of the time you will want to add there either a {@link module:ui/list/listview~ListView list of options}\n * or a list of buttons (i.e. a {@link module:ui/toolbar/toolbarview~ToolbarView toolbar}).\n * To simplify the task, you can use, respectively, {@link module:ui/dropdown/utils~addListToDropdown} or\n * {@link module:ui/dropdown/utils~addToolbarToDropdown} utils.\n *\n * @param {module:utils/locale~Locale} locale The locale instance.\n * @param {Function} ButtonClass The dropdown button view class. Needs to implement the\n * {@link module:ui/dropdown/button/dropdownbutton~DropdownButton} interface.\n * @returns {module:ui/dropdown/dropdownview~DropdownView} The dropdown view instance.\n */\nexport function createDropdown( locale, ButtonClass = DropdownButtonView ) {\n\tconst buttonView = new ButtonClass( locale );\n\n\tconst panelView = new DropdownPanelView( locale );\n\tconst dropdownView = new DropdownView( locale, buttonView, panelView );\n\n\tbuttonView.bind( 'isEnabled' ).to( dropdownView );\n\n\tif ( buttonView instanceof DropdownButtonView ) {\n\t\tbuttonView.bind( 'isOn' ).to( dropdownView, 'isOpen' );\n\t} else {\n\t\tbuttonView.arrowView.bind( 'isOn' ).to( dropdownView, 'isOpen' );\n\t}\n\n\taddDefaultBehavior( dropdownView );\n\n\treturn dropdownView;\n}\n\n/**\n * Adds an instance of {@link module:ui/toolbar/toolbarview~ToolbarView} to a dropdown.\n *\n *\t\tconst buttons = [];\n *\n *\t\t// Either create a new ButtonView instance or create existing.\n *\t\tbuttons.push( new ButtonView() );\n *\t\tbuttons.push( editor.ui.componentFactory.create( 'someButton' ) );\n *\n *\t\tconst dropdown = createDropdown( locale );\n *\n *\t\taddToolbarToDropdown( dropdown, buttons );\n *\n *\t\tdropdown.toolbarView.isVertical = true;\n *\n *\t\t// Will render a vertical button dropdown labeled \"A button dropdown\"\n *\t\t// with a button group in the panel containing two buttons.\n *\t\tdropdown.render()\n *\t\tdocument.body.appendChild( dropdown.element );\n *\n * See {@link module:ui/dropdown/utils~createDropdown} and {@link module:ui/toolbar/toolbarview~ToolbarView}.\n *\n * @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView A dropdown instance to which `ToolbarView` will be added.\n * @param {Iterable.<module:ui/button/buttonview~ButtonView>} buttons\n */\nexport function addToolbarToDropdown( dropdownView, buttons ) {\n\tconst locale = dropdownView.locale;\n\tconst t = locale.t;\n\tconst toolbarView = dropdownView.toolbarView = new ToolbarView( locale );\n\n\ttoolbarView.set( 'ariaLabel', t( 'Dropdown toolbar' ) );\n\n\tdropdownView.extendTemplate( {\n\t\tattributes: {\n\t\t\tclass: [ 'ck-toolbar-dropdown' ]\n\t\t}\n\t} );\n\n\tbuttons.map( view => toolbarView.items.add( view ) );\n\n\tdropdownView.panelView.children.add( toolbarView );\n\ttoolbarView.items.delegate( 'execute' ).to( dropdownView );\n}\n\n/**\n * Adds an instance of {@link module:ui/list/listview~ListView} to a dropdown.\n *\n *\t\tconst items = new Collection();\n *\n *\t\titems.add( {\n *\t\t\ttype: 'button',\n *\t\t\tmodel: new Model( {\n *\t\t\t\twithText: true,\n *\t\t\t\tlabel: 'First item',\n *\t\t\t\tlabelStyle: 'color: red'\n *\t\t\t} )\n *\t\t} );\n *\n *\t\titems.add( {\n *\t\t\t type: 'button',\n *\t\t\t model: new Model( {\n *\t\t\t\twithText: true,\n *\t\t\t\tlabel: 'Second item',\n *\t\t\t\tlabelStyle: 'color: green',\n *\t\t\t\tclass: 'foo'\n *\t\t\t} )\n *\t\t} );\n *\n *\t\tconst dropdown = createDropdown( locale );\n *\n *\t\taddListToDropdown( dropdown, items );\n *\n *\t\t// Will render a dropdown with a list in the panel containing two items.\n *\t\tdropdown.render()\n *\t\tdocument.body.appendChild( dropdown.element );\n *\n * The `items` collection passed to this methods controls the presence and attributes of respective\n * {@link module:ui/list/listitemview~ListItemView list items}.\n *\n *\n * See {@link module:ui/dropdown/utils~createDropdown} and {@link module:list/list~List}.\n *\n * @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView A dropdown instance to which `ListVIew` will be added.\n * @param {Iterable.<module:ui/dropdown/utils~ListDropdownItemDefinition>} items\n * A collection of the list item definitions to populate the list.\n */\nexport function addListToDropdown( dropdownView, items ) {\n\tconst locale = dropdownView.locale;\n\tconst listView = dropdownView.listView = new ListView( locale );\n\n\tlistView.items.bindTo( items ).using( ( { type, model } ) => {\n\t\tif ( type === 'separator' ) {\n\t\t\treturn new ListSeparatorView( locale );\n\t\t} else if ( type === 'button' || type === 'switchbutton' ) {\n\t\t\tconst listItemView = new ListItemView( locale );\n\t\t\tlet buttonView;\n\n\t\t\tif ( type === 'button' ) {\n\t\t\t\tbuttonView = new ButtonView( locale );\n\t\t\t} else {\n\t\t\t\tbuttonView = new SwitchButtonView( locale );\n\t\t\t}\n\n\t\t\t// Bind all model properties to the button view.\n\t\t\tbuttonView.bind( ...Object.keys( model ) ).to( model );\n\t\t\tbuttonView.delegate( 'execute' ).to( listItemView );\n\n\t\t\tlistItemView.children.add( buttonView );\n\n\t\t\treturn listItemView;\n\t\t}\n\t} );\n\n\tdropdownView.panelView.children.add( listView );\n\n\tlistView.items.delegate( 'execute' ).to( dropdownView );\n}\n\n// Add a set of default behaviors to dropdown view.\n//\n// @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView\nfunction addDefaultBehavior( dropdownView ) {\n\tcloseDropdownOnBlur( dropdownView );\n\tcloseDropdownOnExecute( dropdownView );\n\tfocusDropdownContentsOnArrows( dropdownView );\n}\n\n// Adds a behavior to a dropdownView that closes opened dropdown when user clicks outside the dropdown.\n//\n// @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView\nfunction closeDropdownOnBlur( dropdownView ) {\n\tdropdownView.on( 'render', () => {\n\t\tclickOutsideHandler( {\n\t\t\temitter: dropdownView,\n\t\t\tactivator: () => dropdownView.isOpen,\n\t\t\tcallback: () => {\n\t\t\t\tdropdownView.isOpen = false;\n\t\t\t},\n\t\t\tcontextElements: [ dropdownView.element ]\n\t\t} );\n\t} );\n}\n\n// Adds a behavior to a dropdownView that closes the dropdown view on \"execute\" event.\n//\n// @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView\nfunction closeDropdownOnExecute( dropdownView ) {\n\t// Close the dropdown when one of the list items has been executed.\n\tdropdownView.on( 'execute', evt => {\n\t\t// Toggling a switch button view should not close the dropdown.\n\t\tif ( evt.source instanceof SwitchButtonView ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdropdownView.isOpen = false;\n\t} );\n}\n\n// Adds a behavior to a dropdownView that focuses the dropdown's panel view contents on keystrokes.\n//\n// @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView\nfunction focusDropdownContentsOnArrows( dropdownView ) {\n\t// If the dropdown panel is already open, the arrow down key should focus the first child of the #panelView.\n\tdropdownView.keystrokes.set( 'arrowdown', ( data, cancel ) => {\n\t\tif ( dropdownView.isOpen ) {\n\t\t\tdropdownView.panelView.focus();\n\t\t\tcancel();\n\t\t}\n\t} );\n\n\t// If the dropdown panel is already open, the arrow up key should focus the last child of the #panelView.\n\tdropdownView.keystrokes.set( 'arrowup', ( data, cancel ) => {\n\t\tif ( dropdownView.isOpen ) {\n\t\t\tdropdownView.panelView.focusLast();\n\t\t\tcancel();\n\t\t}\n\t} );\n}\n\n/**\n * A definition of the list item used by the {@link module:ui/dropdown/utils~addListToDropdown}\n * utility.\n *\n * @typedef {Object} module:ui/dropdown/utils~ListDropdownItemDefinition\n *\n * @property {String} type Either `'separator'`, `'button'` or `'switchbutton'`.\n * @property {module:ui/model~Model} [model] Model of the item (when **not** `'separator'`).\n * Its properties fuel the newly created list item (or its children, depending on the `type`).\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/toolbar/toolbarview\n */\n\nimport View from '../view';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport FocusCycler from '../focuscycler';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\nimport ToolbarSeparatorView from './toolbarseparatorview';\nimport ToolbarLineBreakView from './toolbarlinebreakview';\nimport ResizeObserver from '@ckeditor/ckeditor5-utils/src/dom/resizeobserver';\nimport preventDefault from '../bindings/preventdefault.js';\nimport Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport { createDropdown, addToolbarToDropdown } from '../dropdown/utils';\nimport { logWarning } from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport verticalDotsIcon from '@ckeditor/ckeditor5-core/theme/icons/three-vertical-dots.svg';\n\nimport '../../theme/components/toolbar/toolbar.css';\n\n/**\n * The toolbar view class.\n *\n * @extends module:ui/view~View\n * @implements module:ui/dropdown/dropdownpanelfocusable~DropdownPanelFocusable\n */\nexport default class ToolbarView extends View {\n\t/**\n\t * Creates an instance of the {@link module:ui/toolbar/toolbarview~ToolbarView} class.\n\t *\n\t * Also see {@link #render}.\n\t *\n\t * @param {module:utils/locale~Locale} locale The localization services instance.\n\t * @param {module:ui/toolbar/toolbarview~ToolbarOptions} [options] Configuration options of the toolbar.\n\t */\n\tconstructor( locale, options ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\t\tconst t = this.t;\n\n\t\t/**\n\t\t * A reference to the options object passed to the constructor.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ToolbarOptions}\n\t\t */\n\t\tthis.options = options || {};\n\n\t\t/**\n\t\t * Label used by assistive technologies to describe this toolbar element.\n\t\t *\n\t\t * @default 'Editor toolbar'\n\t\t * @member {String} #ariaLabel\n\t\t */\n\t\tthis.set( 'ariaLabel', t( 'Editor toolbar' ) );\n\n\t\t/**\n\t\t * The maximum width of the toolbar element.\n\t\t *\n\t\t * **Note**: When set to a specific value (e.g. `'200px'`), the value will affect the behavior of the\n\t\t * {@link module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull}\n\t\t * option by changing the number of {@link #items} that will be displayed in the toolbar at a time.\n\t\t *\n\t\t * @observable\n\t\t * @default 'auto'\n\t\t * @member {String} #maxWidth\n\t\t */\n\t\tthis.set( 'maxWidth', 'auto' );\n\n\t\t/**\n\t\t * A collection of toolbar items (buttons, dropdowns, etc.).\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.items = this.createCollection();\n\n\t\t/**\n\t\t * Tracks information about the DOM focus in the toolbar.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}\n\t\t * to handle keyboard navigation in the toolbar.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * An additional CSS class added to the {@link #element}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #class\n\t\t */\n\t\tthis.set( 'class' );\n\n\t\t/**\n\t\t * When set true, makes the toolbar look compact with {@link #element}.\n\t\t *\n\t\t * @observable\n\t\t * @default false\n\t\t * @member {String} #isCompact\n\t\t */\n\t\tthis.set( 'isCompact', false );\n\n\t\t/**\n\t\t * A (child) view containing {@link #items toolbar items}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ItemsView}\n\t\t */\n\t\tthis.itemsView = new ItemsView( locale );\n\n\t\t/**\n\t\t * A top–level collection aggregating building blocks of the toolbar.\n\t\t *\n\t\t *\t┌───────────────── ToolbarView ─────────────────┐\n\t\t *\t| ┌──────────────── #children ────────────────┐ |\n\t\t *\t| |   ┌──────────── #itemsView ───────────┐   | |\n\t\t *\t| |   | [ item1 ] [ item2 ] ... [ itemN ] |   | |\n\t\t *\t| |   └──────────────────────────────────-┘   | |\n\t\t *\t| └───────────────────────────────────────────┘ |\n\t\t *\t└───────────────────────────────────────────────┘\n\t\t *\n\t\t * By default, it contains the {@link #itemsView} but it can be extended with additional\n\t\t * UI elements when necessary.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\t\tthis.children.add( this.itemsView );\n\n\t\t/**\n\t\t * A collection of {@link #items} that take part in the focus cycling\n\t\t * (i.e. navigation using the keyboard). Usually, it contains a subset of {@link #items} with\n\t\t * some optional UI elements that also belong to the toolbar and should be focusable\n\t\t * by the user.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.focusables = this.createCollection();\n\n\t\t/**\n\t\t * Controls the orientation of toolbar items. Only available when\n\t\t * {@link module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull dynamic items grouping}\n\t\t * is **disabled**.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isVertical\n\t\t */\n\n\t\t/**\n\t\t * Helps cycling over {@link #focusables focusable items} in the toolbar.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this.focusables,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate toolbar items backwards using the arrow[left,up] keys.\n\t\t\t\tfocusPrevious: [ 'arrowleft', 'arrowup' ],\n\n\t\t\t\t// Navigate toolbar items forwards using the arrow[right,down] keys.\n\t\t\t\tfocusNext: [ 'arrowright', 'arrowdown' ]\n\t\t\t}\n\t\t} );\n\n\t\tconst classes = [\n\t\t\t'ck',\n\t\t\t'ck-toolbar',\n\t\t\tbind.to( 'class' ),\n\t\t\tbind.if( 'isCompact', 'ck-toolbar_compact' )\n\t\t];\n\n\t\tif ( this.options.shouldGroupWhenFull && this.options.isFloating ) {\n\t\t\tclasses.push( 'ck-toolbar_floating' );\n\t\t}\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: classes,\n\t\t\t\trole: 'toolbar',\n\t\t\t\t'aria-label': bind.to( 'ariaLabel' ),\n\t\t\t\tstyle: {\n\t\t\t\t\tmaxWidth: bind.to( 'maxWidth' )\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tchildren: this.children,\n\n\t\t\ton: {\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/206\n\t\t\t\tmousedown: preventDefault( this )\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * An instance of the active toolbar behavior that shapes its look and functionality.\n\t\t *\n\t\t * See {@link module:ui/toolbar/toolbarview~ToolbarBehavior} to learn more.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ToolbarBehavior}\n\t\t */\n\t\tthis._behavior = this.options.shouldGroupWhenFull ? new DynamicGrouping( this ) : new StaticLayout( this );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Children added before rendering should be known to the #focusTracker.\n\t\tfor ( const item of this.items ) {\n\t\t\tthis.focusTracker.add( item.element );\n\t\t}\n\n\t\tthis.items.on( 'add', ( evt, item ) => {\n\t\t\tthis.focusTracker.add( item.element );\n\t\t} );\n\n\t\tthis.items.on( 'remove', ( evt, item ) => {\n\t\t\tthis.focusTracker.remove( item.element );\n\t\t} );\n\n\t\t// Start listening for the keystrokes coming from #element.\n\t\tthis.keystrokes.listenTo( this.element );\n\n\t\tthis._behavior.render( this );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tthis._behavior.destroy();\n\n\t\treturn super.destroy();\n\t}\n\n\t/**\n\t * Focuses the first focusable in {@link #focusables}.\n\t */\n\tfocus() {\n\t\tthis._focusCycler.focusFirst();\n\t}\n\n\t/**\n\t * Focuses the last focusable in {@link #focusables}.\n\t */\n\tfocusLast() {\n\t\tthis._focusCycler.focusLast();\n\t}\n\n\t/**\n\t * A utility that expands the plain toolbar configuration into\n\t * {@link module:ui/toolbar/toolbarview~ToolbarView#items} using a given component factory.\n\t *\n\t * @param {Array.<String>} config The toolbar items configuration.\n\t * @param {module:ui/componentfactory~ComponentFactory} factory A factory producing toolbar items.\n\t */\n\tfillFromConfig( config, factory ) {\n\t\tthis.items.addMany( config.map( name => {\n\t\t\tif ( name == '|' ) {\n\t\t\t\treturn new ToolbarSeparatorView();\n\t\t\t} else if ( name == '-' ) {\n\t\t\t\tif ( this.options.shouldGroupWhenFull ) {\n\t\t\t\t\t/**\n\t\t\t\t\t * Toolbar line breaks can only work the when the automatic button grouping is disabled in the toolbar configuration.\n\t\t\t\t\t * To do this, set the `shouldNotGroupWhenFull` option to `true` in the editor configuration:\n\t\t\t\t\t *\n\t\t\t\t\t *\t\tconst config = {\n\t\t\t\t\t *\t\t\ttoolbar: {\n\t\t\t\t\t *\t\t\t\tshouldNotGroupWhenFull: true\n\t\t\t\t\t *\t\t\t}\n\t\t\t\t\t *\t\t}\n\t\t\t\t\t *\n\t\t\t\t\t * Learn more about {@link module:core/editor/editorconfig~EditorConfig#toolbar toolbar configuration}.\n\t\t\t\t\t *\n\t\t\t\t\t * @error toolbarview-line-break-ignored-when-grouping-items\n\t\t\t\t\t */\n\t\t\t\t\tlogWarning( 'toolbarview-line-break-ignored-when-grouping-items', config );\n\t\t\t\t}\n\n\t\t\t\treturn new ToolbarLineBreakView();\n\t\t\t} else if ( factory.has( name ) ) {\n\t\t\t\treturn factory.create( name );\n\t\t\t} else {\n\t\t\t\t/**\n\t\t\t\t * There was a problem processing the configuration of the toolbar. The item with the given\n\t\t\t\t * name does not exist so it was omitted when rendering the toolbar.\n\t\t\t\t *\n\t\t\t\t * This warning usually shows up when the {@link module:core/plugin~Plugin} which is supposed\n\t\t\t\t * to provide a toolbar item has not been loaded or there is a typo in the configuration.\n\t\t\t\t *\n\t\t\t\t * Make sure the plugin responsible for this toolbar item is loaded and the toolbar configuration\n\t\t\t\t * is correct, e.g. {@link module:basic-styles/bold~Bold} is loaded for the `'bold'` toolbar item.\n\t\t\t\t *\n\t\t\t\t * You can use the following snippet to retrieve all available toolbar items:\n\t\t\t\t *\n\t\t\t\t *\t\tArray.from( editor.ui.componentFactory.names() );\n\t\t\t\t *\n\t\t\t\t * @error toolbarview-item-unavailable\n\t\t\t\t * @param {String} name The name of the component.\n\t\t\t\t */\n\t\t\t\tlogWarning( 'toolbarview-item-unavailable', { name } );\n\t\t\t}\n\t\t} ).filter( item => item !== undefined ) );\n\t}\n\n\t/**\n\t * Fired when some toolbar {@link #items} were grouped or ungrouped as a result of some change\n\t * in the toolbar geometry.\n\t *\n\t * **Note**: This event is always fired **once** regardless of the number of items that were be\n\t * grouped or ungrouped at a time.\n\t *\n\t * **Note**: This event is fired only if the items grouping functionality was enabled in\n\t * the first place (see {@link module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull}).\n\t *\n\t * @event groupedItemsUpdate\n\t */\n}\n\n/**\n * An inner block of the {@link module:ui/toolbar/toolbarview~ToolbarView} hosting its\n * {@link module:ui/toolbar/toolbarview~ToolbarView#items}.\n *\n * @private\n * @extends module:ui/view~View\n */\nclass ItemsView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * A collection of items (buttons, dropdowns, etc.).\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-toolbar__items'\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: this.children\n\t\t} );\n\t}\n}\n\n/**\n * A toolbar behavior that makes it static and unresponsive to the changes of the environment.\n * At the same time, it also makes it possible to display a toolbar with a vertical layout\n * using the {@link module:ui/toolbar/toolbarview~ToolbarView#isVertical} property.\n *\n * @private\n * @implements module:ui/toolbar/toolbarview~ToolbarBehavior\n */\nclass StaticLayout {\n\t/**\n\t * Creates an instance of the {@link module:ui/toolbar/toolbarview~StaticLayout} toolbar\n\t * behavior.\n\t *\n\t * @param {module:ui/toolbar/toolbarview~ToolbarView} view An instance of the toolbar that this behavior\n\t * is added to.\n\t */\n\tconstructor( view ) {\n\t\tconst bind = view.bindTemplate;\n\n\t\t// Static toolbar can be vertical when needed.\n\t\tview.set( 'isVertical', false );\n\n\t\t// 1:1 pass–through binding, all ToolbarView#items are visible.\n\t\tview.itemsView.children.bindTo( view.items ).using( item => item );\n\n\t\t// 1:1 pass–through binding, all ToolbarView#items are focusable.\n\t\tview.focusables.bindTo( view.items ).using( item => item );\n\n\t\tview.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t// When vertical, the toolbar has an additional CSS class.\n\t\t\t\t\tbind.if( 'isVertical', 'ck-toolbar_vertical' )\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {}\n}\n\n/**\n * A toolbar behavior that makes the items respond to changes in the geometry.\n *\n * In a nutshell, it groups {@link module:ui/toolbar/toolbarview~ToolbarView#items}\n * that do not fit visually into a single row of the toolbar (due to limited space).\n * Items that do not fit are aggregated in a dropdown displayed at the end of the toolbar.\n *\n *\t┌──────────────────────────────────────── ToolbarView ──────────────────────────────────────────┐\n *\t| ┌─────────────────────────────────────── #children ─────────────────────────────────────────┐ |\n *\t| |   ┌─────── #itemsView ────────┐ ┌──────────────────────┐ ┌── #groupedItemsDropdown ───┐   | |\n *\t| |   |       #ungroupedItems     | | ToolbarSeparatorView | |        #groupedItems       |   | |\n *\t| |   └──────────────────────────-┘ └──────────────────────┘ └────────────────────────────┘   | |\n *\t| |                                  \\---------- only when toolbar items overflow --------/    | |\n *\t| └───────────────────────────────────────────────────────────────────────────────────────────┘ |\n *\t└───────────────────────────────────────────────────────────────────────────────────────────────┘\n *\n * @private\n * @implements module:ui/toolbar/toolbarview~ToolbarBehavior\n */\nclass DynamicGrouping {\n\t/**\n\t * Creates an instance of the {@link module:ui/toolbar/toolbarview~DynamicGrouping} toolbar\n\t * behavior.\n\t *\n\t * @param {module:ui/toolbar/toolbarview~ToolbarView} view An instance of the toolbar that this behavior\n\t * is added to.\n\t */\n\tconstructor( view ) {\n\t\t/**\n\t\t * A toolbar view this behavior belongs to.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar~ToolbarView}\n\t\t */\n\t\tthis.view = view;\n\n\t\t/**\n\t\t * A collection of toolbar children.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.viewChildren = view.children;\n\n\t\t/**\n\t\t * A collection of focusable toolbar elements.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.viewFocusables = view.focusables;\n\n\t\t/**\n\t\t * A view containing toolbar items.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ItemsView}\n\t\t */\n\t\tthis.viewItemsView = view.itemsView;\n\n\t\t/**\n\t\t * Toolbar focus tracker.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.viewFocusTracker = view.focusTracker;\n\n\t\t/**\n\t\t * Toolbar locale.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/locale~Locale}\n\t\t */\n\t\tthis.viewLocale = view.locale;\n\n\t\t/**\n\t\t * Toolbar element.\n\t\t *\n\t\t * @readonly\n\t\t * @member {HTMLElement} #viewElement\n\t\t */\n\n\t\t/**\n\t\t * A subset of toolbar {@link module:ui/toolbar/toolbarview~ToolbarView#items}.\n\t\t * Aggregates items that fit into a single row of the toolbar and were not {@link #groupedItems grouped}\n\t\t * into a {@link #groupedItemsDropdown dropdown}. Items of this collection are displayed in the\n\t\t * {@link module:ui/toolbar/toolbarview~ToolbarView#itemsView}.\n\t\t *\n\t\t * When none of the {@link module:ui/toolbar/toolbarview~ToolbarView#items} were grouped, it\n\t\t * matches the {@link module:ui/toolbar/toolbarview~ToolbarView#items} collection in size and order.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.ungroupedItems = view.createCollection();\n\n\t\t/**\n\t\t * A subset of toolbar {@link module:ui/toolbar/toolbarview~ToolbarView#items}.\n\t\t * A collection of the toolbar items that do not fit into a single row of the toolbar.\n\t\t * Grouped items are displayed in a dedicated {@link #groupedItemsDropdown dropdown}.\n\t\t *\n\t\t * When none of the {@link module:ui/toolbar/toolbarview~ToolbarView#items} were grouped,\n\t\t * this collection is empty.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.groupedItems = view.createCollection();\n\n\t\t/**\n\t\t * The dropdown that aggregates {@link #groupedItems grouped items} that do not fit into a single\n\t\t * row of the toolbar. It is displayed on demand as the last of\n\t\t * {@link module:ui/toolbar/toolbarview~ToolbarView#children toolbar children} and offers another\n\t\t * (nested) toolbar which displays items that would normally overflow.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/dropdown/dropdownview~DropdownView}\n\t\t */\n\t\tthis.groupedItemsDropdown = this._createGroupedItemsDropdown();\n\n\t\t/**\n\t\t * An instance of the resize observer that helps dynamically determine the geometry of the toolbar\n\t\t * and manage items that do not fit into a single row.\n\t\t *\n\t\t * **Note:** Created in {@link #_enableGroupingOnResize}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/dom/resizeobserver~ResizeObserver}\n\t\t */\n\t\tthis.resizeObserver = null;\n\n\t\t/**\n\t\t * A cached value of the horizontal padding style used by {@link #_updateGrouping}\n\t\t * to manage the {@link module:ui/toolbar/toolbarview~ToolbarView#items} that do not fit into\n\t\t * a single toolbar line. This value can be reused between updates because it is unlikely that\n\t\t * the padding will change and re–using `Window.getComputedStyle()` is expensive.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.cachedPadding = null;\n\n\t\t/**\n\t\t * A flag indicating that an items grouping update has been queued (e.g. due to the toolbar being visible)\n\t\t * and should be executed immediately the next time the toolbar shows up.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis.shouldUpdateGroupingOnNextResize = false;\n\n\t\t// Only those items that were not grouped are visible to the user.\n\t\tview.itemsView.children.bindTo( this.ungroupedItems ).using( item => item );\n\n\t\t// Make sure all #items visible in the main space of the toolbar are \"focuscycleable\".\n\t\tthis.ungroupedItems.on( 'add', this._updateFocusCycleableItems.bind( this ) );\n\t\tthis.ungroupedItems.on( 'remove', this._updateFocusCycleableItems.bind( this ) );\n\n\t\t// Make sure the #groupedItemsDropdown is also included in cycling when it appears.\n\t\tview.children.on( 'add', this._updateFocusCycleableItems.bind( this ) );\n\t\tview.children.on( 'remove', this._updateFocusCycleableItems.bind( this ) );\n\n\t\t// ToolbarView#items is dynamic. When an item is added or removed, it should be automatically\n\t\t// represented in either grouped or ungrouped items at the right index.\n\t\t// In other words #items == concat( #ungroupedItems, #groupedItems )\n\t\t// (in length and order).\n\t\tview.items.on( 'change', ( evt, changeData ) => {\n\t\t\tconst index = changeData.index;\n\n\t\t\t// Removing.\n\t\t\tfor ( const removedItem of changeData.removed ) {\n\t\t\t\tif ( index >= this.ungroupedItems.length ) {\n\t\t\t\t\tthis.groupedItems.remove( removedItem );\n\t\t\t\t} else {\n\t\t\t\t\tthis.ungroupedItems.remove( removedItem );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Adding.\n\t\t\tfor ( let currentIndex = index; currentIndex < index + changeData.added.length; currentIndex++ ) {\n\t\t\t\tconst addedItem = changeData.added[ currentIndex - index ];\n\n\t\t\t\tif ( currentIndex > this.ungroupedItems.length ) {\n\t\t\t\t\tthis.groupedItems.add( addedItem, currentIndex - this.ungroupedItems.length );\n\t\t\t\t} else {\n\t\t\t\t\tthis.ungroupedItems.add( addedItem, currentIndex );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// When new ungrouped items join in and land in #ungroupedItems, there's a chance it causes\n\t\t\t// the toolbar to overflow.\n\t\t\t// Consequently if removed from grouped or ungrouped items, there is a chance\n\t\t\t// some new space is available and we could do some ungrouping.\n\t\t\tthis._updateGrouping();\n\t\t} );\n\n\t\tview.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t// To group items dynamically, the toolbar needs a dedicated CSS class.\n\t\t\t\t\t'ck-toolbar_grouping'\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Enables dynamic items grouping based on the dimensions of the toolbar.\n\t *\n\t * @param {module:ui/toolbar/toolbarview~ToolbarView} view An instance of the toolbar that this behavior\n\t * is added to.\n\t */\n\trender( view ) {\n\t\tthis.viewElement = view.element;\n\n\t\tthis._enableGroupingOnResize();\n\t\tthis._enableGroupingOnMaxWidthChange( view );\n\t}\n\n\t/**\n\t * Cleans up the internals used by this behavior.\n\t */\n\tdestroy() {\n\t\t// The dropdown may not be in ToolbarView#children at the moment of toolbar destruction\n\t\t// so let's make sure it's actually destroyed along with the toolbar.\n\t\tthis.groupedItemsDropdown.destroy();\n\n\t\tthis.resizeObserver.destroy();\n\t}\n\n\t/**\n\t * When called, it will check if any of the {@link #ungroupedItems} do not fit into a single row of the toolbar,\n\t * and it will move them to the {@link #groupedItems} when it happens.\n\t *\n\t * At the same time, it will also check if there is enough space in the toolbar for the first of the\n\t * {@link #groupedItems} to be returned back to {@link #ungroupedItems} and still fit into a single row\n\t * without the toolbar wrapping.\n\t *\n\t * @protected\n\t */\n\t_updateGrouping() {\n\t\t// Do no grouping–related geometry analysis when the toolbar is detached from visible DOM,\n\t\t// for instance before #render(), or after render but without a parent or a parent detached\n\t\t// from DOM. DOMRects won't work anyway and there will be tons of warning in the console and\n\t\t// nothing else. This happens, for instance, when the toolbar is detached from DOM and\n\t\t// some logic adds or removes its #items.\n\t\tif ( !this.viewElement.ownerDocument.body.contains( this.viewElement ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Do not update grouping when the element is invisible. Such toolbar has DOMRect filled with zeros\n\t\t// and that would cause all items to be grouped. Instead, queue the grouping so it runs next time\n\t\t// the toolbar is visible (the next ResizeObserver callback execution). This is handy because\n\t\t// the grouping could be caused by increasing the #maxWidth when the toolbar was invisible and the next\n\t\t// time it shows up, some items could actually be ungrouped (https://github.com/ckeditor/ckeditor5/issues/6575).\n\t\tif ( !this.viewElement.offsetParent ) {\n\t\t\tthis.shouldUpdateGroupingOnNextResize = true;\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Remember how many items were initially grouped so at the it is possible to figure out if the number\n\t\t// of grouped items has changed. If the number has changed, geometry of the toolbar has also changed.\n\t\tconst initialGroupedItemsCount = this.groupedItems.length;\n\t\tlet wereItemsGrouped;\n\n\t\t// Group #items as long as some wrap to the next row. This will happen, for instance,\n\t\t// when the toolbar is getting narrow and there is not enough space to display all items in\n\t\t// a single row.\n\t\twhile ( this._areItemsOverflowing ) {\n\t\t\tthis._groupLastItem();\n\n\t\t\twereItemsGrouped = true;\n\t\t}\n\n\t\t// If none were grouped now but there were some items already grouped before,\n\t\t// then, what the hell, maybe let's see if some of them can be ungrouped. This happens when,\n\t\t// for instance, the toolbar is stretching and there's more space in it than before.\n\t\tif ( !wereItemsGrouped && this.groupedItems.length ) {\n\t\t\t// Ungroup items as long as none are overflowing or there are none to ungroup left.\n\t\t\twhile ( this.groupedItems.length && !this._areItemsOverflowing ) {\n\t\t\t\tthis._ungroupFirstItem();\n\t\t\t}\n\n\t\t\t// If the ungrouping ended up with some item wrapping to the next row,\n\t\t\t// put it back to the group toolbar (\"undo the last ungroup\"). We don't know whether\n\t\t\t// an item will wrap or not until we ungroup it (that's a DOM/CSS thing) so this\n\t\t\t// clean–up is vital for the algorithm.\n\t\t\tif ( this._areItemsOverflowing ) {\n\t\t\t\tthis._groupLastItem();\n\t\t\t}\n\t\t}\n\n\t\tif ( this.groupedItems.length !== initialGroupedItemsCount ) {\n\t\t\tthis.view.fire( 'groupedItemsUpdate' );\n\t\t}\n\t}\n\n\t/**\n\t * Returns `true` when {@link module:ui/toolbar/toolbarview~ToolbarView#element} children visually overflow,\n\t * for instance if the toolbar is narrower than its members. Returns `false` otherwise.\n\t *\n\t * @private\n\t * @type {Boolean}\n\t */\n\tget _areItemsOverflowing() {\n\t\t// An empty toolbar cannot overflow.\n\t\tif ( !this.ungroupedItems.length ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst element = this.viewElement;\n\t\tconst uiLanguageDirection = this.viewLocale.uiLanguageDirection;\n\t\tconst lastChildRect = new Rect( element.lastChild );\n\t\tconst toolbarRect = new Rect( element );\n\n\t\tif ( !this.cachedPadding ) {\n\t\t\tconst computedStyle = global.window.getComputedStyle( element );\n\t\t\tconst paddingProperty = uiLanguageDirection === 'ltr' ? 'paddingRight' : 'paddingLeft';\n\n\t\t\t// parseInt() is essential because of quirky floating point numbers logic and DOM.\n\t\t\t// If the padding turned out too big because of that, the grouped items dropdown would\n\t\t\t// always look (from the Rect perspective) like it overflows (while it's not).\n\t\t\tthis.cachedPadding = Number.parseInt( computedStyle[ paddingProperty ] );\n\t\t}\n\n\t\tif ( uiLanguageDirection === 'ltr' ) {\n\t\t\treturn lastChildRect.right > toolbarRect.right - this.cachedPadding;\n\t\t} else {\n\t\t\treturn lastChildRect.left < toolbarRect.left + this.cachedPadding;\n\t\t}\n\t}\n\n\t/**\n\t * Enables the functionality that prevents {@link #ungroupedItems} from overflowing (wrapping to the next row)\n\t * upon resize when there is little space available. Instead, the toolbar items are moved to the\n\t * {@link #groupedItems} collection and displayed in a dropdown at the end of the row (which has its own nested toolbar).\n\t *\n\t * When called, the toolbar will automatically analyze the location of its {@link #ungroupedItems} and \"group\"\n\t * them in the dropdown if necessary. It will also observe the browser window for size changes in\n\t * the future and respond to them by grouping more items or reverting already grouped back, depending\n\t * on the visual space available.\n\t *\n\t * @private\n\t */\n\t_enableGroupingOnResize() {\n\t\tlet previousWidth;\n\n\t\t// TODO: Consider debounce.\n\t\tthis.resizeObserver = new ResizeObserver( this.viewElement, entry => {\n\t\t\tif ( !previousWidth || previousWidth !== entry.contentRect.width || this.shouldUpdateGroupingOnNextResize ) {\n\t\t\t\tthis.shouldUpdateGroupingOnNextResize = false;\n\n\t\t\t\tthis._updateGrouping();\n\n\t\t\t\tpreviousWidth = entry.contentRect.width;\n\t\t\t}\n\t\t} );\n\n\t\tthis._updateGrouping();\n\t}\n\n\t/**\n\t * Enables the grouping functionality, just like {@link #_enableGroupingOnResize} but the difference is that\n\t * it listens to the changes of {@link module:ui/toolbar/toolbarview~ToolbarView#maxWidth} instead.\n\t *\n\t * @private\n\t */\n\t_enableGroupingOnMaxWidthChange( view ) {\n\t\tview.on( 'change:maxWidth', () => {\n\t\t\tthis._updateGrouping();\n\t\t} );\n\t}\n\n\t/**\n\t * When called, it will remove the last item from {@link #ungroupedItems} and move it back\n\t * to the {@link #groupedItems} collection.\n\t *\n\t * The opposite of {@link #_ungroupFirstItem}.\n\t *\n\t * @private\n\t */\n\t_groupLastItem() {\n\t\tif ( !this.groupedItems.length ) {\n\t\t\tthis.viewChildren.add( new ToolbarSeparatorView() );\n\t\t\tthis.viewChildren.add( this.groupedItemsDropdown );\n\t\t\tthis.viewFocusTracker.add( this.groupedItemsDropdown.element );\n\t\t}\n\n\t\tthis.groupedItems.add( this.ungroupedItems.remove( this.ungroupedItems.last ), 0 );\n\t}\n\n\t/**\n\t * Moves the very first item belonging to {@link #groupedItems} back\n\t * to the {@link #ungroupedItems} collection.\n\t *\n\t * The opposite of {@link #_groupLastItem}.\n\t *\n\t * @private\n\t */\n\t_ungroupFirstItem() {\n\t\tthis.ungroupedItems.add( this.groupedItems.remove( this.groupedItems.first ) );\n\n\t\tif ( !this.groupedItems.length ) {\n\t\t\tthis.viewChildren.remove( this.groupedItemsDropdown );\n\t\t\tthis.viewChildren.remove( this.viewChildren.last );\n\t\t\tthis.viewFocusTracker.remove( this.groupedItemsDropdown.element );\n\t\t}\n\t}\n\n\t/**\n\t * Creates the {@link #groupedItemsDropdown} that hosts the members of the {@link #groupedItems}\n\t * collection when there is not enough space in the toolbar to display all items in a single row.\n\t *\n\t * @private\n\t * @returns {module:ui/dropdown/dropdownview~DropdownView}\n\t */\n\t_createGroupedItemsDropdown() {\n\t\tconst locale = this.viewLocale;\n\t\tconst t = locale.t;\n\t\tconst dropdown = createDropdown( locale );\n\n\t\tdropdown.class = 'ck-toolbar__grouped-dropdown';\n\n\t\t// Make sure the dropdown never sticks out to the left/right. It should be under the main toolbar.\n\t\t// (https://github.com/ckeditor/ckeditor5/issues/5608)\n\t\tdropdown.panelPosition = locale.uiLanguageDirection === 'ltr' ? 'sw' : 'se';\n\n\t\taddToolbarToDropdown( dropdown, [] );\n\n\t\tdropdown.buttonView.set( {\n\t\t\tlabel: t( 'Show more items' ),\n\t\t\ttooltip: true,\n\t\t\ticon: verticalDotsIcon\n\t\t} );\n\n\t\t// 1:1 pass–through binding.\n\t\tdropdown.toolbarView.items.bindTo( this.groupedItems ).using( item => item );\n\n\t\treturn dropdown;\n\t}\n\n\t/**\n\t * Updates the {@link module:ui/toolbar/toolbarview~ToolbarView#focusables focus–cycleable items}\n\t * collection so it represents the up–to–date state of the UI from the perspective of the user.\n\t *\n\t * For instance, the {@link #groupedItemsDropdown} can show up and hide but when it is visible,\n\t * it must be subject to focus cycling in the toolbar.\n\t *\n\t * See the {@link module:ui/toolbar/toolbarview~ToolbarView#focusables collection} documentation\n\t * to learn more about the purpose of this method.\n\t *\n\t * @private\n\t */\n\t_updateFocusCycleableItems() {\n\t\tthis.viewFocusables.clear();\n\n\t\tthis.ungroupedItems.map( item => {\n\t\t\tthis.viewFocusables.add( item );\n\t\t} );\n\n\t\tif ( this.groupedItems.length ) {\n\t\t\tthis.viewFocusables.add( this.groupedItemsDropdown );\n\t\t}\n\t}\n}\n\n/**\n * Options passed to the {@link module:ui/toolbar/toolbarview~ToolbarView#constructor} of the toolbar.\n *\n * @interface module:ui/toolbar/toolbarview~ToolbarOptions\n */\n\n/**\n * When set to `true`, the toolbar will automatically group {@link module:ui/toolbar/toolbarview~ToolbarView#items} that\n * would normally wrap to the next line when there is not enough space to display them in a single row, for\n * instance, if the parent container of the toolbar is narrow. For toolbars in absolutely positioned containers\n * without width restrictions also the {@link module:ui/toolbar/toolbarview~ToolbarOptions#isFloating} option is required to be `true`.\n *\n * See also: {@link module:ui/toolbar/toolbarview~ToolbarView#maxWidth}.\n *\n * @member {Boolean} module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull\n */\n\n/**\n * This option should be enabled for toolbars in absolutely positioned containers without width restrictions\n * to enable automatic {@link module:ui/toolbar/toolbarview~ToolbarView#items} grouping.\n * When this option is set to `true`, the items will stop wrapping to the next line\n * and together with {@link module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull}\n * this will allow grouping them when there is not enough space in a single row.\n *\n * @member {Boolean} module:ui/toolbar/toolbarview~ToolbarOptions#isFloating\n */\n\n/**\n * A class interface defining the behavior of the {@link module:ui/toolbar/toolbarview~ToolbarView}.\n *\n * Toolbar behaviors extend its look and functionality and have an impact on the\n * {@link module:ui/toolbar/toolbarview~ToolbarView#element} template or\n * {@link module:ui/toolbar/toolbarview~ToolbarView#render rendering}. They can be enabled\n * conditionally, e.g. depending on the configuration of the toolbar.\n *\n * @private\n * @interface module:ui/toolbar/toolbarview~ToolbarBehavior\n */\n\n/**\n * Creates a new toolbar behavior instance.\n *\n * The instance is created in the {@link module:ui/toolbar/toolbarview~ToolbarView#constructor} of the toolbar.\n * This is the right place to extend the {@link module:ui/toolbar/toolbarview~ToolbarView#template} of\n * the toolbar, define extra toolbar properties, etc.\n *\n * @method #constructor\n * @param {module:ui/toolbar/toolbarview~ToolbarView} view An instance of the toolbar that this behavior is added to.\n */\n\n/**\n * A method called after the toolbar has been {@link module:ui/toolbar/toolbarview~ToolbarView#render rendered}.\n * It can be used to, for example, customize the behavior of the toolbar when its {@link module:ui/toolbar/toolbarview~ToolbarView#element}\n * is available.\n *\n * @readonly\n * @member {Function} #render\n * @param {module:ui/toolbar/toolbarview~ToolbarView} view An instance of the toolbar being rendered.\n */\n\n/**\n * A method called after the toolbar has been {@link module:ui/toolbar/toolbarview~ToolbarView#destroy destroyed}.\n * It allows cleaning up after the toolbar behavior, for instance, this is the right place to detach\n * event listeners, free up references, etc.\n *\n * @readonly\n * @member {Function} #destroy\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/bindings/preventdefault\n */\n\n/**\n * A helper which executes a native `Event.preventDefault()` if the target of an event equals the\n * {@link module:ui/view~View#element element of the view}. It shortens the definition of a\n * {@link module:ui/view~View#template template}.\n *\n *\t\t// In a class extending View.\n *\t\timport preventDefault from '@ckeditor/ckeditor5-ui/src/bindings/preventdefault';\n *\n *\t\t// ...\n *\n *\t\tthis.setTemplate( {\n *\t\t\ttag: 'div',\n *\n *\t\t\ton: {\n *\t\t\t\t// Prevent the default mousedown action on this view.\n *\t\t\t\tmousedown: preventDefault( this )\n *\t\t\t}\n *\t\t} );\n *\n * @param {module:ui/view~View} view View instance that defines the template.\n * @returns {module:ui/template~TemplateToBinding}\n */\nexport default function preventDefault( view ) {\n\treturn view.bindTemplate.to( evt => {\n\t\tif ( evt.target === view.element ) {\n\t\t\tevt.preventDefault();\n\t\t}\n\t} );\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><circle cx=\\\"9.5\\\" cy=\\\"4.5\\\" r=\\\"1.5\\\"/><circle cx=\\\"9.5\\\" cy=\\\"10.5\\\" r=\\\"1.5\\\"/><circle cx=\\\"9.5\\\" cy=\\\"16.5\\\" r=\\\"1.5\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module editor-classic/classiceditoruiview\n */\n\nimport BoxedEditorUIView from '@ckeditor/ckeditor5-ui/src/editorui/boxed/boxededitoruiview';\nimport InlineEditableUIView from '@ckeditor/ckeditor5-ui/src/editableui/inline/inlineeditableuiview';\nimport StickyPanelView from '@ckeditor/ckeditor5-ui/src/panel/sticky/stickypanelview';\nimport ToolbarView from '@ckeditor/ckeditor5-ui/src/toolbar/toolbarview';\n\nimport '../theme/classiceditor.css';\n\n/**\n * Classic editor UI view. Uses an inline editable and a sticky toolbar, all\n * enclosed in a boxed UI view.\n *\n * @extends module:ui/editorui/boxed/boxededitoruiview~BoxedEditorUIView\n */\nexport default class ClassicEditorUIView extends BoxedEditorUIView {\n\t/**\n\t * Creates an instance of the classic editor UI view.\n\t *\n\t * @param {module:utils/locale~Locale} locale The {@link module:core/editor/editor~Editor#locale} instance.\n\t * @param {module:engine/view/view~View} editingView The editing view instance this view is related to.\n\t * @param {Object} [options={}] Configuration options fo the view instance.\n\t * @param {Boolean} [options.shouldToolbarGroupWhenFull] When set `true` enables automatic items grouping\n\t * in the main {@link module:editor-classic/classiceditoruiview~ClassicEditorUIView#toolbar toolbar}.\n\t * See {@link module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull} to learn more.\n\t */\n\tconstructor( locale, editingView, options = {} ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * Sticky panel view instance. This is a parent view of a {@link #toolbar}\n\t\t * that makes toolbar sticky.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/panel/sticky/stickypanelview~StickyPanelView}\n\t\t */\n\t\tthis.stickyPanel = new StickyPanelView( locale );\n\n\t\t/**\n\t\t * Toolbar view instance.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ToolbarView}\n\t\t */\n\t\tthis.toolbar = new ToolbarView( locale, {\n\t\t\tshouldGroupWhenFull: options.shouldToolbarGroupWhenFull\n\t\t} );\n\n\t\t/**\n\t\t * Editable UI view.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/editableui/inline/inlineeditableuiview~InlineEditableUIView}\n\t\t */\n\t\tthis.editable = new InlineEditableUIView( locale, editingView );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Set toolbar as a child of a stickyPanel and makes toolbar sticky.\n\t\tthis.stickyPanel.content.add( this.toolbar );\n\n\t\tthis.top.add( this.stickyPanel );\n\t\tthis.main.add( this.editable );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module editor-classic/classiceditor\n */\n\nimport Editor from '@ckeditor/ckeditor5-core/src/editor/editor';\nimport DataApiMixin from '@ckeditor/ckeditor5-core/src/editor/utils/dataapimixin';\nimport ElementApiMixin from '@ckeditor/ckeditor5-core/src/editor/utils/elementapimixin';\nimport attachToForm from '@ckeditor/ckeditor5-core/src/editor/utils/attachtoform';\nimport HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';\nimport ClassicEditorUI from './classiceditorui';\nimport ClassicEditorUIView from './classiceditoruiview';\nimport getDataFromElement from '@ckeditor/ckeditor5-utils/src/dom/getdatafromelement';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport { isElement } from 'lodash-es';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * The {@glink builds/guides/overview#classic-editor classic editor} implementation.\n * It uses an inline editable and a sticky toolbar, all enclosed in a boxed UI.\n * See the {@glink examples/builds/classic-editor demo}.\n *\n * In order to create a classic editor instance, use the static\n * {@link module:editor-classic/classiceditor~ClassicEditor.create `ClassicEditor.create()`} method.\n *\n * # Classic editor and classic build\n *\n * The classic editor can be used directly from source (if you installed the\n * [`@ckeditor/ckeditor5-editor-classic`](https://www.npmjs.com/package/@ckeditor/ckeditor5-editor-classic) package)\n * but it is also available in the {@glink builds/guides/overview#classic-editor classic build}.\n *\n * {@glink builds/guides/overview Builds} are ready-to-use editors with plugins bundled in. When using the editor from\n * source you need to take care of loading all plugins by yourself\n * (through the {@link module:core/editor/editorconfig~EditorConfig#plugins `config.plugins`} option).\n * Using the editor from source gives much better flexibility and allows easier customization.\n *\n * Read more about initializing the editor from source or as a build in\n * {@link module:editor-classic/classiceditor~ClassicEditor.create `ClassicEditor.create()`}.\n *\n * @mixes module:core/editor/utils/dataapimixin~DataApiMixin\n * @mixes module:core/editor/utils/elementapimixin~ElementApiMixin\n * @implements module:core/editor/editorwithui~EditorWithUI\n * @extends module:core/editor/editor~Editor\n */\nexport default class ClassicEditor extends Editor {\n\t/**\n\t * Creates an instance of the classic editor.\n\t *\n\t * **Note:** do not use the constructor to create editor instances. Use the static\n\t * {@link module:editor-classic/classiceditor~ClassicEditor.create `ClassicEditor.create()`} method instead.\n\t *\n\t * @protected\n\t * @param {HTMLElement|String} sourceElementOrData The DOM element that will be the source for the created editor\n\t * or the editor's initial data. For more information see\n\t * {@link module:editor-classic/classiceditor~ClassicEditor.create `ClassicEditor.create()`}.\n\t * @param {module:core/editor/editorconfig~EditorConfig} config The editor configuration.\n\t */\n\tconstructor( sourceElementOrData, config ) {\n\t\tsuper( config );\n\n\t\tif ( isElement( sourceElementOrData ) ) {\n\t\t\tthis.sourceElement = sourceElementOrData;\n\t\t}\n\n\t\tthis.data.processor = new HtmlDataProcessor( this.data.viewDocument );\n\n\t\tthis.model.document.createRoot();\n\n\t\tconst shouldToolbarGroupWhenFull = !this.config.get( 'toolbar.shouldNotGroupWhenFull' );\n\t\tconst view = new ClassicEditorUIView( this.locale, this.editing.view, {\n\t\t\tshouldToolbarGroupWhenFull\n\t\t} );\n\n\t\tthis.ui = new ClassicEditorUI( this, view );\n\n\t\tattachToForm( this );\n\t}\n\n\t/**\n\t * Destroys the editor instance, releasing all resources used by it.\n\t *\n\t * Updates the editor's source element with the data.\n\t *\n\t * @returns {Promise}\n\t */\n\tdestroy() {\n\t\tif ( this.sourceElement ) {\n\t\t\tthis.updateSourceElement();\n\t\t}\n\n\t\tthis.ui.destroy();\n\n\t\treturn super.destroy();\n\t}\n\n\t/**\n\t * Creates a new classic editor instance.\n\t *\n\t * There are three ways how the editor can be initialized.\n\t *\n\t * # Replacing a DOM element (and loading data from it)\n\t *\n\t * You can initialize the editor using an existing DOM element:\n\t *\n\t *\t\tClassicEditor\n\t *\t\t\t.create( document.querySelector( '#editor' ) )\n\t *\t\t\t.then( editor => {\n\t *\t\t\t\tconsole.log( 'Editor was initialized', editor );\n\t *\t\t\t} )\n\t *\t\t\t.catch( err => {\n\t *\t\t\t\tconsole.error( err.stack );\n\t *\t\t\t} );\n\t *\n\t * The element's content will be used as the editor data and the element will be replaced by the editor UI.\n\t *\n\t * # Creating a detached editor\n\t *\n\t * Alternatively, you can initialize the editor by passing the initial data directly as a string.\n\t * In this case, the editor will render an element that must be inserted into the DOM:\n\t *\n\t *\t\tClassicEditor\n\t *\t\t\t.create( '<p>Hello world!</p>' )\n\t *\t\t\t.then( editor => {\n\t *\t\t\t\tconsole.log( 'Editor was initialized', editor );\n\t *\n\t *\t\t\t\t// Initial data was provided so the editor UI element needs to be added manually to the DOM.\n\t *\t\t\t\tdocument.body.appendChild( editor.ui.element );\n\t *\t\t\t} )\n\t *\t\t\t.catch( err => {\n\t *\t\t\t\tconsole.error( err.stack );\n\t *\t\t\t} );\n\t *\n\t * This lets you dynamically append the editor to your web page whenever it is convenient for you. You may use this method if your\n\t * web page content is generated on the client side and the DOM structure is not ready at the moment when you initialize the editor.\n\t *\n\t * # Replacing a DOM element (and data provided in `config.initialData`)\n\t *\n\t * You can also mix these two ways by providing a DOM element to be used and passing the initial data through the configuration:\n\t *\n\t *\t\tClassicEditor\n\t *\t\t\t.create( document.querySelector( '#editor' ), {\n\t *\t\t\t\tinitialData: '<h2>Initial data</h2><p>Foo bar.</p>'\n\t *\t\t\t} )\n\t *\t\t\t.then( editor => {\n\t *\t\t\t\tconsole.log( 'Editor was initialized', editor );\n\t *\t\t\t} )\n\t *\t\t\t.catch( err => {\n\t *\t\t\t\tconsole.error( err.stack );\n\t *\t\t\t} );\n\t *\n\t * This method can be used to initialize the editor on an existing element with the specified content in case if your integration\n\t * makes it difficult to set the content of the source element.\n\t *\n\t * Note that an error will be thrown if you pass the initial data both as the first parameter and also in the configuration.\n\t *\n\t * # Configuring the editor\n\t *\n\t * See the {@link module:core/editor/editorconfig~EditorConfig editor configuration documentation} to learn more about\n\t * customizing plugins, toolbar and more.\n\t *\n\t * # Using the editor from source\n\t *\n\t * The code samples listed in the previous sections of this documentation assume that you are using an\n\t * {@glink builds/guides/overview editor build} (for example – `@ckeditor/ckeditor5-build-classic`).\n\t *\n\t * If you want to use the classic editor from source (`@ckeditor/ckeditor5-editor-classic/src/classiceditor`),\n\t * you need to define the list of\n\t * {@link module:core/editor/editorconfig~EditorConfig#plugins plugins to be initialized} and\n\t * {@link module:core/editor/editorconfig~EditorConfig#toolbar toolbar items}. Read more about using the editor from\n\t * source in the {@glink builds/guides/integration/advanced-setup \"Advanced setup\" guide}.\n\t *\n\t * @param {HTMLElement|String} sourceElementOrData The DOM element that will be the source for the created editor\n\t * or the editor's initial data.\n\t *\n\t * If a DOM element is passed, its content will be automatically loaded to the editor upon initialization\n\t * and the {@link module:editor-classic/classiceditorui~ClassicEditorUI#element editor element} will replace the passed element\n\t * in the DOM (the original one will be hidden and the editor will be injected next to it).\n\t *\n\t * Moreover, the editor data will be set back to the original element once the editor is destroyed and when a form, in which\n\t * this element is contained, is submitted (if the original element is a `<textarea>`). This ensures seamless integration with native\n\t * web forms.\n\t *\n\t * If the initial data is passed, a detached editor will be created. In this case you need to insert it into the DOM manually.\n\t * It is available under the {@link module:editor-classic/classiceditorui~ClassicEditorUI#element `editor.ui.element`} property.\n\t *\n\t * @param {module:core/editor/editorconfig~EditorConfig} [config] The editor configuration.\n\t * @returns {Promise} A promise resolved once the editor is ready. The promise resolves with the created editor instance.\n\t */\n\tstatic create( sourceElementOrData, config = {} ) {\n\t\treturn new Promise( resolve => {\n\t\t\tconst editor = new this( sourceElementOrData, config );\n\n\t\t\tresolve(\n\t\t\t\teditor.initPlugins()\n\t\t\t\t\t.then( () => editor.ui.init( isElement( sourceElementOrData ) ? sourceElementOrData : null ) )\n\t\t\t\t\t.then( () => {\n\t\t\t\t\t\tif ( !isElement( sourceElementOrData ) && config.initialData ) {\n\t\t\t\t\t\t\t// Documented in core/editor/editorconfig.jdoc.\n\t\t\t\t\t\t\t// eslint-disable-next-line ckeditor5-rules/ckeditor-error-message\n\t\t\t\t\t\t\tthrow new CKEditorError( 'editor-create-initial-data', null );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst initialData = config.initialData || getInitialData( sourceElementOrData );\n\n\t\t\t\t\t\treturn editor.data.init( initialData );\n\t\t\t\t\t} )\n\t\t\t\t\t.then( () => editor.fire( 'ready' ) )\n\t\t\t\t\t.then( () => editor )\n\t\t\t);\n\t\t} );\n\t}\n}\n\nmix( ClassicEditor, DataApiMixin );\nmix( ClassicEditor, ElementApiMixin );\n\nfunction getInitialData( sourceElementOrData ) {\n\treturn isElement( sourceElementOrData ) ? getDataFromElement( sourceElementOrData ) : sourceElementOrData;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport { isFunction } from 'lodash-es';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * @module core/editor/utils/attachtoform\n */\n\n/**\n * Checks if the editor is initialized on a `<textarea>` element that belongs to a form. If yes, it updates the editor's element\n * content before submitting the form.\n *\n * This helper requires the {@link module:core/editor/utils/elementapimixin~ElementApi ElementApi interface}.\n *\n * @param {module:core/editor/editor~Editor} editor Editor instance.\n */\nexport default function attachToForm( editor ) {\n\tif ( !isFunction( editor.updateSourceElement ) ) {\n\t\t/**\n\t\t * The editor passed to `attachToForm()` must implement the\n\t\t * {@link module:core/editor/utils/elementapimixin~ElementApi} interface.\n\t\t *\n\t\t * @error attachtoform-missing-elementapi-interface\n\t\t */\n\t\tthrow new CKEditorError(\n\t\t\t'attachtoform-missing-elementapi-interface',\n\t\t\teditor\n\t\t);\n\t}\n\n\tconst sourceElement = editor.sourceElement;\n\n\t// Only when replacing a textarea which is inside of a form element.\n\tif ( sourceElement && sourceElement.tagName.toLowerCase() === 'textarea' && sourceElement.form ) {\n\t\tlet originalSubmit;\n\t\tconst form = sourceElement.form;\n\t\tconst onSubmit = () => editor.updateSourceElement();\n\n\t\t// Replace the original form#submit() to call a custom submit function first.\n\t\t// Check if #submit is a function because the form might have an input named \"submit\".\n\t\tif ( isFunction( form.submit ) ) {\n\t\t\toriginalSubmit = form.submit;\n\n\t\t\tform.submit = () => {\n\t\t\t\tonSubmit();\n\t\t\t\toriginalSubmit.apply( form );\n\t\t\t};\n\t\t}\n\n\t\t// Update the replaced textarea with data before each form#submit event.\n\t\tform.addEventListener( 'submit', onSubmit );\n\n\t\t// Remove the submit listener and revert the original submit method on\n\t\t// editor#destroy.\n\t\teditor.on( 'destroy', () => {\n\t\t\tform.removeEventListener( 'submit', onSubmit );\n\n\t\t\tif ( originalSubmit ) {\n\t\t\t\tform.submit = originalSubmit;\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* globals HTMLTextAreaElement */\n\n/**\n * @module utils/dom/getdatafromelement\n */\n\n/**\n * Gets data from a given source element.\n *\n * @param {HTMLElement} el The element from which the data will be retrieved.\n * @returns {String} The data string.\n */\nexport default function getDataFromElement( el ) {\n\tif ( el instanceof HTMLTextAreaElement ) {\n\t\treturn el.value;\n\t}\n\n\treturn el.innerHTML;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module core/plugin\n */\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * The base class for CKEditor plugin classes.\n *\n * @implements module:core/plugin~PluginInterface\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\t/**\n\t\t * The editor instance.\n\t\t *\n\t\t * Note that most editors implement the {@link module:core/editor/editorwithui~EditorWithUI} interface in addition\n\t\t * to the base {@link module:core/editor/editor~Editor} interface. However, editors with an external UI\n\t\t * (i.e. Bootstrap-based) or a headless editor may not implement the {@link module:core/editor/editorwithui~EditorWithUI}\n\t\t * interface.\n\t\t *\n\t\t * Because of above, to make plugins more universal, it is recommended to split features into:\n\t\t *  - The \"editing\" part that only uses the {@link module:core/editor/editor~Editor} interface.\n\t\t *  - The \"UI\" part that uses both the {@link module:core/editor/editor~Editor} interface and\n\t\t *  the {@link module:core/editor/editorwithui~EditorWithUI} interface.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editor/editor~Editor} #editor\n\t\t */\n\t\tthis.editor = editor;\n\n\t\t/**\n\t\t * Flag indicating whether a plugin is enabled or disabled.\n\t\t * A disabled plugin will not transform text.\n\t\t *\n\t\t * Plugin can be simply disabled like that:\n\t\t *\n\t\t *\t\t// Disable the plugin so that no toolbars are visible.\n\t\t *\t\teditor.plugins.get( 'TextTransformation' ).isEnabled = false;\n\t\t *\n\t\t * You can also use {@link #forceDisabled} method.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #isEnabled\n\t\t */\n\t\tthis.set( 'isEnabled', true );\n\n\t\t/**\n\t\t * Holds identifiers for {@link #forceDisabled} mechanism.\n\t\t *\n\t\t * @type {Set.<String>}\n\t\t * @private\n\t\t */\n\t\tthis._disableStack = new Set();\n\t}\n\n\t/**\n\t * Disables the plugin.\n\t *\n\t * Plugin may be disabled by multiple features or algorithms (at once). When disabling a plugin, unique id should be passed\n\t * (e.g. feature name). The same identifier should be used when {@link #clearForceDisabled enabling back} the plugin.\n\t * The plugin becomes enabled only after all features {@link #clearForceDisabled enabled it back}.\n\t *\n\t * Disabling and enabling a plugin:\n\t *\n\t *\t\tplugin.isEnabled; // -> true\n\t *\t\tplugin.forceDisabled( 'MyFeature' );\n\t *\t\tplugin.isEnabled; // -> false\n\t *\t\tplugin.clearForceDisabled( 'MyFeature' );\n\t *\t\tplugin.isEnabled; // -> true\n\t *\n\t * Plugin disabled by multiple features:\n\t *\n\t *\t\tplugin.forceDisabled( 'MyFeature' );\n\t *\t\tplugin.forceDisabled( 'OtherFeature' );\n\t *\t\tplugin.clearForceDisabled( 'MyFeature' );\n\t *\t\tplugin.isEnabled; // -> false\n\t *\t\tplugin.clearForceDisabled( 'OtherFeature' );\n\t *\t\tplugin.isEnabled; // -> true\n\t *\n\t * Multiple disabling with the same identifier is redundant:\n\t *\n\t *\t\tplugin.forceDisabled( 'MyFeature' );\n\t *\t\tplugin.forceDisabled( 'MyFeature' );\n\t *\t\tplugin.clearForceDisabled( 'MyFeature' );\n\t *\t\tplugin.isEnabled; // -> true\n\t *\n\t * **Note:** some plugins or algorithms may have more complex logic when it comes to enabling or disabling certain plugins,\n\t * so the plugin might be still disabled after {@link #clearForceDisabled} was used.\n\t *\n\t * @param {String} id Unique identifier for disabling. Use the same id when {@link #clearForceDisabled enabling back} the plugin.\n\t */\n\tforceDisabled( id ) {\n\t\tthis._disableStack.add( id );\n\n\t\tif ( this._disableStack.size == 1 ) {\n\t\t\tthis.on( 'set:isEnabled', forceDisable, { priority: 'highest' } );\n\t\t\tthis.isEnabled = false;\n\t\t}\n\t}\n\n\t/**\n\t * Clears forced disable previously set through {@link #forceDisabled}. See {@link #forceDisabled}.\n\t *\n\t * @param {String} id Unique identifier, equal to the one passed in {@link #forceDisabled} call.\n\t */\n\tclearForceDisabled( id ) {\n\t\tthis._disableStack.delete( id );\n\n\t\tif ( this._disableStack.size == 0 ) {\n\t\t\tthis.off( 'set:isEnabled', forceDisable );\n\t\t\tthis.isEnabled = true;\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get isContextPlugin() {\n\t\treturn false;\n\t}\n}\n\nmix( Plugin, ObservableMixin );\n\n/**\n * The base interface for CKEditor plugins.\n *\n * In its minimal form a plugin can be a simple function that accepts {@link module:core/editor/editor~Editor the editor}\n * as a parameter:\n *\n *\t\t// A simple plugin that enables a data processor.\n *\t\tfunction MyPlugin( editor ) {\n *\t\t\teditor.data.processor = new MyDataProcessor();\n *\t\t}\n *\n * In most cases however, you will want to inherit from the {@link module:core/plugin~Plugin} class which implements the\n * {@link module:utils/observablemixin~ObservableMixin} and is, therefore, more convenient:\n *\n *\t\tclass MyPlugin extends Plugin {\n *\t\t\tinit() {\n *\t\t\t\t// `listenTo()` and `editor` are available thanks to `Plugin`.\n *\t\t\t\t// By using `listenTo()` you will ensure that the listener is removed when\n *\t\t\t\t// the plugin is destroyed.\n *\t\t\t\tthis.listenTo( this.editor.data, 'ready', () => {\n *\t\t\t\t\t// Do something when the data is ready.\n *\t\t\t\t} );\n *\t\t\t}\n *\t\t}\n *\n * The plugin can also implement methods (e.g. {@link module:core/plugin~PluginInterface#init `init()`} or\n * {@link module:core/plugin~PluginInterface#destroy `destroy()`}) which, when present, will be used to properly\n * initialize and destroy the plugin.\n *\n * **Note:** When defined as a plain function, the plugin acts as a constructor and will be\n * called in parallel with other plugins' {@link module:core/plugin~PluginInterface#constructor constructors}.\n * This means the code of that plugin will be executed **before** {@link module:core/plugin~PluginInterface#init `init()`} and\n * {@link module:core/plugin~PluginInterface#afterInit `afterInit()`} methods of other plugins and, for instance,\n * you cannot use it to extend other plugins' {@glink framework/guides/architecture/editing-engine#schema schema}\n * rules as they are defined later on during the `init()` stage.\n *\n * @interface PluginInterface\n */\n\n/**\n * Creates a new plugin instance. This is the first step of the plugin initialization.\n * See also {@link #init} and {@link #afterInit}.\n *\n * A plugin is always instantiated after its {@link module:core/plugin~PluginInterface.requires dependencies} and the\n * {@link #init} and {@link #afterInit} methods are called in the same order.\n *\n * Usually, you will want to put your plugin's initialization code in the {@link #init} method.\n * The constructor can be understood as \"before init\" and used in special cases, just like\n * {@link #afterInit} serves the special \"after init\" scenarios (e.g.the code which depends on other\n * plugins, but which does not {@link module:core/plugin~PluginInterface.requires explicitly require} them).\n *\n * @method #constructor\n * @param {module:core/editor/editor~Editor} editor\n */\n\n/**\n * An array of plugins required by this plugin.\n *\n * To keep the plugin class definition tight it is recommended to define this property as a static getter:\n *\n *\t\timport Image from './image.js';\n *\n *\t\texport default class ImageCaption {\n *\t\t\tstatic get requires() {\n *\t\t\t\treturn [ Image ];\n *\t\t\t}\n *\t\t}\n *\n * @static\n * @readonly\n * @member {Array.<Function>|undefined} module:core/plugin~PluginInterface.requires\n */\n\n/**\n * An optional name of the plugin. If set, the plugin will be available in\n * {@link module:core/plugincollection~PluginCollection#get} by its\n * name and its constructor. If not, then only by its constructor.\n *\n * The name should reflect the constructor name.\n *\n * To keep the plugin class definition tight, it is recommended to define this property as a static getter:\n *\n *\t\texport default class ImageCaption {\n *\t\t\tstatic get pluginName() {\n *\t\t\t\treturn 'ImageCaption';\n *\t\t\t}\n *\t\t}\n *\n * Note: The native `Function.name` property could not be used to keep the plugin name because\n * it will be mangled during code minification.\n *\n * Naming a plugin is necessary to enable removing it through the\n * {@link module:core/editor/editorconfig~EditorConfig#removePlugins `config.removePlugins`} option.\n *\n * @static\n * @readonly\n * @member {String|undefined} module:core/plugin~PluginInterface.pluginName\n */\n\n/**\n * The second stage (after plugin {@link #constructor}) of the plugin initialization.\n * Unlike the plugin constructor this method can be asynchronous.\n *\n * A plugin's `init()` method is called after its {@link module:core/plugin~PluginInterface.requires dependencies} are initialized,\n * so in the same order as the constructors of these plugins.\n *\n * **Note:** This method is optional. A plugin instance does not need to have it defined.\n *\n * @method #init\n * @returns {null|Promise}\n */\n\n/**\n * The third (and last) stage of the plugin initialization. See also {@link #constructor} and {@link #init}.\n *\n * **Note:** This method is optional. A plugin instance does not need to have it defined.\n *\n * @method #afterInit\n * @returns {null|Promise}\n */\n\n/**\n * Destroys the plugin.\n *\n * **Note:** This method is optional. A plugin instance does not need to have it defined.\n *\n * @method #destroy\n * @returns {null|Promise}\n */\n\n/**\n * A flag which defines if a plugin is allowed or not allowed to be used directly by a {@link module:core/context~Context}.\n *\n * @static\n * @readonly\n * @member {Boolean} module:core/plugin~PluginInterface.isContextPlugin\n */\n\n/**\n * An array of loaded plugins.\n *\n * @typedef {Array.<module:core/plugin~PluginInterface>} module:core/plugin~LoadedPlugins\n */\n\n// Helper function that forces plugin to be disabled.\nfunction forceDisable( evt ) {\n\tevt.return = false;\n\tevt.stop();\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module clipboard/datatransfer\n */\n\n/**\n * Facade over the native [`DataTransfer`](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer) object.\n */\nexport default class DataTransfer {\n\tconstructor( nativeDataTransfer ) {\n\t\t/**\n\t\t * The array of files created from the native `DataTransfer#files` or `DataTransfer#items`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<File>} #files\n\t\t */\n\t\tthis.files = getFiles( nativeDataTransfer );\n\n\t\t/**\n\t\t * The native DataTransfer object.\n\t\t *\n\t\t * @private\n\t\t * @member {DataTransfer} #_native\n\t\t */\n\t\tthis._native = nativeDataTransfer;\n\t}\n\n\t/**\n\t * Returns an array of available native content types.\n\t *\n\t * @returns {Array.<String>}\n\t */\n\tget types() {\n\t\treturn this._native.types;\n\t}\n\n\t/**\n\t * Gets data from the data transfer by its mime type.\n\t *\n\t *\t\tdataTransfer.getData( 'text/plain' );\n\t *\n\t * @param {String} type The mime type. E.g. `text/html` or `text/plain`.\n\t * @returns {String}\n\t */\n\tgetData( type ) {\n\t\treturn this._native.getData( type );\n\t}\n\n\t/**\n\t * Sets data in the data transfer.\n\t *\n\t * @param {String} type The mime type. E.g. `text/html` or `text/plain`.\n\t * @param {String} data\n\t */\n\tsetData( type, data ) {\n\t\tthis._native.setData( type, data );\n\t}\n}\n\nfunction getFiles( nativeDataTransfer ) {\n\t// DataTransfer.files and items are Array-like and might not have an iterable interface.\n\tconst files = nativeDataTransfer.files ? Array.from( nativeDataTransfer.files ) : [];\n\tconst items = nativeDataTransfer.items ? Array.from( nativeDataTransfer.items ) : [];\n\n\tif ( files.length ) {\n\t\treturn files;\n\t}\n\t// Chrome have empty DataTransfer.files, but let get files through the items interface.\n\treturn items\n\t\t.filter( item => item.kind === 'file' )\n\t\t.map( item => item.getAsFile() );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module clipboard/clipboardobserver\n */\n\nimport DomEventObserver from '@ckeditor/ckeditor5-engine/src/view/observer/domeventobserver';\nimport EventInfo from '@ckeditor/ckeditor5-utils/src/eventinfo';\nimport DataTransfer from './datatransfer';\n\n/**\n * Clipboard events observer.\n *\n * Fires the following events:\n *\n * * {@link module:engine/view/document~Document#event:clipboardInput}\n * * {@link module:engine/view/document~Document#event:dragover}\n * * {@link module:engine/view/document~Document#event:drop}\n * * {@link module:engine/view/document~Document#event:paste}\n * * {@link module:engine/view/document~Document#event:copy}\n * * {@link module:engine/view/document~Document#event:cut}\n *\n * Note that this observer is not available by default (it is not added by the engine).\n * To make it available, it needs to be added to {@link module:engine/view/document~Document} by\n * the {@link module:engine/view/view~View#addObserver `View#addObserver()`} method. You can also load the\n * {@link module:clipboard/clipboard~Clipboard} plugin which adds this observer automatically (because it uses it).\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class ClipboardObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tconst viewDocument = this.document;\n\n\t\tthis.domEventType = [ 'paste', 'copy', 'cut', 'drop', 'dragover' ];\n\n\t\tthis.listenTo( viewDocument, 'paste', handleInput, { priority: 'low' } );\n\t\tthis.listenTo( viewDocument, 'drop', handleInput, { priority: 'low' } );\n\n\t\tfunction handleInput( evt, data ) {\n\t\t\tdata.preventDefault();\n\n\t\t\tconst targetRanges = data.dropRange ? [ data.dropRange ] : Array.from( viewDocument.selection.getRanges() );\n\n\t\t\tconst eventInfo = new EventInfo( viewDocument, 'clipboardInput' );\n\n\t\t\tviewDocument.fire( eventInfo, {\n\t\t\t\tdataTransfer: data.dataTransfer,\n\t\t\t\ttargetRanges\n\t\t\t} );\n\n\t\t\t// If CKEditor handled the input, do not bubble the original event any further.\n\t\t\t// This helps external integrations recognize that fact and act accordingly.\n\t\t\t// https://github.com/ckeditor/ckeditor5-upload/issues/92\n\t\t\tif ( eventInfo.stop.called ) {\n\t\t\t\tdata.stopPropagation();\n\t\t\t}\n\t\t}\n\t}\n\n\tonDomEvent( domEvent ) {\n\t\tconst evtData = {\n\t\t\tdataTransfer: new DataTransfer( domEvent.clipboardData ? domEvent.clipboardData : domEvent.dataTransfer )\n\t\t};\n\n\t\tif ( domEvent.type == 'drop' ) {\n\t\t\tevtData.dropRange = getDropViewRange( this.view, domEvent );\n\t\t}\n\n\t\tthis.fire( domEvent.type, domEvent, evtData );\n\t}\n}\n\nfunction getDropViewRange( view, domEvent ) {\n\tconst domDoc = domEvent.target.ownerDocument;\n\tconst x = domEvent.clientX;\n\tconst y = domEvent.clientY;\n\tlet domRange;\n\n\t// Webkit & Blink.\n\tif ( domDoc.caretRangeFromPoint && domDoc.caretRangeFromPoint( x, y ) ) {\n\t\tdomRange = domDoc.caretRangeFromPoint( x, y );\n\t}\n\t// FF.\n\telse if ( domEvent.rangeParent ) {\n\t\tdomRange = domDoc.createRange();\n\t\tdomRange.setStart( domEvent.rangeParent, domEvent.rangeOffset );\n\t\tdomRange.collapse( true );\n\t}\n\n\tif ( domRange ) {\n\t\treturn view.domConverter.domRangeToView( domRange );\n\t} else {\n\t\treturn view.document.selection.getFirstRange();\n\t}\n}\n\n/**\n * Fired as a continuation of the {@link #event:paste} and {@link #event:drop} events.\n *\n * It is a part of the {@glink framework/guides/deep-dive/clipboard#input-pipeline \"clipboard input pipeline\"}.\n *\n * Fired with a `dataTransfer` which comes from the clipboard and whose content should be processed\n * and inserted into the editor.\n *\n * Note that this event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to the {@link module:engine/view/document~Document} by the {@link module:engine/view/view~View#addObserver} method.\n * This is done by the {@link module:clipboard/clipboard~Clipboard} feature. If it is not loaded, it must be done manually.\n *\n * @see module:clipboard/clipboardobserver~ClipboardObserver\n * @see module:clipboard/clipboard~Clipboard\n * @event module:engine/view/document~Document#event:clipboardInput\n * @param {Object} data Event data.\n * @param {module:clipboard/datatransfer~DataTransfer} data.dataTransfer The data transfer instance.\n * @param {Array.<module:engine/view/range~Range>} data.targetRanges Ranges which are the target of the operation\n * (usually – into which the content should be inserted).\n * If clipboard input was triggered by a paste operation, then these are the selection ranges. If by a drop operation,\n * then it is the drop position (which can be different than the selection at the moment of drop).\n */\n\n/**\n * Fired when the user drags the content over one of the editables.\n *\n * Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}.\n *\n * Note that this event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to the {@link module:engine/view/document~Document} by the {@link module:engine/view/view~View#addObserver} method.\n * This is done by the {@link module:clipboard/clipboard~Clipboard} feature. If it is not loaded, it must be done manually.\n *\n * @see module:engine/view/document~Document#event:clipboardInput\n * @event module:engine/view/document~Document#event:dragover\n * @param {module:clipboard/clipboardobserver~ClipboardEventData} data The event data.\n */\n\n/**\n * Fired when the user dropped the content into one of the editables.\n *\n * Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}.\n *\n * Note that this event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to the {@link module:engine/view/document~Document} by the {@link module:engine/view/view~View#addObserver} method.\n * This is done by the {@link module:clipboard/clipboard~Clipboard} feature. If it is not loaded, it must be done manually.\n *\n * @see module:engine/view/document~Document#event:clipboardInput\n * @event module:engine/view/document~Document#event:drop\n * @param {module:clipboard/clipboardobserver~ClipboardEventData} data The event data.\n * @param {module:engine/view/range~Range} dropRange The position into which the content is dropped.\n */\n\n/**\n * Fired when the user pasted the content into one of the editables.\n *\n * Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}.\n *\n * Note that this event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to the {@link module:engine/view/document~Document} by the {@link module:engine/view/view~View#addObserver} method.\n * This is done by the {@link module:clipboard/clipboard~Clipboard} feature. If it is not loaded, it must be done manually.\n *\n * @see module:engine/view/document~Document#event:clipboardInput\n * @event module:engine/view/document~Document#event:paste\n * @param {module:clipboard/clipboardobserver~ClipboardEventData} data The event data.\n */\n\n/**\n * Fired when the user copied the content from one of the editables.\n *\n * Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}.\n *\n * Note that this event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to the {@link module:engine/view/document~Document} by the {@link module:engine/view/view~View#addObserver} method.\n * This is done by the {@link module:clipboard/clipboard~Clipboard} feature. If it is not loaded, it must be done manually.\n *\n * @see module:clipboard/clipboardobserver~ClipboardObserver\n * @event module:engine/view/document~Document#event:copy\n * @param {module:clipboard/clipboardobserver~ClipboardEventData} data The event data.\n */\n\n/**\n * Fired when the user cut the content from one of the editables.\n *\n * Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}.\n *\n * Note that this event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to the {@link module:engine/view/document~Document} by the {@link module:engine/view/view~View#addObserver} method.\n * This is done by the {@link module:clipboard/clipboard~Clipboard} feature. If it is not loaded, it must be done manually.\n *\n * @see module:clipboard/clipboardobserver~ClipboardObserver\n * @event module:engine/view/document~Document#event:cut\n * @param {module:clipboard/clipboardobserver~ClipboardEventData} data The event data.\n */\n\n/**\n * The value of the {@link module:engine/view/document~Document#event:paste},\n * {@link module:engine/view/document~Document#event:copy} and {@link module:engine/view/document~Document#event:cut} events.\n *\n * In order to access the clipboard data, use the `dataTransfer` property.\n *\n * @class module:clipboard/clipboardobserver~ClipboardEventData\n * @extends module:engine/view/observer/domeventdata~DomEventData\n */\n\n/**\n * The data transfer instance.\n *\n * @readonly\n * @member {module:clipboard/datatransfer~DataTransfer} module:clipboard/clipboardobserver~ClipboardEventData#dataTransfer\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module clipboard/clipboard\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport ClipboardObserver from './clipboardobserver';\n\n/**\n * The plugin detects user intentions for pasting plain text.\n *\n * For example, it detects <kbd>Ctrl/Cmd</kbd> + <kbd>Shift</kbd> + <kbd>V</kbd> keystroke.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class PastePlainText extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'PastePlainText';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst view = this.editor.editing.view;\n\t\tconst viewDocument = view.document;\n\t\tlet shiftPressed = false;\n\n\t\tview.addObserver( ClipboardObserver );\n\n\t\tthis.listenTo( viewDocument, 'keydown', ( evt, data ) => {\n\t\t\tshiftPressed = data.shiftKey;\n\t\t} );\n\n\t\tthis.listenTo( viewDocument, 'clipboardInput', ( evt, data ) => {\n\t\t\tif ( shiftPressed ) {\n\t\t\t\tdata.asPlainText = true;\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module clipboard/utils/viewtoplaintext\n */\n\n// Elements which should not have empty-line padding.\n// Most `view.ContainerElement` want to be separate by new-line, but some are creating one structure\n// together (like `<li>`) so it is better to separate them by only one \"\\n\".\nconst smallPaddingElements = [ 'figcaption', 'li' ];\n\n/**\n * Converts {@link module:engine/view/item~Item view item} and all of its children to plain text.\n *\n * @param {module:engine/view/item~Item} viewItem View item to convert.\n * @returns {String} Plain text representation of `viewItem`.\n */\nexport default function viewToPlainText( viewItem ) {\n\tlet text = '';\n\n\tif ( viewItem.is( '$text' ) || viewItem.is( '$textProxy' ) ) {\n\t\t// If item is `Text` or `TextProxy` simple take its text data.\n\t\ttext = viewItem.data;\n\t} else if ( viewItem.is( 'element', 'img' ) && viewItem.hasAttribute( 'alt' ) ) {\n\t\t// Special case for images - use alt attribute if it is provided.\n\t\ttext = viewItem.getAttribute( 'alt' );\n\t} else if ( viewItem.is( 'element', 'br' ) ) {\n\t\t// A soft break should be converted into a single line break (#8045).\n\t\ttext = '\\n';\n\t} else {\n\t\t// Other elements are document fragments, attribute elements or container elements.\n\t\t// They don't have their own text value, so convert their children.\n\t\tlet prev = null;\n\n\t\tfor ( const child of viewItem.getChildren() ) {\n\t\t\tconst childText = viewToPlainText( child );\n\n\t\t\t// Separate container element children with one or more new-line characters.\n\t\t\tif ( prev && ( prev.is( 'containerElement' ) || child.is( 'containerElement' ) ) ) {\n\t\t\t\tif ( smallPaddingElements.includes( prev.name ) || smallPaddingElements.includes( child.name ) ) {\n\t\t\t\t\ttext += '\\n';\n\t\t\t\t} else {\n\t\t\t\t\ttext += '\\n\\n';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttext += childText;\n\t\t\tprev = child;\n\t\t}\n\t}\n\n\treturn text;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module clipboard/clipboard\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport PastePlainText from './pasteplaintext';\n\nimport ClipboardObserver from './clipboardobserver';\n\nimport plainTextToHtml from './utils/plaintexttohtml';\nimport normalizeClipboardHtml from './utils/normalizeclipboarddata';\nimport viewToPlainText from './utils/viewtoplaintext.js';\n\nimport HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';\nimport EventInfo from '@ckeditor/ckeditor5-utils/src/eventinfo';\n\n/**\n * The clipboard feature. It is responsible for intercepting the `paste` and `drop` events and\n * passing the pasted content through the clipboard pipeline in order to insert it into the editor's content.\n * It also handles the `cut` and `copy` events to fill the native clipboard with serialized editor's data.\n *\n * Read more about the clipboard integration in {@glink framework/guides/deep-dive/clipboard \"Clipboard\" deep dive} guide.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Clipboard extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Clipboard';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ PastePlainText ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst modelDocument = editor.model.document;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\t/**\n\t\t * Data processor used to convert pasted HTML to a view structure.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/dataprocessor/htmldataprocessor~HtmlDataProcessor} #_htmlDataProcessor\n\t\t */\n\t\tthis._htmlDataProcessor = new HtmlDataProcessor( viewDocument );\n\n\t\tview.addObserver( ClipboardObserver );\n\n\t\t// The clipboard paste pipeline.\n\n\t\t// Pasting and dropping is disabled when editor is read-only.\n\t\t// See: https://github.com/ckeditor/ckeditor5-clipboard/issues/26.\n\t\tthis.listenTo( viewDocument, 'clipboardInput', evt => {\n\t\t\tif ( editor.isReadOnly ) {\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: 'highest' } );\n\n\t\tthis.listenTo( viewDocument, 'clipboardInput', ( evt, data ) => {\n\t\t\tconst dataTransfer = data.dataTransfer;\n\t\t\tlet content = '';\n\n\t\t\tif ( dataTransfer.getData( 'text/html' ) ) {\n\t\t\t\tcontent = normalizeClipboardHtml( dataTransfer.getData( 'text/html' ) );\n\t\t\t} else if ( dataTransfer.getData( 'text/plain' ) ) {\n\t\t\t\tcontent = plainTextToHtml( dataTransfer.getData( 'text/plain' ) );\n\t\t\t}\n\n\t\t\tcontent = this._htmlDataProcessor.toView( content );\n\n\t\t\tconst eventInfo = new EventInfo( this, 'inputTransformation' );\n\t\t\tthis.fire( eventInfo, {\n\t\t\t\tcontent,\n\t\t\t\tdataTransfer,\n\t\t\t\tasPlainText: data.asPlainText\n\t\t\t} );\n\n\t\t\t// If CKEditor handled the input, do not bubble the original event any further.\n\t\t\t// This helps external integrations recognize that fact and act accordingly.\n\t\t\t// https://github.com/ckeditor/ckeditor5-upload/issues/92\n\t\t\tif ( eventInfo.stop.called ) {\n\t\t\t\tevt.stop();\n\t\t\t}\n\n\t\t\tview.scrollToTheSelection();\n\t\t}, { priority: 'low' } );\n\n\t\tthis.listenTo( this, 'inputTransformation', ( evt, data ) => {\n\t\t\tif ( !data.content.isEmpty ) {\n\t\t\t\tconst dataController = this.editor.data;\n\t\t\t\tconst model = this.editor.model;\n\n\t\t\t\t// Convert the pasted content to a model document fragment.\n\t\t\t\t// Conversion is contextual, but in this case we need an \"all allowed\" context and for that\n\t\t\t\t// we use the $clipboardHolder item.\n\t\t\t\tconst modelFragment = dataController.toModel( data.content, '$clipboardHolder' );\n\n\t\t\t\tif ( modelFragment.childCount == 0 ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tmodel.change( writer => {\n\t\t\t\t\tconst selection = model.document.selection;\n\n\t\t\t\t\t// Plain text can be determined based on event flag (#7799) or auto detection (#1006). If detected\n\t\t\t\t\t// preserve selection attributes on pasted items.\n\t\t\t\t\tif ( data.asPlainText || isPlainTextFragment( modelFragment, model.schema ) ) {\n\t\t\t\t\t\t// Formatting attributes should be preserved.\n\t\t\t\t\t\tconst textAttributes = Array.from( selection.getAttributes() )\n\t\t\t\t\t\t\t.filter( ( [ key ] ) => model.schema.getAttributeProperties( key ).isFormatting );\n\n\t\t\t\t\t\tif ( !selection.isCollapsed ) {\n\t\t\t\t\t\t\tmodel.deleteContent( selection, { doNotAutoparagraph: true } );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// But also preserve other attributes if they survived the content deletion (because they were not fully selected).\n\t\t\t\t\t\t// For example linkHref is not a formatting attribute but it should be preserved if pasted text was in the middle\n\t\t\t\t\t\t// of a link.\n\t\t\t\t\t\ttextAttributes.push( ...selection.getAttributes() );\n\n\t\t\t\t\t\tconst range = writer.createRangeIn( modelFragment );\n\n\t\t\t\t\t\tfor ( const item of range.getItems() ) {\n\t\t\t\t\t\t\tif ( item.is( '$text' ) || item.is( '$textProxy' ) ) {\n\t\t\t\t\t\t\t\twriter.setAttributes( textAttributes, item );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tmodel.insertContent( modelFragment );\n\t\t\t\t} );\n\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\n\t\t// The clipboard copy/cut pipeline.\n\n\t\tfunction onCopyCut( evt, data ) {\n\t\t\tconst dataTransfer = data.dataTransfer;\n\n\t\t\tdata.preventDefault();\n\n\t\t\tconst content = editor.data.toView( editor.model.getSelectedContent( modelDocument.selection ) );\n\n\t\t\tviewDocument.fire( 'clipboardOutput', { dataTransfer, content, method: evt.name } );\n\t\t}\n\n\t\tthis.listenTo( viewDocument, 'copy', onCopyCut, { priority: 'low' } );\n\t\tthis.listenTo( viewDocument, 'cut', ( evt, data ) => {\n\t\t\t// Cutting is disabled when editor is read-only.\n\t\t\t// See: https://github.com/ckeditor/ckeditor5-clipboard/issues/26.\n\t\t\tif ( editor.isReadOnly ) {\n\t\t\t\tdata.preventDefault();\n\t\t\t} else {\n\t\t\t\tonCopyCut( evt, data );\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\n\t\tthis.listenTo( viewDocument, 'clipboardOutput', ( evt, data ) => {\n\t\t\tif ( !data.content.isEmpty ) {\n\t\t\t\tdata.dataTransfer.setData( 'text/html', this._htmlDataProcessor.toData( data.content ) );\n\t\t\t\tdata.dataTransfer.setData( 'text/plain', viewToPlainText( data.content ) );\n\t\t\t}\n\n\t\t\tif ( data.method == 'cut' ) {\n\t\t\t\teditor.model.deleteContent( modelDocument.selection );\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\t}\n}\n\n/**\n * Fired with a `content` and `dataTransfer` objects. The `content` which comes from the clipboard (was pasted or dropped)\n * should be processed in order to be inserted into the editor. The `dataTransfer` object is available\n * in case the transformation functions needs access to a raw clipboard data.\n *\n * It is a part of the {@glink framework/guides/deep-dive/clipboard#input-pipeline \"clipboard input pipeline\"}.\n *\n * @see module:clipboard/clipboardobserver~ClipboardObserver\n * @see module:clipboard/clipboard~Clipboard\n * @event module:clipboard/clipboard~Clipboard#event:inputTransformation\n * @param {Object} data Event data.\n * @param {module:engine/view/documentfragment~DocumentFragment} data.content Event data. Content to be inserted into the editor.\n * It can be modified by the event listeners. Read more about the clipboard pipelines in\n * {@glink framework/guides/deep-dive/clipboard \"Clipboard\" deep dive}.\n * @param {module:clipboard/datatransfer~DataTransfer} data.dataTransfer Data transfer instance.\n * @param {Boolean} data.asPlainText If set to `true` content is pasted as plain text.\n */\n\n/**\n * Fired on {@link module:engine/view/document~Document#event:copy} and {@link module:engine/view/document~Document#event:cut}\n * with a copy of selected content. The content can be processed before it ends up in the clipboard.\n *\n * It is a part of the {@glink framework/guides/deep-dive/clipboard#output-pipeline \"clipboard output pipeline\"}.\n *\n * @see module:clipboard/clipboardobserver~ClipboardObserver\n * @see module:clipboard/clipboard~Clipboard\n * @event module:engine/view/document~Document#event:clipboardOutput\n * @param {module:clipboard/clipboard~ClipboardOutputEventData} data Event data.\n */\n\n/**\n * The value of the {@link module:engine/view/document~Document#event:clipboardOutput} event.\n *\n * @class module:clipboard/clipboard~ClipboardOutputEventData\n */\n\n/**\n * Data transfer instance.\n *\n * @readonly\n * @member {module:clipboard/datatransfer~DataTransfer} module:clipboard/clipboard~ClipboardOutputEventData#dataTransfer\n */\n\n/**\n * Content to be put into the clipboard. It can be modified by the event listeners.\n * Read more about the clipboard pipelines in {@glink framework/guides/deep-dive/clipboard \"Clipboard\" deep dive}.\n *\n * @member {module:engine/view/documentfragment~DocumentFragment} module:clipboard/clipboard~ClipboardOutputEventData#content\n */\n\n/**\n * Whether the event was triggered by copy or cut operation.\n *\n * @member {'copy'|'cut'} module:clipboard/clipboard~ClipboardOutputEventData#method\n */\n\n// Returns true if specified `documentFragment` represents a plain text.\n//\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment\n// @param {module:engine/model/schema~Schema} schema\n// @returns {Boolean}\nfunction isPlainTextFragment( documentFragment, schema ) {\n\tif ( documentFragment.childCount > 1 ) {\n\t\treturn false;\n\t}\n\n\tconst child = documentFragment.getChild( 0 );\n\n\tif ( schema.isObject( child ) ) {\n\t\treturn false;\n\t}\n\n\treturn [ ...child.getAttributeKeys() ].length == 0;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module clipboard/utils/plaintexttohtml\n */\n\n/**\n * Converts plain text to its HTML-ized version.\n *\n * @param {String} text The plain text to convert.\n * @returns {String} HTML generated from the plain text.\n */\nexport default function plainTextToHtml( text ) {\n\ttext = text\n\t\t// Encode <>.\n\t\t.replace( /</g, '&lt;' )\n\t\t.replace( />/g, '&gt;' )\n\t\t// Creates a paragraph for each double line break.\n\t\t.replace( /\\r?\\n\\r?\\n/g, '</p><p>' )\n\t\t// Creates a line break for each single line break.\n\t\t.replace( /\\r?\\n/g, '<br>' )\n\t\t// Preserve trailing spaces (only the first and last one – the rest is handled below).\n\t\t.replace( /^\\s/, '&nbsp;' )\n\t\t.replace( /\\s$/, '&nbsp;' )\n\t\t// Preserve other subsequent spaces now.\n\t\t.replace( /\\s\\s/g, ' &nbsp;' );\n\n\tif ( text.includes( '</p><p>' ) || text.includes( '<br>' ) ) {\n\t\t// If we created paragraphs above, add the trailing ones.\n\t\ttext = `<p>${ text }</p>`;\n\t}\n\n\t// TODO:\n\t// * What about '\\nfoo' vs ' foo'?\n\n\treturn text;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module clipboard/utils/normalizeclipboarddata\n */\n\n/**\n * Removes some popular browser quirks out of the clipboard data (HTML).\n *\n * @param {String} data The HTML data to normalize.\n * @returns {String} Normalized HTML.\n */\nexport default function normalizeClipboardData( data ) {\n\treturn data\n\t\t.replace( /<span(?: class=\"Apple-converted-space\"|)>(\\s+)<\\/span>/g, ( fullMatch, spaces ) => {\n\t\t\t// Handle the most popular and problematic case when even a single space becomes an nbsp;.\n\t\t\t// Decode those to normal spaces. Read more in https://github.com/ckeditor/ckeditor5-clipboard/issues/2.\n\t\t\tif ( spaces.length == 1 ) {\n\t\t\t\treturn ' ';\n\t\t\t}\n\n\t\t\treturn spaces;\n\t\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module core/command\n */\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * The base class for CKEditor commands.\n *\n * Commands are the main way to manipulate editor contents and state. They are mostly used by UI elements (or by other\n * commands) to make changes in the model. Commands are available in every part of code that has access to\n * the {@link module:core/editor/editor~Editor editor} instance.\n *\n * Instances of registered commands can be retrieved from {@link module:core/editor/editor~Editor#commands `editor.commands`}.\n * The easiest way to execute a command is through {@link module:core/editor/editor~Editor#execute `editor.execute()`}.\n *\n * By default commands are disabled when the editor is in {@link module:core/editor/editor~Editor#isReadOnly read-only} mode.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Command {\n\t/**\n\t * Creates a new `Command` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor Editor on which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\t/**\n\t\t * The editor on which this command will be used.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editor/editor~Editor}\n\t\t */\n\t\tthis.editor = editor;\n\n\t\t/**\n\t\t * The value of the command. A concrete command class should define what it represents for it.\n\t\t *\n\t\t * For example, the `'bold'` command's value indicates whether the selection starts in a bolded text.\n\t\t * And the value of the `'link'` command may be an object with links details.\n\t\t *\n\t\t * It is possible for a command to have no value (e.g. for stateless actions such as `'imageUpload'`).\n\t\t *\n\t\t * A concrete command class should control this value by overriding the {@link #refresh `refresh()`} method.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member #value\n\t\t */\n\t\tthis.set( 'value', undefined );\n\n\t\t/**\n\t\t * Flag indicating whether a command is enabled or disabled.\n\t\t * A disabled command will do nothing when executed.\n\t\t *\n\t\t * A concrete command class should control this value by overriding the {@link #refresh `refresh()`} method.\n\t\t *\n\t\t * It is possible to disable a command from \"outside\". For instance, in your integration you may want to disable\n\t\t * a certain set of commands for the time being. To do that, you can use the fact that `isEnabled` is observable\n\t\t * and it fires the `set:isEnabled` event every time anyone tries to modify its value:\n\t\t *\n\t\t *\t\tfunction disableCommand( cmd ) {\n\t\t *\t\t\tcmd.on( 'set:isEnabled', forceDisable, { priority: 'highest' } );\n\t\t *\n\t\t *\t\t\tcmd.isEnabled = false;\n\t\t *\n\t\t *\t\t\t// Make it possible to enable the command again.\n\t\t *\t\t\treturn () => {\n\t\t *\t\t\t\tcmd.off( 'set:isEnabled', forceDisable );\n\t\t *\t\t\t\tcmd.refresh();\n\t\t *\t\t\t};\n\t\t *\n\t\t *\t\t\tfunction forceDisable( evt ) {\n\t\t *\t\t\t\tevt.return = false;\n\t\t *\t\t\t\tevt.stop();\n\t\t *\t\t\t}\n\t\t *\t\t}\n\t\t *\n\t\t *\t\t// Usage:\n\t\t *\n\t\t *\t\t// Disabling the command.\n\t\t *\t\tconst enableBold = disableCommand( editor.commands.get( 'bold' ) );\n\t\t *\n\t\t *\t\t// Enabling the command again.\n\t\t *\t\tenableBold();\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #isEnabled\n\t\t */\n\t\tthis.set( 'isEnabled', false );\n\n\t\t/**\n\t\t * Holds identifiers for {@link #forceDisabled} mechanism.\n\t\t *\n\t\t * @type {Set.<String>}\n\t\t * @private\n\t\t */\n\t\tthis._disableStack = new Set();\n\n\t\tthis.decorate( 'execute' );\n\n\t\t// By default every command is refreshed when changes are applied to the model.\n\t\tthis.listenTo( this.editor.model.document, 'change', () => {\n\t\t\tthis.refresh();\n\t\t} );\n\n\t\tthis.on( 'execute', evt => {\n\t\t\tif ( !this.isEnabled ) {\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\n\t\t// By default commands are disabled when the editor is in read-only mode.\n\t\tthis.listenTo( editor, 'change:isReadOnly', ( evt, name, value ) => {\n\t\t\tif ( value ) {\n\t\t\t\tthis.forceDisabled( 'readOnlyMode' );\n\t\t\t} else {\n\t\t\t\tthis.clearForceDisabled( 'readOnlyMode' );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Refreshes the command. The command should update its {@link #isEnabled} and {@link #value} properties\n\t * in this method.\n\t *\n\t * This method is automatically called when\n\t * {@link module:engine/model/document~Document#event:change any changes are applied to the document}.\n\t */\n\trefresh() {\n\t\tthis.isEnabled = true;\n\t}\n\n\t/**\n\t * Disables the command.\n\t *\n\t * Command may be disabled by multiple features or algorithms (at once). When disabling a command, unique id should be passed\n\t * (e.g. feature name). The same identifier should be used when {@link #clearForceDisabled enabling back} the command.\n\t * The command becomes enabled only after all features {@link #clearForceDisabled enabled it back}.\n\t *\n\t * Disabling and enabling a command:\n\t *\n\t *\t\tcommand.isEnabled; // -> true\n\t *\t\tcommand.forceDisabled( 'MyFeature' );\n\t *\t\tcommand.isEnabled; // -> false\n\t *\t\tcommand.clearForceDisabled( 'MyFeature' );\n\t *\t\tcommand.isEnabled; // -> true\n\t *\n\t * Command disabled by multiple features:\n\t *\n\t *\t\tcommand.forceDisabled( 'MyFeature' );\n\t *\t\tcommand.forceDisabled( 'OtherFeature' );\n\t *\t\tcommand.clearForceDisabled( 'MyFeature' );\n\t *\t\tcommand.isEnabled; // -> false\n\t *\t\tcommand.clearForceDisabled( 'OtherFeature' );\n\t *\t\tcommand.isEnabled; // -> true\n\t *\n\t * Multiple disabling with the same identifier is redundant:\n\t *\n\t *\t\tcommand.forceDisabled( 'MyFeature' );\n\t *\t\tcommand.forceDisabled( 'MyFeature' );\n\t *\t\tcommand.clearForceDisabled( 'MyFeature' );\n\t *\t\tcommand.isEnabled; // -> true\n\t *\n\t * **Note:** some commands or algorithms may have more complex logic when it comes to enabling or disabling certain commands,\n\t * so the command might be still disabled after {@link #clearForceDisabled} was used.\n\t *\n\t * @param {String} id Unique identifier for disabling. Use the same id when {@link #clearForceDisabled enabling back} the command.\n\t */\n\tforceDisabled( id ) {\n\t\tthis._disableStack.add( id );\n\n\t\tif ( this._disableStack.size == 1 ) {\n\t\t\tthis.on( 'set:isEnabled', forceDisable, { priority: 'highest' } );\n\t\t\tthis.isEnabled = false;\n\t\t}\n\t}\n\n\t/**\n\t * Clears forced disable previously set through {@link #forceDisabled}. See {@link #forceDisabled}.\n\t *\n\t * @param {String} id Unique identifier, equal to the one passed in {@link #forceDisabled} call.\n\t */\n\tclearForceDisabled( id ) {\n\t\tthis._disableStack.delete( id );\n\n\t\tif ( this._disableStack.size == 0 ) {\n\t\t\tthis.off( 'set:isEnabled', forceDisable );\n\t\t\tthis.refresh();\n\t\t}\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * A command may accept parameters. They will be passed from {@link module:core/editor/editor~Editor#execute `editor.execute()`}\n\t * to the command.\n\t *\n\t * The `execute()` method will automatically abort when the command is disabled ({@link #isEnabled} is `false`).\n\t * This behavior is implemented by a high priority listener to the {@link #event:execute} event.\n\t *\n\t * In order to see how to disable a command from \"outside\" see the {@link #isEnabled} documentation.\n\t *\n\t * This method may return a value, which would be forwarded all the way down to the\n\t * {@link module:core/editor/editor~Editor#execute `editor.execute()`}.\n\t *\n\t * @fires execute\n\t */\n\texecute() {}\n\n\t/**\n\t * Destroys the command.\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Event fired by the {@link #execute} method. The command action is a listener to this event so it's\n\t * possible to change/cancel the behavior of the command by listening to this event.\n\t *\n\t * See {@link module:utils/observablemixin~ObservableMixin#decorate} for more information and samples.\n\t *\n\t * **Note:** This event is fired even if command is disabled. However, it is automatically blocked\n\t * by a high priority listener in order to prevent command execution.\n\t *\n\t * @event execute\n\t */\n}\n\nmix( Command, ObservableMixin );\n\n// Helper function that forces command to be disabled.\nfunction forceDisable( evt ) {\n\tevt.return = false;\n\tevt.stop();\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module enter/utils\n */\n\n/**\n * Returns attributes that should be preserved on the enter key.\n *\n * Filtering is realized based on `copyOnEnter` attribute property. Read more about attribute properties\n * {@link module:engine/model/schema~Schema#setAttributeProperties here}.\n *\n * @param {module:engine/model/schema~Schema} schema\n * @param {Iterable.<*>} allAttributes attributes to filter.\n * @returns {Iterable.<*>}\n */\nexport function* getCopyOnEnterAttributes( schema, allAttributes ) {\n\tfor ( const attribute of allAttributes ) {\n\t\tif ( attribute && schema.getAttributeProperties( attribute[ 0 ] ).copyOnEnter ) {\n\t\t\tyield attribute;\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module enter/entercommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { getCopyOnEnterAttributes } from './utils';\n\n/**\n * Enter command. It is used by the {@link module:enter/enter~Enter Enter feature} to handle the <kbd>Enter</kbd> key.\n *\n * @extends module:core/command~Command\n */\nexport default class EnterCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tmodel.change( writer => {\n\t\t\tenterBlock( this.editor.model, writer, doc.selection, model.schema );\n\t\t\tthis.fire( 'afterExecute', { writer } );\n\t\t} );\n\t}\n}\n\n// Creates a new block in the way that the <kbd>Enter</kbd> key is expected to work.\n//\n// @param {module:engine/model~Model} model\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n// Selection on which the action should be performed.\n// @param {module:engine/model/schema~Schema} schema\nfunction enterBlock( model, writer, selection, schema ) {\n\tconst isSelectionEmpty = selection.isCollapsed;\n\tconst range = selection.getFirstRange();\n\tconst startElement = range.start.parent;\n\tconst endElement = range.end.parent;\n\n\t// Don't touch the roots and other limit elements.\n\tif ( schema.isLimit( startElement ) || schema.isLimit( endElement ) ) {\n\t\t// Delete the selected content but only if inside a single limit element.\n\t\t// Abort, when crossing limit elements boundary (e.g. <limit1>x[x</limit1>donttouchme<limit2>y]y</limit2>).\n\t\t// This is an edge case and it's hard to tell what should actually happen because such a selection\n\t\t// is not entirely valid.\n\t\tif ( !isSelectionEmpty && startElement == endElement ) {\n\t\t\tmodel.deleteContent( selection );\n\t\t}\n\n\t\treturn;\n\t}\n\n\tif ( isSelectionEmpty ) {\n\t\tconst attributesToCopy = getCopyOnEnterAttributes( writer.model.schema, selection.getAttributes() );\n\t\tsplitBlock( writer, range.start );\n\t\twriter.setSelectionAttribute( attributesToCopy );\n\t} else {\n\t\tconst leaveUnmerged = !( range.start.isAtStart && range.end.isAtEnd );\n\t\tconst isContainedWithinOneElement = ( startElement == endElement );\n\n\t\tmodel.deleteContent( selection, { leaveUnmerged } );\n\n\t\tif ( leaveUnmerged ) {\n\t\t\t// Partially selected elements.\n\t\t\t//\n\t\t\t// <h>x[xx]x</h>\t\t-> <h>x^x</h>\t\t\t-> <h>x</h><h>^x</h>\n\t\t\tif ( isContainedWithinOneElement ) {\n\t\t\t\tsplitBlock( writer, selection.focus );\n\t\t\t}\n\t\t\t// Selection over multiple elements.\n\t\t\t//\n\t\t\t// <h>x[x</h><p>y]y<p>\t-> <h>x^</h><p>y</p>\t-> <h>x</h><p>^y</p>\n\t\t\telse {\n\t\t\t\twriter.setSelection( endElement, 0 );\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction splitBlock( writer, splitPos ) {\n\twriter.split( splitPos );\n\twriter.setSelection( splitPos.parent.nextSibling, 0 );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module enter/enterobserver\n */\n\nimport Observer from '@ckeditor/ckeditor5-engine/src/view/observer/observer';\nimport DomEventData from '@ckeditor/ckeditor5-engine/src/view/observer/domeventdata';\nimport { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';\n\n/**\n * Enter observer introduces the {@link module:engine/view/document~Document#event:enter} event.\n *\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class EnterObserver extends Observer {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tconst doc = this.document;\n\n\t\tdoc.on( 'keydown', ( evt, data ) => {\n\t\t\tif ( this.isEnabled && data.keyCode == keyCodes.enter ) {\n\t\t\t\t// Save the event object to check later if it was stopped or not.\n\t\t\t\tlet event;\n\t\t\t\tdoc.once( 'enter', evt => ( event = evt ), { priority: 'highest' } );\n\n\t\t\t\tdoc.fire( 'enter', new DomEventData( doc, data.domEvent, {\n\t\t\t\t\tisSoft: data.shiftKey\n\t\t\t\t} ) );\n\n\t\t\t\t// Stop `keydown` event if `enter` event was stopped.\n\t\t\t\t// https://github.com/ckeditor/ckeditor5/issues/753\n\t\t\t\tif ( event && event.stop.called ) {\n\t\t\t\t\tevt.stop();\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve() {}\n}\n\n/**\n * Event fired when the user presses the <kbd>Enter</kbd> key.\n *\n * Note: This event is fired by the {@link module:enter/enterobserver~EnterObserver observer}\n * (usually registered by the {@link module:enter/enter~Enter Enter feature} and\n * {@link module:enter/shiftenter~ShiftEnter ShiftEnter feature}).\n *\n * @event module:engine/view/document~Document#event:enter\n * @param {module:engine/view/observer/domeventdata~DomEventData} data\n * @param {Boolean} data.isSoft Whether it's a soft enter (<kbd>Shift</kbd>+<kbd>Enter</kbd>) or hard enter (<kbd>Enter</kbd>).\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module enter/enter\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport EnterCommand from './entercommand';\nimport EnterObserver from './enterobserver';\n\n/**\n * This plugin handles the <kbd>Enter</kbd> key (hard line break) in the editor.\n *\n * See also the {@link module:enter/shiftenter~ShiftEnter} plugin.\n *\n * For more information about this feature see the {@glink api/enter package page}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Enter extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Enter';\n\t}\n\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\tview.addObserver( EnterObserver );\n\n\t\teditor.commands.add( 'enter', new EnterCommand( editor ) );\n\n\t\tthis.listenTo( viewDocument, 'enter', ( evt, data ) => {\n\t\t\tdata.preventDefault();\n\n\t\t\t// The soft enter key is handled by the ShiftEnter plugin.\n\t\t\tif ( data.isSoft ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\teditor.execute( 'enter' );\n\t\t\tview.scrollToTheSelection();\n\t\t}, { priority: 'low' } );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module enter/shiftentercommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { getCopyOnEnterAttributes } from './utils';\n\n/**\n * ShiftEnter command. It is used by the {@link module:enter/shiftenter~ShiftEnter ShiftEnter feature} to handle\n * the <kbd>Shift</kbd>+<kbd>Enter</kbd> keystroke.\n *\n * @extends module:core/command~Command\n */\nexport default class ShiftEnterCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tmodel.change( writer => {\n\t\t\tsoftBreakAction( model, writer, doc.selection );\n\t\t\tthis.fire( 'afterExecute', { writer } );\n\t\t} );\n\t}\n\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tthis.isEnabled = isEnabled( model.schema, doc.selection );\n\t}\n}\n\n// Checks whether the ShiftEnter command should be enabled in the specified selection.\n//\n// @param {module:engine/model/schema~Schema} schema\n// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\nfunction isEnabled( schema, selection ) {\n\t// At this moment it is okay to support single range selections only.\n\t// But in the future we may need to change that.\n\tif ( selection.rangeCount > 1 ) {\n\t\treturn false;\n\t}\n\n\tconst anchorPos = selection.anchor;\n\n\t// Check whether the break element can be inserted in the current selection anchor.\n\tif ( !anchorPos || !schema.checkChild( anchorPos, 'softBreak' ) ) {\n\t\treturn false;\n\t}\n\n\tconst range = selection.getFirstRange();\n\tconst startElement = range.start.parent;\n\tconst endElement = range.end.parent;\n\n\t// Do not modify the content if selection is cross-limit elements.\n\tif ( ( isInsideLimitElement( startElement, schema ) || isInsideLimitElement( endElement, schema ) ) && startElement !== endElement ) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n// Creates a break in the way that the <kbd>Shift</kbd>+<kbd>Enter</kbd> keystroke is expected to work.\n//\n// @param {module:engine/model~Model} model\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n// Selection on which the action should be performed.\nfunction softBreakAction( model, writer, selection ) {\n\tconst isSelectionEmpty = selection.isCollapsed;\n\tconst range = selection.getFirstRange();\n\tconst startElement = range.start.parent;\n\tconst endElement = range.end.parent;\n\tconst isContainedWithinOneElement = ( startElement == endElement );\n\n\tif ( isSelectionEmpty ) {\n\t\tconst attributesToCopy = getCopyOnEnterAttributes( model.schema, selection.getAttributes() );\n\t\tinsertBreak( model, writer, range.end );\n\n\t\twriter.removeSelectionAttribute( selection.getAttributeKeys() );\n\t\twriter.setSelectionAttribute( attributesToCopy );\n\t} else {\n\t\tconst leaveUnmerged = !( range.start.isAtStart && range.end.isAtEnd );\n\t\tmodel.deleteContent( selection, { leaveUnmerged } );\n\n\t\t// Selection within one element:\n\t\t//\n\t\t// <h>x[xx]x</h>\t\t-> <h>x^x</h>\t\t\t-> <h>x<br>^x</h>\n\t\tif ( isContainedWithinOneElement ) {\n\t\t\tinsertBreak( model, writer, selection.focus );\n\t\t}\n\t\t// Selection over multiple elements.\n\t\t//\n\t\t// <h>x[x</h><p>y]y<p>\t-> <h>x^</h><p>y</p>\t-> <h>x</h><p>^y</p>\n\t\t//\n\t\t// We chose not to insert a line break in this case because:\n\t\t//\n\t\t// * it's not a very common scenario,\n\t\t// * it actually surprised me when I saw the \"expected behavior\" in real life.\n\t\t//\n\t\t// It's ok if the user will need to be more specific where they want the <br> to be inserted.\n\t\telse {\n\t\t\t// Move the selection to the 2nd element (last step of the example above).\n\t\t\tif ( leaveUnmerged ) {\n\t\t\t\twriter.setSelection( endElement, 0 );\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction insertBreak( model, writer, position ) {\n\tconst breakLineElement = writer.createElement( 'softBreak' );\n\n\tmodel.insertContent( breakLineElement, position );\n\twriter.setSelection( breakLineElement, 'after' );\n}\n\n// Checks whether the specified `element` is a child of the limit element.\n//\n// Checking whether the `<p>` element is inside a limit element:\n//   - <$root><p>Text.</p></$root> => false\n//   - <$root><limitElement><p>Text</p></limitElement></$root> => true\n//\n// @param {module:engine/model/element~Element} element\n// @param {module:engine/schema~Schema} schema\n// @returns {Boolean}\nfunction isInsideLimitElement( element, schema ) {\n\t// `$root` is a limit element but in this case is an invalid element.\n\tif ( element.is( 'rootElement' ) ) {\n\t\treturn false;\n\t}\n\n\treturn schema.isLimit( element ) || isInsideLimitElement( element.parent, schema );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module enter/shiftenter\n */\n\nimport ShiftEnterCommand from './shiftentercommand';\nimport EnterObserver from './enterobserver';\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\n/**\n * This plugin handles the <kbd>Shift</kbd>+<kbd>Enter</kbd> keystroke (soft line break) in the editor.\n *\n * See also the {@link module:enter/enter~Enter} plugin.\n *\n * For more information about this feature see the {@glink api/enter package page}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ShiftEnter extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ShiftEnter';\n\t}\n\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\t\tconst conversion = editor.conversion;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\t// Configure the schema.\n\t\tschema.register( 'softBreak', {\n\t\t\tallowWhere: '$text',\n\t\t\tisInline: true\n\t\t} );\n\n\t\t// Configure converters.\n\t\tconversion.for( 'upcast' )\n\t\t\t.elementToElement( {\n\t\t\t\tmodel: 'softBreak',\n\t\t\t\tview: 'br'\n\t\t\t} );\n\n\t\tconversion.for( 'downcast' )\n\t\t\t.elementToElement( {\n\t\t\t\tmodel: 'softBreak',\n\t\t\t\tview: ( modelElement, { writer } ) => writer.createEmptyElement( 'br' )\n\t\t\t} );\n\n\t\tview.addObserver( EnterObserver );\n\n\t\teditor.commands.add( 'shiftEnter', new ShiftEnterCommand( editor ) );\n\n\t\tthis.listenTo( viewDocument, 'enter', ( evt, data ) => {\n\t\t\tdata.preventDefault();\n\n\t\t\t// The hard enter key is handled by the Enter plugin.\n\t\t\tif ( !data.isSoft ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\teditor.execute( 'shiftEnter' );\n\t\t\tview.scrollToTheSelection();\n\t\t}, { priority: 'low' } );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module select-all/selectallcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\n/**\n * The select all command.\n *\n * It is used by the {@link module:select-all/selectallediting~SelectAllEditing select all editing feature} to handle\n * the <kbd>Ctrl/⌘</kbd>+<kbd>A</kbd> keystroke.\n *\n * Executing this command changes the {@glink framework/guides/architecture/editing-engine#model model}\n * selection so it contains the entire content of the editable root of the editor the selection is\n * {@link module:engine/model/selection~Selection#anchor anchored} in.\n *\n * If the selection was anchored in a {@glink framework/guides/tutorials/implementing-a-block-widget nested editable}\n * (e.g. a caption of an image), the new selection will contain its entire content. Successive executions of this command\n * will expand the selection to encompass more and more content up to the entire editable root of the editor.\n *\n * @extends module:core/command~Command\n */\nexport default class SelectAllCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tlet scopeElement = model.schema.getLimitElement( selection );\n\n\t\t// If an entire scope is selected, or the selection's ancestor is not a scope yet,\n\t\t// browse through ancestors to find the enclosing parent scope.\n\t\tif ( selection.containsEntireContent( scopeElement ) || !isSelectAllScope( model.schema, scopeElement ) ) {\n\t\t\tdo {\n\t\t\t\tscopeElement = scopeElement.parent;\n\n\t\t\t\t// Do nothing, if the entire `root` is already selected.\n\t\t\t\tif ( !scopeElement ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} while ( !isSelectAllScope( model.schema, scopeElement ) );\n\t\t}\n\n\t\tmodel.change( writer => {\n\t\t\twriter.setSelection( scopeElement, 'in' );\n\t\t} );\n\t}\n}\n\n// Checks whether the element is a valid select-all scope.\n// Returns true, if the element is a {@link module:engine/model/schema~Schema#isLimit limit},\n// and can contain any text or paragraph.\n//\n// @param {module:engine/model/schema~Schema} schema The schema to check against.\n// @param {module:engine/model/element~Element} element\n// @return {Boolean}\nfunction isSelectAllScope( schema, element ) {\n\treturn schema.isLimit( element ) && ( schema.checkChild( element, '$text' ) || schema.checkChild( element, 'paragraph' ) );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module select-all/selectallediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport { getCode, parseKeystroke } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport SelectAllCommand from './selectallcommand';\n\nconst SELECT_ALL_KEYSTROKE = parseKeystroke( 'Ctrl+A' );\n\n/**\n * The select all editing feature.\n *\n * It registers the `'selectAll'` {@link module:select-all/selectallcommand~SelectAllCommand command}\n * and the <kbd>Ctrl/⌘</kbd>+<kbd>A</kbd> keystroke listener which executes it.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class SelectAllEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'SelectAllEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\teditor.commands.add( 'selectAll', new SelectAllCommand( editor ) );\n\n\t\tthis.listenTo( viewDocument, 'keydown', ( eventInfo, domEventData ) => {\n\t\t\tif ( getCode( domEventData ) === SELECT_ALL_KEYSTROKE ) {\n\t\t\t\teditor.execute( 'selectAll' );\n\t\t\t\tdomEventData.preventDefault();\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module select-all/selectallui\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\n\nimport selectAllIcon from '../theme/icons/select-all.svg';\n\n/**\n * The select all UI feature.\n *\n * It registers the `'selectAll'` UI button in the editor's\n * {@link module:ui/componentfactory~ComponentFactory component factory}. When clicked, the button\n * executes the {@link module:select-all/selectallcommand~SelectAllCommand select all command}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class SelectAllUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'SelectAllUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\teditor.ui.componentFactory.add( 'selectAll', locale => {\n\t\t\tconst command = editor.commands.get( 'selectAll' );\n\t\t\tconst view = new ButtonView( locale );\n\t\t\tconst t = locale.t;\n\n\t\t\tview.set( {\n\t\t\t\tlabel: t( 'Select all' ),\n\t\t\t\ticon: selectAllIcon,\n\t\t\t\tkeystroke: 'Ctrl+A',\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );\n\n\t\t\t// Execute the command.\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\teditor.execute( 'selectAll' );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","export default \"<svg width=\\\"20\\\" height=\\\"20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M.75 15.5a.75.75 0 0 1 .75.75V18l.008.09A.5.5 0 0 0 2 18.5h1.75a.75.75 0 1 1 0 1.5H1.5l-.144-.007a1.5 1.5 0 0 1-1.35-1.349L0 18.5v-2.25a.75.75 0 0 1 .75-.75zm18.5 0a.75.75 0 0 1 .75.75v2.25l-.007.144a1.5 1.5 0 0 1-1.349 1.35L18.5 20h-2.25a.75.75 0 1 1 0-1.5H18a.5.5 0 0 0 .492-.41L18.5 18v-1.75a.75.75 0 0 1 .75-.75zm-10.45 3c.11 0 .2.09.2.2v1.1a.2.2 0 0 1-.2.2H7.2a.2.2 0 0 1-.2-.2v-1.1c0-.11.09-.2.2-.2h1.6zm4 0c.11 0 .2.09.2.2v1.1a.2.2 0 0 1-.2.2h-1.6a.2.2 0 0 1-.2-.2v-1.1c0-.11.09-.2.2-.2h1.6zm.45-5.5a.75.75 0 1 1 0 1.5h-8.5a.75.75 0 1 1 0-1.5h8.5zM1.3 11c.11 0 .2.09.2.2v1.6a.2.2 0 0 1-.2.2H.2a.2.2 0 0 1-.2-.2v-1.6c0-.11.09-.2.2-.2h1.1zm18.5 0c.11 0 .2.09.2.2v1.6a.2.2 0 0 1-.2.2h-1.1a.2.2 0 0 1-.2-.2v-1.6c0-.11.09-.2.2-.2h1.1zm-4.55-2a.75.75 0 1 1 0 1.5H4.75a.75.75 0 1 1 0-1.5h10.5zM1.3 7c.11 0 .2.09.2.2v1.6a.2.2 0 0 1-.2.2H.2a.2.2 0 0 1-.2-.2V7.2c0-.11.09-.2.2-.2h1.1zm18.5 0c.11 0 .2.09.2.2v1.6a.2.2 0 0 1-.2.2h-1.1a.2.2 0 0 1-.2-.2V7.2c0-.11.09-.2.2-.2h1.1zm-4.55-2a.75.75 0 1 1 0 1.5h-2.5a.75.75 0 1 1 0-1.5h2.5zm-5 0a.75.75 0 1 1 0 1.5h-5.5a.75.75 0 0 1 0-1.5h5.5zm-6.5-5a.75.75 0 0 1 0 1.5H2a.5.5 0 0 0-.492.41L1.5 2v1.75a.75.75 0 0 1-1.5 0V1.5l.007-.144A1.5 1.5 0 0 1 1.356.006L1.5 0h2.25zM18.5 0l.144.007a1.5 1.5 0 0 1 1.35 1.349L20 1.5v2.25a.75.75 0 1 1-1.5 0V2l-.008-.09A.5.5 0 0 0 18 1.5h-1.75a.75.75 0 1 1 0-1.5h2.25zM8.8 0c.11 0 .2.09.2.2v1.1a.2.2 0 0 1-.2.2H7.2a.2.2 0 0 1-.2-.2V.2c0-.11.09-.2.2-.2h1.6zm4 0c.11 0 .2.09.2.2v1.1a.2.2 0 0 1-.2.2h-1.6a.2.2 0 0 1-.2-.2V.2c0-.11.09-.2.2-.2h1.6z\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module select-all/selectall\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport SelectAllEditing from './selectallediting';\nimport SelectAllUI from './selectallui';\n\n/**\n * The select all feature.\n *\n * This is a \"glue\" plugin which loads the {@link module:select-all/selectallediting~SelectAllEditing select all editing feature}\n * and the {@link module:select-all/selectallui~SelectAllUI select all UI feature}.\n *\n * Please refer to the documentation of individual features to learn more.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class SelectAll extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ SelectAllEditing, SelectAllUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'SelectAll';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/utils/changebuffer\n */\n\n/**\n * Change buffer allows to group atomic changes (like characters that have been typed) into\n * {@link module:engine/model/batch~Batch batches}.\n *\n * Batches represent single undo steps, hence changes added to one single batch are undone together.\n *\n * The buffer has a configurable limit of atomic changes that it can accommodate. After the limit was\n * exceeded (see {@link ~ChangeBuffer#input}), a new batch is created in {@link ~ChangeBuffer#batch}.\n *\n * To use the change buffer you need to let it know about the number of changes that were added to the batch:\n *\n *\t\tconst buffer = new ChangeBuffer( model, LIMIT );\n *\n *\t\t// Later on in your feature:\n *\t\tbuffer.batch.insert( pos, insertedCharacters );\n *\t\tbuffer.input( insertedCharacters.length );\n *\n */\nexport default class ChangeBuffer {\n\t/**\n\t * Creates a new instance of the change buffer.\n\t *\n\t * @param {module:engine/model/model~Model} model\n\t * @param {Number} [limit=20] The maximum number of atomic changes which can be contained in one batch.\n\t */\n\tconstructor( model, limit = 20 ) {\n\t\t/**\n\t\t * The model instance.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/model~Model} #model\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * The number of atomic changes in the buffer. Once it exceeds the {@link #limit},\n\t\t * the {@link #batch batch} is set to a new one.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #size\n\t\t */\n\t\tthis.size = 0;\n\n\t\t/**\n\t\t * The maximum number of atomic changes which can be contained in one batch.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #limit\n\t\t */\n\t\tthis.limit = limit;\n\n\t\t/**\n\t\t * Whether the buffer is locked. A locked buffer cannot be reset unless it gets unlocked.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} #isLocked\n\t\t */\n\t\tthis.isLocked = false;\n\n\t\t// The function to be called in order to notify the buffer about batches which appeared in the document.\n\t\t// The callback will check whether it is a new batch and in that case the buffer will be flushed.\n\t\t//\n\t\t// The reason why the buffer needs to be flushed whenever a new batch appears is that the changes added afterwards\n\t\t// should be added to a new batch. For instance, when the  user types, then inserts an image, and then types again,\n\t\t// the characters typed after inserting the image should be added to a different batch than the characters typed before.\n\t\tthis._changeCallback = ( evt, batch ) => {\n\t\t\tif ( batch.type != 'transparent' && batch !== this._batch ) {\n\t\t\t\tthis._reset( true );\n\t\t\t}\n\t\t};\n\n\t\tthis._selectionChangeCallback = () => {\n\t\t\tthis._reset();\n\t\t};\n\n\t\tthis.model.document.on( 'change', this._changeCallback );\n\n\t\tthis.model.document.selection.on( 'change:range', this._selectionChangeCallback );\n\t\tthis.model.document.selection.on( 'change:attribute', this._selectionChangeCallback );\n\n\t\t/**\n\t\t * The current batch instance.\n\t\t *\n\t\t * @private\n\t\t * @member #_batch\n\t\t */\n\n\t\t/**\n\t\t * The callback to document the change event which later needs to be removed.\n\t\t *\n\t\t * @private\n\t\t * @member #_changeCallback\n\t\t */\n\n\t\t/**\n\t\t * The callback to document selection `change:attribute` and `change:range` events which resets the buffer.\n\t\t *\n\t\t * @private\n\t\t * @member #_selectionChangeCallback\n\t\t */\n\t}\n\n\t/**\n\t * The current batch to which a feature should add its operations. Once the {@link #size}\n\t * is reached or exceeds the {@link #limit}, the batch is set to a new instance and the size is reset.\n\t *\n\t * @type {module:engine/model/batch~Batch}\n\t */\n\tget batch() {\n\t\tif ( !this._batch ) {\n\t\t\tthis._batch = this.model.createBatch();\n\t\t}\n\n\t\treturn this._batch;\n\t}\n\n\t/**\n\t * The input number of changes into the buffer. Once the {@link #size} is\n\t * reached or exceeds the {@link #limit}, the batch is set to a new instance and the size is reset.\n\t *\n\t * @param {Number} changeCount The number of atomic changes to input.\n\t */\n\tinput( changeCount ) {\n\t\tthis.size += changeCount;\n\n\t\tif ( this.size >= this.limit ) {\n\t\t\tthis._reset( true );\n\t\t}\n\t}\n\n\t/**\n\t * Locks the buffer.\n\t */\n\tlock() {\n\t\tthis.isLocked = true;\n\t}\n\n\t/**\n\t * Unlocks the buffer.\n\t */\n\tunlock() {\n\t\tthis.isLocked = false;\n\t}\n\n\t/**\n\t * Destroys the buffer.\n\t */\n\tdestroy() {\n\t\tthis.model.document.off( 'change', this._changeCallback );\n\t\tthis.model.document.selection.off( 'change:range', this._selectionChangeCallback );\n\t\tthis.model.document.selection.off( 'change:attribute', this._selectionChangeCallback );\n\t}\n\n\t/**\n\t * Resets the change buffer.\n\t *\n\t * @private\n\t * @param {Boolean} [ignoreLock] Whether internal lock {@link #isLocked} should be ignored.\n\t */\n\t_reset( ignoreLock ) {\n\t\tif ( !this.isLocked || ignoreLock ) {\n\t\t\tthis._batch = null;\n\t\t\tthis.size = 0;\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/inputcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\nimport ChangeBuffer from './utils/changebuffer';\n\n/**\n * The input command. Used by the {@link module:typing/input~Input input feature} to handle typing.\n *\n * @extends module:core/command~Command\n */\nexport default class InputCommand extends Command {\n\t/**\n\t * Creates an instance of the command.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor\n\t * @param {Number} undoStepSize The maximum number of atomic changes\n\t * which can be contained in one batch in the command buffer.\n\t */\n\tconstructor( editor, undoStepSize ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * Typing's change buffer used to group subsequent changes into batches.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @member {module:typing/utils/changebuffer~ChangeBuffer} #_buffer\n\t\t */\n\t\tthis._buffer = new ChangeBuffer( editor.model, undoStepSize );\n\n\t\t/**\n\t\t * Stores batches created by the input command. The batches are used to differentiate input batches from other batches using\n\t\t * {@link module:typing/input~Input#isInput} method.\n\t\t *\n\t\t * @type {WeakSet<module:engine/model/batch~Batch>}\n\t\t * @protected\n\t\t */\n\t\tthis._batches = new WeakSet();\n\t}\n\n\t/**\n\t * The current change buffer.\n\t *\n\t * @type {module:typing/utils/changebuffer~ChangeBuffer}\n\t */\n\tget buffer() {\n\t\treturn this._buffer;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tthis._buffer.destroy();\n\t}\n\n\t/**\n\t * Executes the input command. It replaces the content within the given range with the given text.\n\t * Replacing is a two step process, first the content within the range is removed and then the new text is inserted\n\t * at the beginning of the range (which after the removal is a collapsed range).\n\t *\n\t * @fires execute\n\t * @param {Object} [options] The command options.\n\t * @param {String} [options.text=''] The text to be inserted.\n\t * @param {module:engine/model/range~Range} [options.range] The range in which the text is inserted. Defaults\n\t * to the first range in the current selection.\n\t * @param {module:engine/model/range~Range} [options.resultRange] The range where the selection\n\t * should be placed after the insertion. If not specified, the selection will be placed right after\n\t * the inserted text.\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst text = options.text || '';\n\t\tconst textInsertions = text.length;\n\t\tconst selection = options.range ? model.createSelection( options.range ) : doc.selection;\n\t\tconst resultRange = options.resultRange;\n\n\t\tmodel.enqueueChange( this._buffer.batch, writer => {\n\t\t\tthis._buffer.lock();\n\n\t\t\t// Store the batch as an 'input' batch for the Input.isInput( batch ) check.\n\t\t\tthis._batches.add( this._buffer.batch );\n\n\t\t\tmodel.deleteContent( selection );\n\n\t\t\tif ( text ) {\n\t\t\t\tmodel.insertContent( writer.createText( text, doc.selection.getAttributes() ), selection );\n\t\t\t}\n\n\t\t\tif ( resultRange ) {\n\t\t\t\twriter.setSelection( resultRange );\n\t\t\t} else if ( !selection.is( 'documentSelection' ) ) {\n\t\t\t\twriter.setSelection( selection );\n\t\t\t}\n\n\t\t\tthis._buffer.unlock();\n\n\t\t\tthis._buffer.input( textInsertions );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/utils/injectunsafekeystrokeshandling\n */\n\nimport { getCode } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\n/**\n * Handles keystrokes which are unsafe for typing. This handler's logic is explained\n * in https://github.com/ckeditor/ckeditor5-typing/issues/83#issuecomment-398690251.\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n */\nexport default function injectUnsafeKeystrokesHandling( editor ) {\n\tlet latestCompositionSelection = null;\n\n\tconst model = editor.model;\n\tconst view = editor.editing.view;\n\tconst inputCommand = editor.commands.get( 'input' );\n\n\t// For Android, we want to handle keystrokes on `beforeinput` to be sure that code in `DeleteObserver` already had a chance to be fired.\n\tif ( env.isAndroid ) {\n\t\tview.document.on( 'beforeinput', ( evt, evtData ) => handleUnsafeKeystroke( evtData ), { priority: 'lowest' } );\n\t} else {\n\t\tview.document.on( 'keydown', ( evt, evtData ) => handleUnsafeKeystroke( evtData ), { priority: 'lowest' } );\n\t}\n\n\tview.document.on( 'compositionstart', handleCompositionStart, { priority: 'lowest' } );\n\n\tview.document.on( 'compositionend', () => {\n\t\tlatestCompositionSelection = model.createSelection( model.document.selection );\n\t}, { priority: 'lowest' } );\n\n\t// Handles the keydown event. We need to guess whether such keystroke is going to result\n\t// in typing. If so, then before character insertion happens, any selected content needs\n\t// to be deleted. Otherwise the default browser deletion mechanism would be\n\t// triggered, resulting in:\n\t//\n\t// * Hundreds of mutations which could not be handled.\n\t// * But most importantly, loss of control over how the content is being deleted.\n\t//\n\t// The method is used in a low-priority listener, hence allowing other listeners (e.g. delete or enter features)\n\t// to handle the event.\n\t//\n\t// @param {module:engine/view/observer/keyobserver~KeyEventData} evtData\n\tfunction handleUnsafeKeystroke( evtData ) {\n\t\tconst doc = model.document;\n\t\tconst isComposing = view.document.isComposing;\n\t\tconst isSelectionUnchanged = latestCompositionSelection && latestCompositionSelection.isEqual( doc.selection );\n\n\t\t// Reset stored composition selection.\n\t\tlatestCompositionSelection = null;\n\n\t\t// By relying on the state of the input command we allow disabling the entire input easily\n\t\t// by just disabling the input command. We could’ve used here the delete command but that\n\t\t// would mean requiring the delete feature which would block loading one without the other.\n\t\t// We could also check the editor.isReadOnly property, but that wouldn't allow to block\n\t\t// the input without blocking other features.\n\t\tif ( !inputCommand.isEnabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( isNonTypingKeystroke( evtData ) || doc.selection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If during composition, deletion should be prevented as it may remove composed sequence (#83).\n\t\tif ( isComposing && evtData.keyCode === 229 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there is a `keydown` event fired with '229' keycode it might be related\n\t\t// to recent composition. Check if selection is the same as upon ending recent composition,\n\t\t// if so do not remove selected content as it will remove composed sequence (#83).\n\t\tif ( !isComposing && evtData.keyCode === 229 && isSelectionUnchanged ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdeleteSelectionContent();\n\t}\n\n\t// Handles the `compositionstart` event. It is used only in special cases to remove the contents\n\t// of a non-collapsed selection so composition itself does not result in complex mutations.\n\t//\n\t// The special case mentioned above is a situation in which the `keydown` event is fired after\n\t// `compositionstart` event. In such cases {@link #handleKeydown} cannot clear current selection\n\t// contents (because it is too late and will break the composition) so the composition handler takes care of it.\n\tfunction handleCompositionStart() {\n\t\tconst doc = model.document;\n\t\tconst isFlatSelection = doc.selection.rangeCount === 1 ? doc.selection.getFirstRange().isFlat : true;\n\n\t\t// If on `compositionstart` there is a non-collapsed selection which start and end have different parents\n\t\t// it means the `handleKeydown()` method did not remove its contents. It happens usually because\n\t\t// of different order of events (`compositionstart` before `keydown` - in Safari). In such cases\n\t\t// we need to remove selection contents on composition start (#83).\n\t\tif ( doc.selection.isCollapsed || isFlatSelection ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdeleteSelectionContent();\n\t}\n\n\tfunction deleteSelectionContent() {\n\t\tconst buffer = inputCommand.buffer;\n\n\t\tbuffer.lock();\n\n\t\tconst batch = buffer.batch;\n\t\tinputCommand._batches.add( batch );\n\n\t\tmodel.enqueueChange( batch, () => {\n\t\t\tmodel.deleteContent( model.document.selection );\n\t\t} );\n\n\t\tbuffer.unlock();\n\t}\n}\n\nconst safeKeycodes = [\n\tgetCode( 'arrowUp' ),\n\tgetCode( 'arrowRight' ),\n\tgetCode( 'arrowDown' ),\n\tgetCode( 'arrowLeft' ),\n\t9, // Tab\n\t16, // Shift\n\t17, // Ctrl\n\t18, // Alt\n\t19, // Pause\n\t20, // CapsLock\n\t27, // Escape\n\t33, // PageUp\n\t34, // PageDown\n\t35, // Home\n\t36, // End,\n\t45, // Insert,\n\t91, // Windows,\n\t93, // Menu key,\n\t144, // NumLock\n\t145, // ScrollLock,\n\t173, // Mute/Unmute\n\t174, // Volume up\n\t175, // Volume down,\n\t176, // Next song,\n\t177, // Previous song,\n\t178, // Stop,\n\t179, // Play/Pause,\n\t255 // Display brightness (increase and decrease)\n];\n\n// Function keys.\nfor ( let code = 112; code <= 135; code++ ) {\n\tsafeKeycodes.push( code );\n}\n\n/**\n * Returns `true` if a keystroke will **not** result in \"typing\".\n *\n * For instance, keystrokes that result in typing are letters \"a-zA-Z\", numbers \"0-9\", delete, backspace, etc.\n *\n * Keystrokes that do not cause typing are, for instance, Fn keys (F5, F8, etc.), arrow keys (←, →, ↑, ↓),\n * Tab (↹), \"Windows logo key\" (⊞ Win), etc.\n *\n * Note: This implementation is very simple and will need to be refined with time.\n *\n * @param {module:engine/view/observer/keyobserver~KeyEventData} keyData\n * @returns {Boolean}\n */\nexport function isNonTypingKeystroke( keyData ) {\n\t// Keystrokes which contain Ctrl don't represent typing.\n\tif ( keyData.ctrlKey ) {\n\t\treturn true;\n\t}\n\n\treturn safeKeycodes.includes( keyData.keyCode );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/utils/utils\n */\n\nimport diff from '@ckeditor/ckeditor5-utils/src/diff';\nimport diffToChanges from '@ckeditor/ckeditor5-utils/src/difftochanges';\n\n/**\n * Returns true if container children have mutated or more than a single text node was changed.\n *\n * @private\n * @param {Array.<module:engine/view/observer/mutationobserver~MutatedText|\n * module:engine/view/observer/mutationobserver~MutatedChildren>} mutations\n * @returns {Boolean}\n */\nexport function containerChildrenMutated( mutations ) {\n\tif ( mutations.length == 0 ) {\n\t\treturn false;\n\t}\n\n\t// Check if there is any mutation of `children` type or any mutation that changes more than one text node.\n\tfor ( const mutation of mutations ) {\n\t\tif ( mutation.type === 'children' && !getSingleTextNodeChange( mutation ) ) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Returns change made to a single text node.\n *\n * @private\n * @param {module:engine/view/observer/mutationobserver~MutatedText|\n * module:engine/view/observer/mutationobserver~MutatedChildren} mutation\n * @returns {Object|undefined} Change object (see {@link module:utils/difftochanges~diffToChanges} output)\n * or undefined if more than a single text node was changed.\n */\nexport function getSingleTextNodeChange( mutation ) {\n\t// One new node.\n\tif ( mutation.newChildren.length - mutation.oldChildren.length != 1 ) {\n\t\treturn;\n\t}\n\n\t// Which is text.\n\tconst diffResult = diff( mutation.oldChildren, mutation.newChildren, compareChildNodes );\n\tconst changes = diffToChanges( diffResult, mutation.newChildren );\n\n\t// In case of [ delete, insert, insert ] the previous check will not exit.\n\tif ( changes.length > 1 ) {\n\t\treturn;\n\t}\n\n\tconst change = changes[ 0 ];\n\n\t// Which is text.\n\tif ( !( !!change.values[ 0 ] && change.values[ 0 ].is( '$text' ) ) ) {\n\t\treturn;\n\t}\n\n\treturn change;\n}\n\n/**\n * Checks whether two view nodes are identical, which means they are the same object\n * or contain exactly same data (in case of text nodes).\n *\n * @private\n * @param {module:engine/view/node~Node} oldChild\n * @param {module:engine/view/node~Node} newChild\n * @returns {Boolean}\n */\nexport function compareChildNodes( oldChild, newChild ) {\n\tif ( !!oldChild && oldChild.is( '$text' ) && !!newChild && newChild.is( '$text' ) ) {\n\t\treturn oldChild.data === newChild.data;\n\t} else {\n\t\treturn oldChild === newChild;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/difftochanges\n */\n\n/**\n * Creates a set of changes which need to be applied to the input in order to transform\n * it into the output. This function can be used with strings or arrays.\n *\n *\t\tconst input = Array.from( 'abc' );\n *\t\tconst output = Array.from( 'xaby' );\n *\t\tconst changes = diffToChanges( diff( input, output ), output );\n *\n *\t\tchanges.forEach( change => {\n *\t\t\tif ( change.type == 'insert' ) {\n *\t\t\t\tinput.splice( change.index, 0, ...change.values );\n *\t\t\t} else if ( change.type == 'delete' ) {\n *\t\t\t\tinput.splice( change.index, change.howMany );\n *\t\t\t}\n *\t\t} );\n *\n *\t\tinput.join( '' ) == output.join( '' ); // -> true\n *\n * @param {Array.<'equal'|'insert'|'delete'>} diff Result of {@link module:utils/diff~diff}.\n * @param {String|Array} output The string or array which was passed as diff's output.\n * @returns {Array.<Object>} Set of changes (insert or delete) which need to be applied to the input\n * in order to transform it into the output.\n */\nexport default function diffToChanges( diff, output ) {\n\tconst changes = [];\n\tlet index = 0;\n\tlet lastOperation;\n\n\tdiff.forEach( change => {\n\t\tif ( change == 'equal' ) {\n\t\t\tpushLast();\n\n\t\t\tindex++;\n\t\t} else if ( change == 'insert' ) {\n\t\t\tif ( isContinuationOf( 'insert' ) ) {\n\t\t\t\tlastOperation.values.push( output[ index ] );\n\t\t\t} else {\n\t\t\t\tpushLast();\n\n\t\t\t\tlastOperation = {\n\t\t\t\t\ttype: 'insert',\n\t\t\t\t\tindex,\n\t\t\t\t\tvalues: [ output[ index ] ]\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tindex++;\n\t\t} else /* if ( change == 'delete' ) */ {\n\t\t\tif ( isContinuationOf( 'delete' ) ) {\n\t\t\t\tlastOperation.howMany++;\n\t\t\t} else {\n\t\t\t\tpushLast();\n\n\t\t\t\tlastOperation = {\n\t\t\t\t\ttype: 'delete',\n\t\t\t\t\tindex,\n\t\t\t\t\thowMany: 1\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t} );\n\n\tpushLast();\n\n\treturn changes;\n\n\tfunction pushLast() {\n\t\tif ( lastOperation ) {\n\t\t\tchanges.push( lastOperation );\n\t\t\tlastOperation = null;\n\t\t}\n\t}\n\n\tfunction isContinuationOf( expected ) {\n\t\treturn lastOperation && lastOperation.type == expected;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/utils/injecttypingmutationshandling\n */\n\nimport diff from '@ckeditor/ckeditor5-utils/src/diff';\nimport DomConverter from '@ckeditor/ckeditor5-engine/src/view/domconverter';\n\nimport { getSingleTextNodeChange, containerChildrenMutated } from './utils';\n\n/**\n * Handles mutations caused by normal typing.\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n */\nexport default function injectTypingMutationsHandling( editor ) {\n\teditor.editing.view.document.on( 'mutations', ( evt, mutations, viewSelection ) => {\n\t\tnew MutationHandler( editor ).handle( mutations, viewSelection );\n\t} );\n}\n\n/**\n * Helper class for translating DOM mutations into model changes.\n *\n * @private\n */\nclass MutationHandler {\n\t/**\n\t * Creates an instance of the mutation handler.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor\n\t */\n\tconstructor( editor ) {\n\t\t/**\n\t\t * Editor instance for which mutations are handled.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editor/editor~Editor} #editor\n\t\t */\n\t\tthis.editor = editor;\n\n\t\t/**\n\t\t * The editing controller.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/controller/editingcontroller~EditingController} #editing\n\t\t */\n\t\tthis.editing = this.editor.editing;\n\t}\n\n\t/**\n\t * Handles given mutations.\n\t *\n\t * @param {Array.<module:engine/view/observer/mutationobserver~MutatedText|\n\t * module:engine/view/observer/mutationobserver~MutatedChildren>} mutations\n\t * @param {module:engine/view/selection~Selection|null} viewSelection\n\t */\n\thandle( mutations, viewSelection ) {\n\t\tif ( containerChildrenMutated( mutations ) ) {\n\t\t\tthis._handleContainerChildrenMutations( mutations, viewSelection );\n\t\t} else {\n\t\t\tfor ( const mutation of mutations ) {\n\t\t\t\t// Fortunately it will never be both.\n\t\t\t\tthis._handleTextMutation( mutation, viewSelection );\n\t\t\t\tthis._handleTextNodeInsertion( mutation );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Handles situations when container's children mutated during input. This can happen when\n\t * the browser is trying to \"fix\" DOM in certain situations. For example, when the user starts to type\n\t * in `<p><a href=\"\"><i>Link{}</i></a></p>`, the browser might change the order of elements\n\t * to `<p><i><a href=\"\">Link</a>x{}</i></p>`. A similar situation happens when the spell checker\n\t * replaces a word wrapped with `<strong>` with a word wrapped with a `<b>` element.\n\t *\n\t * To handle such situations, the common DOM ancestor of all mutations is converted to the model representation\n\t * and then compared with the current model to calculate the proper text change.\n\t *\n\t * Note: Single text node insertion is handled in {@link #_handleTextNodeInsertion} and text node mutation is handled\n\t * in {@link #_handleTextMutation}).\n\t *\n\t * @private\n\t * @param {Array.<module:engine/view/observer/mutationobserver~MutatedText|\n\t * module:engine/view/observer/mutationobserver~MutatedChildren>} mutations\n\t * @param {module:engine/view/selection~Selection|null} viewSelection\n\t */\n\t_handleContainerChildrenMutations( mutations, viewSelection ) {\n\t\t// Get common ancestor of all mutations.\n\t\tconst mutationsCommonAncestor = getMutationsContainer( mutations );\n\n\t\t// Quit if there is no common ancestor.\n\t\tif ( !mutationsCommonAncestor ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst domConverter = this.editor.editing.view.domConverter;\n\n\t\t// Get common ancestor in DOM.\n\t\tconst domMutationCommonAncestor = domConverter.mapViewToDom( mutationsCommonAncestor );\n\n\t\t// Create fresh DomConverter so it will not use existing mapping and convert current DOM to model.\n\t\t// This wouldn't be needed if DomConverter would allow to create fresh view without checking any mappings.\n\t\tconst freshDomConverter = new DomConverter( this.editor.editing.view.document );\n\t\tconst modelFromCurrentDom = this.editor.data.toModel(\n\t\t\tfreshDomConverter.domToView( domMutationCommonAncestor )\n\t\t).getChild( 0 );\n\n\t\t// Current model.\n\t\tconst currentModel = this.editor.editing.mapper.toModelElement( mutationsCommonAncestor );\n\n\t\t// If common ancestor is not mapped, do not do anything. It probably is a parent of another view element.\n\t\t// That means that we would need to diff model elements (see `if` below). Better return early instead of\n\t\t// trying to get a reasonable model ancestor. It will fell into the `if` below anyway.\n\t\t// This situation happens for example for lists. If `<ul>` is a common ancestor, `currentModel` is `undefined`\n\t\t// because `<ul>` is not mapped (`<li>`s are).\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/718.\n\t\tif ( !currentModel ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Get children from both ancestors.\n\t\tconst modelFromDomChildren = Array.from( modelFromCurrentDom.getChildren() );\n\t\tconst currentModelChildren = Array.from( currentModel.getChildren() );\n\n\t\t// Remove the last `<softBreak>` from the end of `modelFromDomChildren` if there is no `<softBreak>` in current model.\n\t\t// If the described scenario happened, it means that this is a bogus `<br />` added by a browser.\n\t\tconst lastDomChild = modelFromDomChildren[ modelFromDomChildren.length - 1 ];\n\t\tconst lastCurrentChild = currentModelChildren[ currentModelChildren.length - 1 ];\n\n\t\tconst isLastDomChildSoftBreak = lastDomChild && lastDomChild.is( 'element', 'softBreak' );\n\t\tconst isLastCurrentChildSoftBreak = lastCurrentChild && !lastCurrentChild.is( 'element', 'softBreak' );\n\n\t\tif ( isLastDomChildSoftBreak && isLastCurrentChildSoftBreak ) {\n\t\t\tmodelFromDomChildren.pop();\n\t\t}\n\n\t\tconst schema = this.editor.model.schema;\n\n\t\t// Skip situations when common ancestor has any container elements.\n\t\tif ( !isSafeForTextMutation( modelFromDomChildren, schema ) || !isSafeForTextMutation( currentModelChildren, schema ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Replace &nbsp; inserted by the browser with normal space. See comment in `_handleTextMutation`.\n\t\t// Replace non-texts with any character. This is potentially dangerous but passes in manual tests. The thing is\n\t\t// that we need to take care of proper indexes so we cannot simply remove non-text elements from the content.\n\t\t// By inserting a character we keep all the real texts on their indexes.\n\t\tconst newText = modelFromDomChildren.map( item => item.is( '$text' ) ? item.data : '@' ).join( '' ).replace( /\\u00A0/g, ' ' );\n\t\tconst oldText = currentModelChildren.map( item => item.is( '$text' ) ? item.data : '@' ).join( '' ).replace( /\\u00A0/g, ' ' );\n\n\t\t// Do nothing if mutations created same text.\n\t\tif ( oldText === newText ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst diffResult = diff( oldText, newText );\n\n\t\tconst { firstChangeAt, insertions, deletions } = calculateChanges( diffResult );\n\n\t\t// Try setting new model selection according to passed view selection.\n\t\tlet modelSelectionRange = null;\n\n\t\tif ( viewSelection ) {\n\t\t\tmodelSelectionRange = this.editing.mapper.toModelRange( viewSelection.getFirstRange() );\n\t\t}\n\n\t\tconst insertText = newText.substr( firstChangeAt, insertions );\n\t\tconst removeRange = this.editor.model.createRange(\n\t\t\tthis.editor.model.createPositionAt( currentModel, firstChangeAt ),\n\t\t\tthis.editor.model.createPositionAt( currentModel, firstChangeAt + deletions )\n\t\t);\n\n\t\tthis.editor.execute( 'input', {\n\t\t\ttext: insertText,\n\t\t\trange: removeRange,\n\t\t\tresultRange: modelSelectionRange\n\t\t} );\n\t}\n\n\t/**\n\t * @private\n\t */\n\t_handleTextMutation( mutation, viewSelection ) {\n\t\tif ( mutation.type != 'text' ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Replace &nbsp; inserted by the browser with normal space.\n\t\t// We want only normal spaces in the model and in the view. Renderer and DOM Converter will be then responsible\n\t\t// for rendering consecutive spaces using &nbsp;, but the model and the view has to be clear.\n\t\t// Other feature may introduce inserting non-breakable space on specific key stroke (for example shift + space).\n\t\t// However then it will be handled outside of mutations, like enter key is.\n\t\t// The replacing is here because it has to be done before `diff` and `diffToChanges` functions, as they\n\t\t// take `newText` and compare it to (cleaned up) view.\n\t\t// It could also be done in mutation observer too, however if any outside plugin would like to\n\t\t// introduce additional events for mutations, they would get already cleaned up version (this may be good or not).\n\t\tconst newText = mutation.newText.replace( /\\u00A0/g, ' ' );\n\t\t// To have correct `diffResult`, we also compare view node text data with &nbsp; replaced by space.\n\t\tconst oldText = mutation.oldText.replace( /\\u00A0/g, ' ' );\n\n\t\t// Do nothing if mutations created same text.\n\t\tif ( oldText === newText ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst diffResult = diff( oldText, newText );\n\n\t\tconst { firstChangeAt, insertions, deletions } = calculateChanges( diffResult );\n\n\t\t// Try setting new model selection according to passed view selection.\n\t\tlet modelSelectionRange = null;\n\n\t\tif ( viewSelection ) {\n\t\t\tmodelSelectionRange = this.editing.mapper.toModelRange( viewSelection.getFirstRange() );\n\t\t}\n\n\t\t// Get the position in view and model where the changes will happen.\n\t\tconst viewPos = this.editing.view.createPositionAt( mutation.node, firstChangeAt );\n\t\tconst modelPos = this.editing.mapper.toModelPosition( viewPos );\n\t\tconst removeRange = this.editor.model.createRange( modelPos, modelPos.getShiftedBy( deletions ) );\n\t\tconst insertText = newText.substr( firstChangeAt, insertions );\n\n\t\tthis.editor.execute( 'input', {\n\t\t\ttext: insertText,\n\t\t\trange: removeRange,\n\t\t\tresultRange: modelSelectionRange\n\t\t} );\n\t}\n\n\t/**\n\t * @private\n\t */\n\t_handleTextNodeInsertion( mutation ) {\n\t\tif ( mutation.type != 'children' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst change = getSingleTextNodeChange( mutation );\n\t\tconst viewPos = this.editing.view.createPositionAt( mutation.node, change.index );\n\t\tconst modelPos = this.editing.mapper.toModelPosition( viewPos );\n\t\tconst insertedText = change.values[ 0 ].data;\n\n\t\tthis.editor.execute( 'input', {\n\t\t\t// Replace &nbsp; inserted by the browser with normal space.\n\t\t\t// See comment in `_handleTextMutation`.\n\t\t\t// In this case we don't need to do this before `diff` because we diff whole nodes.\n\t\t\t// Just change &nbsp; in case there are some.\n\t\t\ttext: insertedText.replace( /\\u00A0/g, ' ' ),\n\t\t\trange: this.editor.model.createRange( modelPos )\n\t\t} );\n\t}\n}\n\n// Returns first common ancestor of all mutations that is either {@link module:engine/view/containerelement~ContainerElement}\n// or {@link module:engine/view/rootelement~RootElement}.\n//\n// @private\n// @param {Array.<module:engine/view/observer/mutationobserver~MutatedText|\n// module:engine/view/observer/mutationobserver~MutatedChildren>} mutations\n// @returns {module:engine/view/containerelement~ContainerElement|engine/view/rootelement~RootElement|undefined}\nfunction getMutationsContainer( mutations ) {\n\tconst lca = mutations\n\t\t.map( mutation => mutation.node )\n\t\t.reduce( ( commonAncestor, node ) => {\n\t\t\treturn commonAncestor.getCommonAncestor( node, { includeSelf: true } );\n\t\t} );\n\n\tif ( !lca ) {\n\t\treturn;\n\t}\n\n\t// We need to look for container and root elements only, so check all LCA's\n\t// ancestors (starting from itself).\n\treturn lca.getAncestors( { includeSelf: true, parentFirst: true } )\n\t\t.find( element => element.is( 'containerElement' ) || element.is( 'rootElement' ) );\n}\n\n// Returns true if provided array contains content that won't be problematic during diffing and text mutation handling.\n//\n// @param {Array.<module:engine/model/node~Node>} children\n// @param {module:engine/model/schema~Schema} schema\n// @returns {Boolean}\nfunction isSafeForTextMutation( children, schema ) {\n\treturn children.every( child => schema.isInline( child ) );\n}\n\n// Calculates first change index and number of characters that should be inserted and deleted starting from that index.\n//\n// @private\n// @param diffResult\n// @returns {{insertions: number, deletions: number, firstChangeAt: *}}\nfunction calculateChanges( diffResult ) {\n\t// Index where the first change happens. Used to set the position from which nodes will be removed and where will be inserted.\n\tlet firstChangeAt = null;\n\t// Index where the last change happens. Used to properly count how many characters have to be removed and inserted.\n\tlet lastChangeAt = null;\n\n\t// Get `firstChangeAt` and `lastChangeAt`.\n\tfor ( let i = 0; i < diffResult.length; i++ ) {\n\t\tconst change = diffResult[ i ];\n\n\t\tif ( change != 'equal' ) {\n\t\t\tfirstChangeAt = firstChangeAt === null ? i : firstChangeAt;\n\t\t\tlastChangeAt = i;\n\t\t}\n\t}\n\n\t// How many characters, starting from `firstChangeAt`, should be removed.\n\tlet deletions = 0;\n\t// How many characters, starting from `firstChangeAt`, should be inserted.\n\tlet insertions = 0;\n\n\tfor ( let i = firstChangeAt; i <= lastChangeAt; i++ ) {\n\t\t// If there is no change (equal) or delete, the character is existing in `oldText`. We count it for removing.\n\t\tif ( diffResult[ i ] != 'insert' ) {\n\t\t\tdeletions++;\n\t\t}\n\n\t\t// If there is no change (equal) or insert, the character is existing in `newText`. We count it for inserting.\n\t\tif ( diffResult[ i ] != 'delete' ) {\n\t\t\tinsertions++;\n\t\t}\n\t}\n\n\treturn { insertions, deletions, firstChangeAt };\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/input\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport InputCommand from './inputcommand';\n\nimport injectUnsafeKeystrokesHandling from './utils/injectunsafekeystrokeshandling';\nimport injectTypingMutationsHandling from './utils/injecttypingmutationshandling';\n\n/**\n * Handles text input coming from the keyboard or other input methods.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Input extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Input';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// TODO The above default configuration value should be defined using editor.config.define() once it's fixed.\n\t\tconst inputCommand = new InputCommand( editor, editor.config.get( 'typing.undoStep' ) || 20 );\n\n\t\teditor.commands.add( 'input', inputCommand );\n\n\t\tinjectUnsafeKeystrokesHandling( editor );\n\t\tinjectTypingMutationsHandling( editor );\n\t}\n\n\t/**\n\t * Checks batch if it is a result of user input - e.g. typing.\n\t *\n\t *\t\tconst input = editor.plugins.get( 'Input' );\n\t *\n\t *\t\teditor.model.document.on( 'change:data', ( evt, batch ) => {\n\t *\t\t\tif ( input.isInput( batch ) ) {\n\t *\t\t\t\tconsole.log( 'The user typed something...' );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * **Note:** This method checks if the batch was created using {@link module:typing/inputcommand~InputCommand 'input'}\n\t * command as typing changes coming from user input are inserted to the document using that command.\n\t *\n\t * @param {module:engine/model/batch~Batch} batch A batch to check.\n\t * @returns {Boolean}\n\t */\n\tisInput( batch ) {\n\t\tconst inputCommand = this.editor.commands.get( 'input' );\n\n\t\treturn inputCommand._batches.has( batch );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/deletecommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport count from '@ckeditor/ckeditor5-utils/src/count';\n\nimport ChangeBuffer from './utils/changebuffer';\n\n/**\n * The delete command. Used by the {@link module:typing/delete~Delete delete feature} to handle the <kbd>Delete</kbd> and\n * <kbd>Backspace</kbd> keys.\n *\n * @extends module:core/command~Command\n */\nexport default class DeleteCommand extends Command {\n\t/**\n\t * Creates an instance of the command.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor\n\t * @param {'forward'|'backward'} direction The directionality of the delete describing in what direction it\n\t * should consume the content when the selection is collapsed.\n\t */\n\tconstructor( editor, direction ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The directionality of the delete describing in what direction it should\n\t\t * consume the content when the selection is collapsed.\n\t\t *\n\t\t * @readonly\n\t\t * @member {'forward'|'backward'} #direction\n\t\t */\n\t\tthis.direction = direction;\n\n\t\t/**\n\t\t * Delete's change buffer used to group subsequent changes into batches.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @type {module:typing/utils/changebuffer~ChangeBuffer}\n\t\t */\n\t\tthis._buffer = new ChangeBuffer( editor.model, editor.config.get( 'typing.undoStep' ) );\n\t}\n\n\t/**\n\t * The current change buffer.\n\t *\n\t * @type {module:typing/utils/changebuffer~ChangeBuffer}\n\t */\n\tget buffer() {\n\t\treturn this._buffer;\n\t}\n\n\t/**\n\t * Executes the delete command. Depending on whether the selection is collapsed or not, deletes its content\n\t * or a piece of content in the {@link #direction defined direction}.\n\t *\n\t * @fires execute\n\t * @param {Object} [options] The command options.\n\t * @param {'character'} [options.unit='character'] See {@link module:engine/model/utils/modifyselection~modifySelection}'s options.\n\t * @param {Number} [options.sequence=1] A number describing which subsequent delete event it is without the key being released.\n\t * See the {@link module:engine/view/document~Document#event:delete} event data.\n\t * @param {module:engine/model/selection~Selection} [options.selection] Selection to remove. If not set, current model selection\n\t * will be used.\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tmodel.enqueueChange( this._buffer.batch, writer => {\n\t\t\tthis._buffer.lock();\n\n\t\t\tconst selection = writer.createSelection( options.selection || doc.selection );\n\n\t\t\t// Do not replace the whole selected content if selection was collapsed.\n\t\t\t// This prevents such situation:\n\t\t\t//\n\t\t\t// <h1></h1><p>[]</p>\t-->  <h1>[</h1><p>]</p> \t\t-->  <p></p>\n\t\t\t// starting content\t\t-->   after `modifySelection`\t-->  after `deleteContent`.\n\t\t\tconst doNotResetEntireContent = selection.isCollapsed;\n\n\t\t\t// Try to extend the selection in the specified direction.\n\t\t\tif ( selection.isCollapsed ) {\n\t\t\t\tmodel.modifySelection( selection, { direction: this.direction, unit: options.unit } );\n\t\t\t}\n\n\t\t\t// Check if deleting in an empty editor. See #61.\n\t\t\tif ( this._shouldEntireContentBeReplacedWithParagraph( options.sequence || 1 ) ) {\n\t\t\t\tthis._replaceEntireContentWithParagraph( writer );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If selection is still collapsed, then there's nothing to delete.\n\t\t\tif ( selection.isCollapsed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet changeCount = 0;\n\n\t\t\tselection.getFirstRange().getMinimalFlatRanges().forEach( range => {\n\t\t\t\tchangeCount += count(\n\t\t\t\t\trange.getWalker( { singleCharacters: true, ignoreElementEnd: true, shallow: true } )\n\t\t\t\t);\n\t\t\t} );\n\n\t\t\tmodel.deleteContent( selection, {\n\t\t\t\tdoNotResetEntireContent,\n\t\t\t\tdirection: this.direction\n\t\t\t} );\n\n\t\t\tthis._buffer.input( changeCount );\n\n\t\t\twriter.setSelection( selection );\n\n\t\t\tthis._buffer.unlock();\n\t\t} );\n\t}\n\n\t/**\n\t * If the user keeps <kbd>Backspace</kbd> or <kbd>Delete</kbd> key pressed, the content of the current\n\t * editable will be cleared. However, this will not yet lead to resetting the remaining block to a paragraph\n\t * (which happens e.g. when the user does <kbd>Ctrl</kbd> + <kbd>A</kbd>, <kbd>Backspace</kbd>).\n\t *\n\t * But, if the user pressed the key in an empty editable for the first time,\n\t * we want to replace the entire content with a paragraph if:\n\t *\n\t * * the current limit element is empty,\n\t * * the paragraph is allowed in the limit element,\n\t * * the limit doesn't already have a paragraph inside.\n\t *\n\t * See https://github.com/ckeditor/ckeditor5-typing/issues/61.\n\t *\n\t * @private\n\t * @param {Number} sequence A number describing which subsequent delete event it is without the key being released.\n\t * @returns {Boolean}\n\t */\n\t_shouldEntireContentBeReplacedWithParagraph( sequence ) {\n\t\t// Does nothing if user pressed and held the \"Backspace\" or \"Delete\" key.\n\t\tif ( sequence > 1 ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst selection = doc.selection;\n\t\tconst limitElement = model.schema.getLimitElement( selection );\n\n\t\t// If a collapsed selection contains the whole content it means that the content is empty\n\t\t// (from the user perspective).\n\t\tconst limitElementIsEmpty = selection.isCollapsed && selection.containsEntireContent( limitElement );\n\n\t\tif ( !limitElementIsEmpty ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( !model.schema.checkChild( limitElement, 'paragraph' ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst limitElementFirstChild = limitElement.getChild( 0 );\n\n\t\t// Does nothing if the limit element already contains only a paragraph.\n\t\t// We ignore the case when paragraph might have some inline elements (<p><inlineWidget>[]</inlineWidget></p>)\n\t\t// because we don't support such cases yet and it's unclear whether inlineWidget shouldn't be a limit itself.\n\t\tif ( limitElementFirstChild && limitElementFirstChild.name === 'paragraph' ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * The entire content is replaced with the paragraph. Selection is moved inside the paragraph.\n\t *\n\t * @private\n\t */\n\t_replaceEntireContentWithParagraph( writer ) {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst selection = doc.selection;\n\t\tconst limitElement = model.schema.getLimitElement( selection );\n\t\tconst paragraph = writer.createElement( 'paragraph' );\n\n\t\twriter.remove( writer.createRangeIn( limitElement ) );\n\t\twriter.insert( paragraph, limitElement );\n\n\t\twriter.setSelection( paragraph, 0 );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/deleteobserver\n */\n\nimport Observer from '@ckeditor/ckeditor5-engine/src/view/observer/observer';\nimport DomEventData from '@ckeditor/ckeditor5-engine/src/view/observer/domeventdata';\nimport { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\n/**\n * Delete observer introduces the {@link module:engine/view/document~Document#event:delete} event.\n *\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class DeleteObserver extends Observer {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tconst document = view.document;\n\t\tlet sequence = 0;\n\n\t\tdocument.on( 'keyup', ( evt, data ) => {\n\t\t\tif ( data.keyCode == keyCodes.delete || data.keyCode == keyCodes.backspace ) {\n\t\t\t\tsequence = 0;\n\t\t\t}\n\t\t} );\n\n\t\tdocument.on( 'keydown', ( evt, data ) => {\n\t\t\tconst deleteData = {};\n\n\t\t\tif ( data.keyCode == keyCodes.delete ) {\n\t\t\t\tdeleteData.direction = 'forward';\n\t\t\t\tdeleteData.unit = 'character';\n\t\t\t} else if ( data.keyCode == keyCodes.backspace ) {\n\t\t\t\tdeleteData.direction = 'backward';\n\t\t\t\tdeleteData.unit = 'codePoint';\n\t\t\t} else {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst hasWordModifier = env.isMac ? data.altKey : data.ctrlKey;\n\t\t\tdeleteData.unit = hasWordModifier ? 'word' : deleteData.unit;\n\t\t\tdeleteData.sequence = ++sequence;\n\n\t\t\tfireViewDeleteEvent( evt, data.domEvent, deleteData );\n\t\t} );\n\n\t\t// `beforeinput` is handled only for Android devices. Desktop Chrome and iOS are skipped because they are working fine now.\n\t\tif ( env.isAndroid ) {\n\t\t\tdocument.on( 'beforeinput', ( evt, data ) => {\n\t\t\t\t// If event type is other than `deleteContentBackward` then this is not deleting.\n\t\t\t\tif ( data.domEvent.inputType != 'deleteContentBackward' ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst deleteData = {\n\t\t\t\t\tunit: 'codepoint',\n\t\t\t\t\tdirection: 'backward',\n\t\t\t\t\tsequence: 1\n\t\t\t\t};\n\n\t\t\t\t// Android IMEs may change the DOM selection on `beforeinput` event so that the selection contains all the text\n\t\t\t\t// that the IME wants to remove. We will pass this information to `delete` event so proper part of the content is removed.\n\t\t\t\t//\n\t\t\t\t// Sometimes it is only expanding by a one character (in case of collapsed selection). In this case we don't need to\n\t\t\t\t// set a different selection to remove, it will work just fine.\n\t\t\t\tconst domSelection = data.domTarget.ownerDocument.defaultView.getSelection();\n\n\t\t\t\tif ( domSelection.anchorNode == domSelection.focusNode && domSelection.anchorOffset + 1 != domSelection.focusOffset ) {\n\t\t\t\t\tdeleteData.selectionToRemove = view.domConverter.domSelectionToView( domSelection );\n\t\t\t\t}\n\n\t\t\t\tfireViewDeleteEvent( evt, data.domEvent, deleteData );\n\t\t\t} );\n\t\t}\n\n\t\tfunction fireViewDeleteEvent( originalEvent, domEvent, deleteData ) {\n\t\t\t// Save the event object to check later if it was stopped or not.\n\t\t\tlet event;\n\t\t\tdocument.once( 'delete', evt => ( event = evt ), { priority: Number.POSITIVE_INFINITY } );\n\n\t\t\tdocument.fire( 'delete', new DomEventData( document, domEvent, deleteData ) );\n\n\t\t\t// Stop the original event if `delete` event was stopped.\n\t\t\t// https://github.com/ckeditor/ckeditor5/issues/753\n\t\t\tif ( event && event.stop.called ) {\n\t\t\t\toriginalEvent.stop();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve() {}\n}\n\n/**\n * Event fired when the user tries to delete content (e.g. presses <kbd>Delete</kbd> or <kbd>Backspace</kbd>).\n *\n * Note: This event is fired by the {@link module:typing/deleteobserver~DeleteObserver observer}\n * (usually registered by the {@link module:typing/delete~Delete delete feature}).\n *\n * @event module:engine/view/document~Document#event:delete\n * @param {module:engine/view/observer/domeventdata~DomEventData} data\n * @param {'forward'|'delete'} data.direction The direction in which the deletion should happen.\n * @param {'character'|'word'} data.unit The \"amount\" of content that should be deleted.\n * @param {Number} data.sequence A number describing which subsequent delete event it is without the key being released.\n * If it's 2 or more it means that the key was pressed and hold.\n * @param {module:engine/view/selection~Selection} [data.selectionToRemove] View selection which content should be removed. If not set,\n * current selection should be used.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/delete\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport DeleteCommand from './deletecommand';\nimport DeleteObserver from './deleteobserver';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\n/**\n * The delete and backspace feature. Handles the <kbd>Delete</kbd> and <kbd>Backspace</kbd> keys in the editor.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Delete extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Delete';\n\t}\n\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\tview.addObserver( DeleteObserver );\n\n\t\teditor.commands.add( 'forwardDelete', new DeleteCommand( editor, 'forward' ) );\n\t\teditor.commands.add( 'delete', new DeleteCommand( editor, 'backward' ) );\n\n\t\tthis.listenTo( viewDocument, 'delete', ( evt, data ) => {\n\t\t\tconst deleteCommandParams = { unit: data.unit, sequence: data.sequence };\n\n\t\t\t// If a specific (view) selection to remove was set, convert it to a model selection and set as a parameter for `DeleteCommand`.\n\t\t\tif ( data.selectionToRemove ) {\n\t\t\t\tconst modelSelection = editor.model.createSelection();\n\t\t\t\tconst ranges = [];\n\n\t\t\t\tfor ( const viewRange of data.selectionToRemove.getRanges() ) {\n\t\t\t\t\tranges.push( editor.editing.mapper.toModelRange( viewRange ) );\n\t\t\t\t}\n\n\t\t\t\tmodelSelection.setTo( ranges );\n\n\t\t\t\tdeleteCommandParams.selection = modelSelection;\n\t\t\t}\n\n\t\t\teditor.execute( data.direction == 'forward' ? 'forwardDelete' : 'delete', deleteCommandParams );\n\n\t\t\tdata.preventDefault();\n\n\t\t\tview.scrollToTheSelection();\n\t\t} );\n\n\t\t// Android IMEs have a quirk - they change DOM selection after the input changes were performed by the browser.\n\t\t// This happens on `keyup` event. Android doesn't know anything about our deletion and selection handling. Even if the selection\n\t\t// was changed during input events, IME remembers the position where the selection \"should\" be placed and moves it there.\n\t\t//\n\t\t// To prevent incorrect selection, we save the selection after deleting here and then re-set it on `keyup`. This has to be done\n\t\t// on DOM selection level, because on `keyup` the model selection is still the same as it was just after deletion, so it\n\t\t// wouldn't be changed and the fix would do nothing.\n\t\t//\n\t\tif ( env.isAndroid ) {\n\t\t\tlet domSelectionAfterDeletion = null;\n\n\t\t\tthis.listenTo( viewDocument, 'delete', ( evt, data ) => {\n\t\t\t\tconst domSelection = data.domTarget.ownerDocument.defaultView.getSelection();\n\n\t\t\t\tdomSelectionAfterDeletion = {\n\t\t\t\t\tanchorNode: domSelection.anchorNode,\n\t\t\t\t\tanchorOffset: domSelection.anchorOffset,\n\t\t\t\t\tfocusNode: domSelection.focusNode,\n\t\t\t\t\tfocusOffset: domSelection.focusOffset\n\t\t\t\t};\n\t\t\t}, { priority: 'lowest' } );\n\n\t\t\tthis.listenTo( viewDocument, 'keyup', ( evt, data ) => {\n\t\t\t\tif ( domSelectionAfterDeletion ) {\n\t\t\t\t\tconst domSelection = data.domTarget.ownerDocument.defaultView.getSelection();\n\n\t\t\t\t\tdomSelection.collapse( domSelectionAfterDeletion.anchorNode, domSelectionAfterDeletion.anchorOffset );\n\t\t\t\t\tdomSelection.extend( domSelectionAfterDeletion.focusNode, domSelectionAfterDeletion.focusOffset );\n\n\t\t\t\t\tdomSelectionAfterDeletion = null;\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/typing\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Input from './input';\nimport Delete from './delete';\n\n/**\n * The typing feature. It handles typing.\n *\n * This is a \"glue\" plugin which loads the {@link module:typing/input~Input} and {@link module:typing/delete~Delete}\n * plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Typing extends Plugin {\n\tstatic get requires() {\n\t\treturn [ Input, Delete ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Typing';\n\t}\n}\n\n/**\n * The configuration of the typing features. Used by the features from the `@ckeditor/ckeditor5-typing` package.\n *\n * Read more in {@link module:typing/typing~TypingConfig}.\n *\n * @member {module:typing/typing~TypingConfig} module:core/editor/editorconfig~EditorConfig#typing\n */\n\n/**\n * The configuration of the typing features. Used by the typing features in `@ckeditor/ckeditor5-typing` package.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\ttyping: ... // Typing feature options.\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface TypingConfig\n */\n\n/**\n * The granularity of undo/redo for typing and deleting. The value `20` means (more or less) that a new undo step\n * is created every 20 characters are inserted or deleted.\n *\n * @member {Number} [module:typing/typing~TypingConfig#undoStep=20]\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport InsertOperation from './insertoperation';\nimport AttributeOperation from './attributeoperation';\nimport RenameOperation from './renameoperation';\nimport MarkerOperation from './markeroperation';\nimport MoveOperation from './moveoperation';\nimport RootAttributeOperation from './rootattributeoperation';\nimport MergeOperation from './mergeoperation';\nimport SplitOperation from './splitoperation';\nimport NoOperation from './nooperation';\nimport Range from '../range';\nimport Position from '../position';\n\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\n\nconst transformations = new Map();\n\n/**\n * @module engine/model/operation/transform\n */\n\n/**\n * Sets a transformation function to be be used to transform instances of class `OperationA` by instances of class `OperationB`.\n *\n * The `transformationFunction` is passed three parameters:\n *\n * * `a` - operation to be transformed, an instance of `OperationA`,\n * * `b` - operation to be transformed by, an instance of `OperationB`,\n * * {@link module:engine/model/operation/transform~TransformationContext `context`} - object with additional information about\n * transformation context.\n *\n * The `transformationFunction` should return transformation result, which is an array with one or multiple\n * {@link module:engine/model/operation/operation~Operation operation} instances.\n *\n * @protected\n * @param {Function} OperationA\n * @param {Function} OperationB\n * @param {Function} transformationFunction Function to use for transforming.\n */\nfunction setTransformation( OperationA, OperationB, transformationFunction ) {\n\tlet aGroup = transformations.get( OperationA );\n\n\tif ( !aGroup ) {\n\t\taGroup = new Map();\n\t\ttransformations.set( OperationA, aGroup );\n\t}\n\n\taGroup.set( OperationB, transformationFunction );\n}\n\n/**\n * Returns a previously set transformation function for transforming an instance of `OperationA` by an instance of `OperationB`.\n *\n * If no transformation was set for given pair of operations, {@link module:engine/model/operation/transform~noUpdateTransformation}\n * is returned. This means that if no transformation was set, the `OperationA` instance will not change when transformed\n * by the `OperationB` instance.\n *\n * @private\n * @param {Function} OperationA\n * @param {Function} OperationB\n * @returns {Function} Function set to transform an instance of `OperationA` by an instance of `OperationB`.\n */\nfunction getTransformation( OperationA, OperationB ) {\n\tconst aGroup = transformations.get( OperationA );\n\n\tif ( aGroup && aGroup.has( OperationB ) ) {\n\t\treturn aGroup.get( OperationB );\n\t}\n\n\treturn noUpdateTransformation;\n}\n\n/**\n * A transformation function that only clones operation to transform, without changing it.\n *\n * @private\n * @param {module:engine/model/operation/operation~Operation} a Operation to transform.\n * @returns {Array.<module:engine/model/operation/operation~Operation>}\n */\nfunction noUpdateTransformation( a ) {\n\treturn [ a ];\n}\n\n/**\n * Transforms operation `a` by operation `b`.\n *\n * @param {module:engine/model/operation/operation~Operation} a Operation to be transformed.\n * @param {module:engine/model/operation/operation~Operation} b Operation to transform by.\n * @param {module:engine/model/operation/transform~TransformationContext} context Transformation context for this transformation.\n * @returns {Array.<module:engine/model/operation/operation~Operation>} Transformation result.\n */\nexport function transform( a, b, context = {} ) {\n\tconst transformationFunction = getTransformation( a.constructor, b.constructor );\n\n\t/* eslint-disable no-useless-catch */\n\ttry {\n\t\ta = a.clone();\n\n\t\treturn transformationFunction( a, b, context );\n\t} catch ( e ) {\n\t\t// @if CK_DEBUG // console.warn( 'Error during operation transformation!', e.message );\n\t\t// @if CK_DEBUG // console.warn( 'Transformed operation', a );\n\t\t// @if CK_DEBUG // console.warn( 'Operation transformed by', b );\n\t\t// @if CK_DEBUG // console.warn( 'context.aIsStrong', context.aIsStrong );\n\t\t// @if CK_DEBUG // console.warn( 'context.aWasUndone', context.aWasUndone );\n\t\t// @if CK_DEBUG // console.warn( 'context.bWasUndone', context.bWasUndone );\n\t\t// @if CK_DEBUG // console.warn( 'context.abRelation', context.abRelation );\n\t\t// @if CK_DEBUG // console.warn( 'context.baRelation', context.baRelation );\n\n\t\tthrow e;\n\t}\n\t/* eslint-enable no-useless-catch */\n}\n\n/**\n * Performs a transformation of two sets of operations - `operationsA` and `operationsB`. The transformation is two-way -\n * both transformed `operationsA` and transformed `operationsB` are returned.\n *\n * Note, that the first operation in each set should base on the same document state (\n * {@link module:engine/model/document~Document#version document version}).\n *\n * It is assumed that `operationsA` are \"more important\" during conflict resolution between two operations.\n *\n * New copies of both passed arrays and operations inside them are returned. Passed arguments are not altered.\n *\n * Base versions of the transformed operations sets are updated accordingly. For example, assume that base versions are `4`\n * and there are `3` operations in `operationsA` and `5` operations in `operationsB`. Then:\n *\n * * transformed `operationsA` will start from base version `9` (`4` base version + `5` operations B),\n * * transformed `operationsB` will start from base version `7` (`4` base version + `3` operations A).\n *\n * If no operation was broken into two during transformation, then both sets will end up with an operation that bases on version `11`:\n *\n * * transformed `operationsA` start from `9` and there are `3` of them, so the last will have `baseVersion` equal to `11`,\n * * transformed `operationsB` start from `7` and there are `5` of them, so the last will have `baseVersion` equal to `11`.\n *\n * @param {Array.<module:engine/model/operation/operation~Operation>} operationsA\n * @param {Array.<module:engine/model/operation/operation~Operation>} operationsB\n * @param {Object} options Additional transformation options.\n * @param {module:engine/model/document~Document|null} options.document Document which the operations change.\n * @param {Boolean} [options.useRelations=false] Whether during transformation relations should be used (used during undo for\n * better conflict resolution).\n * @param {Boolean} [options.padWithNoOps=false] Whether additional {@link module:engine/model/operation/nooperation~NoOperation}s\n * should be added to the transformation results to force the same last base version for both transformed sets (in case\n * if some operations got broken into multiple operations during transformation).\n * @returns {Object} Transformation result.\n * @returns {Array.<module:engine/model/operation/operation~Operation>} return.operationsA Transformed `operationsA`.\n * @returns {Array.<module:engine/model/operation/operation~Operation>} return.operationsB Transformed `operationsB`.\n * @returns {Map} return.originalOperations A map that links transformed operations to original operations. The keys are the transformed\n * operations and the values are the original operations from the input (`operationsA` and `operationsB`).\n */\nexport function transformSets( operationsA, operationsB, options ) {\n\t// Create new arrays so the originally passed arguments are not changed.\n\t// No need to clone operations, they are cloned as they are transformed.\n\toperationsA = operationsA.slice();\n\toperationsB = operationsB.slice();\n\n\tconst contextFactory = new ContextFactory( options.document, options.useRelations, options.forceWeakRemove );\n\tcontextFactory.setOriginalOperations( operationsA );\n\tcontextFactory.setOriginalOperations( operationsB );\n\n\tconst originalOperations = contextFactory.originalOperations;\n\n\t// If one of sets is empty there is simply nothing to transform, so return sets as they are.\n\tif ( operationsA.length == 0 || operationsB.length == 0 ) {\n\t\treturn { operationsA, operationsB, originalOperations };\n\t}\n\t//\n\t// Following is a description of transformation process:\n\t//\n\t// There are `operationsA` and `operationsB` to be transformed, both by both.\n\t//\n\t// So, suppose we have sets of two operations each: `operationsA` = `[ a1, a2 ]`, `operationsB` = `[ b1, b2 ]`.\n\t//\n\t// Remember, that we can only transform operations that base on the same context. We assert that `a1` and `b1` base on\n\t// the same context and we transform them. Then, we get `a1'` and `b1'`. `a2` bases on a context with `a1` -- `a2`\n\t// is an operation that followed `a1`. Similarly, `b2` bases on a context with `b1`.\n\t//\n\t// However, since `a1'` is a result of transformation by `b1`, `a1'` now also has a context with `b1`. This means that\n\t// we can safely transform `a1'` by `b2`. As we finish transforming `a1`, we also transformed all `operationsB`.\n\t// All `operationsB` also have context including `a1`. Now, we can properly transform `a2` by those operations.\n\t//\n\t// The transformation process can be visualized on a transformation diagram (\"diamond diagram\"):\n\t//\n\t//          [the initial state]\n\t//         [common for a1 and b1]\n\t//\n\t//                   *\n\t//                  / \\\n\t//                 /   \\\n\t//               b1     a1\n\t//               /       \\\n\t//              /         \\\n\t//             *           *\n\t//            / \\         / \\\n\t//           /   \\       /   \\\n\t//         b2    a1'   b1'    a2\n\t//         /       \\   /       \\\n\t//        /         \\ /         \\\n\t//       *           *           *\n\t//        \\         / \\         /\n\t//         \\       /   \\       /\n\t//        a1''   b2'   a2'   b1''\n\t//           \\   /       \\   /\n\t//            \\ /         \\ /\n\t//             *           *\n\t//              \\         /\n\t//               \\       /\n\t//              a2''   b2''\n\t//                 \\   /\n\t//                  \\ /\n\t//                   *\n\t//\n\t//           [the final state]\n\t//\n\t// The final state can be reached from the initial state by applying `a1`, `a2`, `b1''` and `b2''`, as well as by\n\t// applying `b1`, `b2`, `a1''`, `a2''`. Note how the operations get to a proper common state before each pair is\n\t// transformed.\n\t//\n\t// Another thing to consider is that an operation during transformation can be broken into multiple operations.\n\t// Suppose that `a1` * `b1` = `[ a11', a12' ]` (instead of `a1'` that we considered previously).\n\t//\n\t// In that case, we leave `a12'` for later and we continue transforming `a11'` until it is transformed by all `operationsB`\n\t// (in our case it is just `b2`). At this point, `b1` is transformed by \"whole\" `a1`, while `b2` is only transformed\n\t// by `a11'`. Similarly, `a12'` is only transformed by `b1`. This leads to a conclusion that we need to start transforming `a12'`\n\t// from the moment just after it was broken. So, `a12'` is transformed by `b2`. Now, \"the whole\" `a1` is transformed\n\t// by `operationsB`, while all `operationsB` are transformed by \"the whole\" `a1`. This means that we can continue with\n\t// following `operationsA` (in our case it is just `a2`).\n\t//\n\t// Of course, also `operationsB` can be broken. However, since we focus on transforming operation `a` to the end,\n\t// the only thing to do is to store both pieces of operation `b`, so that the next transformed operation `a` will\n\t// be transformed by both of them.\n\t//\n\t//                       *\n\t//                      / \\\n\t//                     /   \\\n\t//                    /     \\\n\t//                  b1       a1\n\t//                  /         \\\n\t//                 /           \\\n\t//                /             \\\n\t//               *               *\n\t//              / \\             / \\\n\t//             /  a11'         /   \\\n\t//            /     \\         /     \\\n\t//          b2       *      b1'      a2\n\t//          /       / \\     /         \\\n\t//         /       /  a12' /           \\\n\t//        /       /     \\ /             \\\n\t//       *       b2'     *               *\n\t//        \\     /       / \\             /\n\t//       a11'' /     b21'' \\           /\n\t//          \\ /       /     \\         /\n\t//           *       *      a2'     b1''\n\t//            \\     / \\       \\     /\n\t//          a12'' b22''\\       \\   /\n\t//              \\ /     \\       \\ /\n\t//               *      a2''     *\n\t//                \\       \\     /\n\t//                 \\       \\  b21'''\n\t//                  \\       \\ /\n\t//                a2'''      *\n\t//                    \\     /\n\t//                     \\  b22'''\n\t//                      \\ /\n\t//                       *\n\t//\n\t// Note, how `a1` is broken and transformed into `a11'` and `a12'`, while `b2'` got broken and transformed into `b21''` and `b22''`.\n\t//\n\t// Having all that on mind, here is an outline for the transformation process algorithm:\n\t//\n\t// 1. We have `operationsA` and `operationsB` array, which we dynamically update as the transformation process goes.\n\t//\n\t// 2. We take next (or first) operation from `operationsA` and check from which operation `b` we need to start transforming it.\n\t// All original `operationsA` are set to be transformed starting from the first operation `b`.\n\t//\n\t// 3. We take operations from `operationsB`, one by one, starting from the correct one, and transform operation `a`\n\t// by operation `b` (and vice versa). We update `operationsA` and `operationsB` by replacing the original operations\n\t// with the transformation results.\n\t//\n\t// 4. If operation is broken into multiple operations, we save all the new operations in the place of the\n\t// original operation.\n\t//\n\t// 5. Additionally, if operation `a` was broken, for the \"new\" operation, we remember from which operation `b` it should\n\t// be transformed by.\n\t//\n\t// 6. We continue transforming \"current\" operation `a` until it is transformed by all `operationsB`. Then, go to 2.\n\t// unless the last operation `a` was transformed.\n\t//\n\t// The actual implementation of the above algorithm is slightly different, as only one loop (while) is used.\n\t// The difference is that we have \"current\" `a` operation to transform and we store the index of the next `b` operation\n\t// to transform by. Each loop operates on two indexes then: index pointing to currently processed `a` operation and\n\t// index pointing to next `b` operation. Each loop is just one `a * b` + `b * a` transformation. After each loop\n\t// operation `b` index is updated. If all `b` operations were visited for the current `a` operation, we change\n\t// current `a` operation index to the next one.\n\t//\n\n\t// For each operation `a`, keeps information what is the index in `operationsB` from which the transformation should start.\n\tconst nextTransformIndex = new WeakMap();\n\n\t// For all the original `operationsA`, set that they should be transformed starting from the first of `operationsB`.\n\tfor ( const op of operationsA ) {\n\t\tnextTransformIndex.set( op, 0 );\n\t}\n\n\t// Additional data that is used for some postprocessing after the main transformation process is done.\n\tconst data = {\n\t\tnextBaseVersionA: operationsA[ operationsA.length - 1 ].baseVersion + 1,\n\t\tnextBaseVersionB: operationsB[ operationsB.length - 1 ].baseVersion + 1,\n\t\toriginalOperationsACount: operationsA.length,\n\t\toriginalOperationsBCount: operationsB.length\n\t};\n\n\t// Index of currently transformed operation `a`.\n\tlet i = 0;\n\n\t// While not all `operationsA` are transformed...\n\twhile ( i < operationsA.length ) {\n\t\t// Get \"current\" operation `a`.\n\t\tconst opA = operationsA[ i ];\n\n\t\t// For the \"current\" operation `a`, get the index of the next operation `b` to transform by.\n\t\tconst indexB = nextTransformIndex.get( opA );\n\n\t\t// If operation `a` was already transformed by every operation `b`, change \"current\" operation `a` to the next one.\n\t\tif ( indexB == operationsB.length ) {\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst opB = operationsB[ indexB ];\n\n\t\t// Transform `a` by `b` and `b` by `a`.\n\t\tconst newOpsA = transform( opA, opB, contextFactory.getContext( opA, opB, true ) );\n\t\tconst newOpsB = transform( opB, opA, contextFactory.getContext( opB, opA, false ) );\n\t\t// As a result we get one or more `newOpsA` and one or more `newOpsB` operations.\n\n\t\t// Update contextual information about operations.\n\t\tcontextFactory.updateRelation( opA, opB );\n\n\t\tcontextFactory.setOriginalOperations( newOpsA, opA );\n\t\tcontextFactory.setOriginalOperations( newOpsB, opB );\n\n\t\t// For new `a` operations, update their index of the next operation `b` to transform them by.\n\t\t//\n\t\t// This is needed even if there was only one result (`a` was not broken) because that information is used\n\t\t// at the beginning of this loop every time.\n\t\tfor ( const newOpA of newOpsA ) {\n\t\t\t// Acknowledge, that operation `b` also might be broken into multiple operations.\n\t\t\t//\n\t\t\t// This is why we raise `indexB` not just by 1. If `newOpsB` are multiple operations, they will be\n\t\t\t// spliced in the place of `opB`. So we need to change `transformBy` accordingly, so that an operation won't\n\t\t\t// be transformed by the same operation (part of it) again.\n\t\t\tnextTransformIndex.set( newOpA, indexB + newOpsB.length );\n\t\t}\n\n\t\t// Update `operationsA` and `operationsB` with the transformed versions.\n\t\toperationsA.splice( i, 1, ...newOpsA );\n\t\toperationsB.splice( indexB, 1, ...newOpsB );\n\t}\n\n\tif ( options.padWithNoOps ) {\n\t\t// If no-operations padding is enabled, count how many extra `a` and `b` operations were generated.\n\t\tconst brokenOperationsACount = operationsA.length - data.originalOperationsACount;\n\t\tconst brokenOperationsBCount = operationsB.length - data.originalOperationsBCount;\n\n\t\t// Then, if that number is not the same, pad `operationsA` or `operationsB` with correct number of no-ops so\n\t\t// that the base versions are equalled.\n\t\t//\n\t\t// Note that only one array will be updated, as only one of those subtractions can be greater than zero.\n\t\tpadWithNoOps( operationsA, brokenOperationsBCount - brokenOperationsACount );\n\t\tpadWithNoOps( operationsB, brokenOperationsACount - brokenOperationsBCount );\n\t}\n\n\t// Finally, update base versions of transformed operations.\n\tupdateBaseVersions( operationsA, data.nextBaseVersionB );\n\tupdateBaseVersions( operationsB, data.nextBaseVersionA );\n\n\treturn { operationsA, operationsB, originalOperations };\n}\n\n// Gathers additional data about operations processed during transformation. Can be used to obtain contextual information\n// about two operations that are about to be transformed. This contextual information can be used for better conflict resolution.\nclass ContextFactory {\n\t// Creates `ContextFactory` instance.\n\t//\n\t// @param {module:engine/model/document~Document} document Document which the operations change.\n\t// @param {Boolean} useRelations Whether during transformation relations should be used (used during undo for\n\t// better conflict resolution).\n\t// @param {Boolean} [forceWeakRemove=false] If set to `false`, remove operation will be always stronger than move operation,\n\t// so the removed nodes won't end up back in the document root. When set to `true`, context data will be used.\n\tconstructor( document, useRelations, forceWeakRemove = false ) {\n\t\t// For each operation that is created during transformation process, we keep a reference to the original operation\n\t\t// which it comes from. The original operation works as a kind of \"identifier\". Every contextual information\n\t\t// gathered during transformation that we want to save for given operation, is actually saved for the original operation.\n\t\t// This way no matter if operation `a` is cloned, then transformed, even breaks, we still have access to the previously\n\t\t// gathered data through original operation reference.\n\t\tthis.originalOperations = new Map();\n\n\t\t// `model.History` instance which information about undone operations will be taken from.\n\t\tthis._history = document.history;\n\n\t\t// Whether additional context should be used.\n\t\tthis._useRelations = useRelations;\n\n\t\tthis._forceWeakRemove = !!forceWeakRemove;\n\n\t\t// Relations is a double-map structure (maps in map) where for two operations we store how those operations were related\n\t\t// to each other. Those relations are evaluated during transformation process. For every transformated pair of operations\n\t\t// we keep relations between them.\n\t\tthis._relations = new Map();\n\t}\n\n\t// Sets \"original operation\" for given operations.\n\t//\n\t// During transformation process, operations are cloned, then changed, then processed again, sometimes broken into two\n\t// or multiple operations. When gathering additional data it is important that all operations can be somehow linked\n\t// so a cloned and transformed \"version\" still kept track of the data assigned earlier to it.\n\t//\n\t// The original operation object will be used as such an universal linking id. Throughout the transformation process\n\t// all cloned operations will refer to \"the original operation\" when storing and reading additional data.\n\t//\n\t// If `takeFrom` is not set, each operation from `operations` array will be assigned itself as \"the original operation\".\n\t// This should be used as an initialization step.\n\t//\n\t// If `takeFrom` is set, each operation from `operations` will be assigned the same original operation as assigned\n\t// for `takeFrom` operation. This should be used to update original operations. It should be used in a way that\n\t// `operations` are the result of `takeFrom` transformation to ensure proper \"original operation propagation\".\n\t//\n\t// @param {Array.<module:engine/model/operation/operation~Operation>} operations\n\t// @param {module:engine/model/operation/operation~Operation|null} [takeFrom=null]\n\tsetOriginalOperations( operations, takeFrom = null ) {\n\t\tconst originalOperation = takeFrom ? this.originalOperations.get( takeFrom ) : null;\n\n\t\tfor ( const operation of operations ) {\n\t\t\tthis.originalOperations.set( operation, originalOperation || operation );\n\t\t}\n\t}\n\n\t// Saves a relation between operations `opA` and `opB`.\n\t//\n\t// Relations are then later used to help solve conflicts when operations are transformed.\n\t//\n\t// @param {module:engine/model/operation/operation~Operation} opA\n\t// @param {module:engine/model/operation/operation~Operation} opB\n\tupdateRelation( opA, opB ) {\n\t\t// The use of relations is described in a bigger detail in transformation functions.\n\t\t//\n\t\t// In brief, this function, for specified pairs of operation types, checks how positions defined in those operations relate.\n\t\t// Then those relations are saved. For example, for two move operations, it is saved if one of those operations target\n\t\t// position is before the other operation source position. This kind of information gives contextual information when\n\t\t// transformation is used during undo. Similar checks are done for other pairs of operations.\n\t\t//\n\t\tswitch ( opA.constructor ) {\n\t\t\tcase MoveOperation: {\n\t\t\t\tswitch ( opB.constructor ) {\n\t\t\t\t\tcase MergeOperation: {\n\t\t\t\t\t\tif ( opA.targetPosition.isEqual( opB.sourcePosition ) || opB.movedRange.containsPosition( opA.targetPosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'insertAtSource' );\n\t\t\t\t\t\t} else if ( opA.targetPosition.isEqual( opB.deletionPosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'insertBetween' );\n\t\t\t\t\t\t} else if ( opA.targetPosition.isAfter( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'moveTargetAfter' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase MoveOperation: {\n\t\t\t\t\t\tif ( opA.targetPosition.isEqual( opB.sourcePosition ) || opA.targetPosition.isBefore( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'insertBefore' );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'insertAfter' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase SplitOperation: {\n\t\t\t\tswitch ( opB.constructor ) {\n\t\t\t\t\tcase MergeOperation: {\n\t\t\t\t\t\tif ( opA.splitPosition.isBefore( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'splitBefore' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase MoveOperation: {\n\t\t\t\t\t\tif ( opA.splitPosition.isEqual( opB.sourcePosition ) || opA.splitPosition.isBefore( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'splitBefore' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase MergeOperation: {\n\t\t\t\tswitch ( opB.constructor ) {\n\t\t\t\t\tcase MergeOperation: {\n\t\t\t\t\t\tif ( !opA.targetPosition.isEqual( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'mergeTargetNotMoved' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( opA.sourcePosition.isEqual( opB.targetPosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'mergeSourceNotMoved' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( opA.sourcePosition.isEqual( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'mergeSameElement' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase SplitOperation: {\n\t\t\t\t\t\tif ( opA.sourcePosition.isEqual( opB.splitPosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'splitAtSource' );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase MarkerOperation: {\n\t\t\t\tconst markerRange = opA.newRange;\n\n\t\t\t\tif ( !markerRange ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tswitch ( opB.constructor ) {\n\t\t\t\t\tcase MoveOperation: {\n\t\t\t\t\t\tconst movedRange = Range._createFromPositionAndShift( opB.sourcePosition, opB.howMany );\n\n\t\t\t\t\t\tconst affectedLeft = movedRange.containsPosition( markerRange.start ) ||\n\t\t\t\t\t\t\tmovedRange.start.isEqual( markerRange.start );\n\n\t\t\t\t\t\tconst affectedRight = movedRange.containsPosition( markerRange.end ) ||\n\t\t\t\t\t\t\tmovedRange.end.isEqual( markerRange.end );\n\n\t\t\t\t\t\tif ( ( affectedLeft || affectedRight ) && !movedRange.containsRange( markerRange ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, {\n\t\t\t\t\t\t\t\tside: affectedLeft ? 'left' : 'right',\n\t\t\t\t\t\t\t\tpath: affectedLeft ? markerRange.start.path.slice() : markerRange.end.path.slice()\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase MergeOperation: {\n\t\t\t\t\t\tconst wasInLeftElement = markerRange.start.isEqual( opB.targetPosition );\n\t\t\t\t\t\tconst wasStartBeforeMergedElement = markerRange.start.isEqual( opB.deletionPosition );\n\t\t\t\t\t\tconst wasEndBeforeMergedElement = markerRange.end.isEqual( opB.deletionPosition );\n\t\t\t\t\t\tconst wasInRightElement = markerRange.end.isEqual( opB.sourcePosition );\n\n\t\t\t\t\t\tif ( wasInLeftElement || wasStartBeforeMergedElement || wasEndBeforeMergedElement || wasInRightElement ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, {\n\t\t\t\t\t\t\t\twasInLeftElement,\n\t\t\t\t\t\t\t\twasStartBeforeMergedElement,\n\t\t\t\t\t\t\t\twasEndBeforeMergedElement,\n\t\t\t\t\t\t\t\twasInRightElement\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Evaluates and returns contextual information about two given operations `opA` and `opB` which are about to be transformed.\n\t//\n\t// @param {module:engine/model/operation/operation~Operation} opA\n\t// @param {module:engine/model/operation/operation~Operation} opB\n\t// @returns {module:engine/model/operation/transform~TransformationContext}\n\tgetContext( opA, opB, aIsStrong ) {\n\t\treturn {\n\t\t\taIsStrong,\n\t\t\taWasUndone: this._wasUndone( opA ),\n\t\t\tbWasUndone: this._wasUndone( opB ),\n\t\t\tabRelation: this._useRelations ? this._getRelation( opA, opB ) : null,\n\t\t\tbaRelation: this._useRelations ? this._getRelation( opB, opA ) : null,\n\t\t\tforceWeakRemove: this._forceWeakRemove\n\t\t};\n\t}\n\n\t// Returns whether given operation `op` has already been undone.\n\t//\n\t// Information whether an operation was undone gives more context when making a decision when two operations are in conflict.\n\t//\n\t// @param {module:engine/model/operation/operation~Operation} op\n\t// @returns {Boolean}\n\t_wasUndone( op ) {\n\t\t// For `op`, get its original operation. After all, if `op` is a clone (or even transformed clone) of another\n\t\t// operation, literally `op` couldn't be undone. It was just generated. If anything, it was the operation it origins\n\t\t// from which was undone. So get that original operation.\n\t\tconst originalOp = this.originalOperations.get( op );\n\n\t\t// And check with the document if the original operation was undone.\n\t\treturn originalOp.wasUndone || this._history.isUndoneOperation( originalOp );\n\t}\n\n\t// Returns a relation between `opA` and an operation which is undone by `opB`. This can be `String` value if a relation\n\t// was set earlier or `null` if there was no relation between those operations.\n\t//\n\t// This is a little tricky to understand, so let's compare it to `ContextFactory#_wasUndone`.\n\t//\n\t// When `wasUndone( opB )` is used, we check if the `opB` has already been undone. It is obvious, that the\n\t// undoing operation must happen after the undone operation. So, essentially, we have `opB`, we take document history,\n\t// we look forward in the future and ask if in that future `opB` was undone.\n\t//\n\t// Relations is a backward process to `wasUndone()`.\n\t//\n\t// Long story short - using relations is asking what happened in the past. Looking back. This time we have an undoing\n\t// operation `opB` which has undone some other operation. When there is a transformation `opA` x `opB` and there is\n\t// a conflict to solve and `opB` is an undoing operation, we can look back in the history and see what was a relation\n\t// between `opA` and the operation which `opB` undone. Basing on that relation from the past, we can now make\n\t// a better decision when resolving a conflict between two operations, because we know more about the context of\n\t// those two operations.\n\t//\n\t// This is why this function does not return a relation directly between `opA` and `opB` because we need to look\n\t// back to search for a meaningful contextual information.\n\t//\n\t// @param {module:engine/model/operation/operation~Operation} opA\n\t// @param {module:engine/model/operation/operation~Operation} opB\n\t// @returns {String|null}\n\t_getRelation( opA, opB ) {\n\t\t// Get the original operation. Similarly as in `wasUndone()` it is used as an universal identifier for stored data.\n\t\tconst origB = this.originalOperations.get( opB );\n\t\tconst undoneB = this._history.getUndoneOperation( origB );\n\n\t\t// If `opB` is not undoing any operation, there is no relation.\n\t\tif ( !undoneB ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst origA = this.originalOperations.get( opA );\n\t\tconst relationsA = this._relations.get( origA );\n\n\t\t// Get all relations for `opA`, and check if there is a relation with `opB`-undone-counterpart. If so, return it.\n\t\tif ( relationsA ) {\n\t\t\treturn relationsA.get( undoneB ) || null;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t// Helper function for `ContextFactory#updateRelations`.\n\t//\n\t// @private\n\t// @param {module:engine/model/operation/operation~Operation} opA\n\t// @param {module:engine/model/operation/operation~Operation} opB\n\t// @param {String} relation\n\t_setRelation( opA, opB, relation ) {\n\t\t// As always, setting is for original operations, not the clones/transformed operations.\n\t\tconst origA = this.originalOperations.get( opA );\n\t\tconst origB = this.originalOperations.get( opB );\n\n\t\tlet relationsA = this._relations.get( origA );\n\n\t\tif ( !relationsA ) {\n\t\t\trelationsA = new Map();\n\t\t\tthis._relations.set( origA, relationsA );\n\t\t}\n\n\t\trelationsA.set( origB, relation );\n\t}\n}\n\n/**\n * Holds additional contextual information about a transformed pair of operations (`a` and `b`). Those information\n * can be used for better conflict resolving.\n *\n * @typedef {Object} module:engine/model/operation/transform~TransformationContext\n *\n * @property {Boolean} aIsStrong Whether `a` is strong operation in this transformation, or weak.\n * @property {Boolean} aWasUndone Whether `a` operation was undone.\n * @property {Boolean} bWasUndone Whether `b` operation was undone.\n * @property {String|null} abRelation The relation between `a` operation and an operation undone by `b` operation.\n * @property {String|null} baRelation The relation between `b` operation and an operation undone by `a` operation.\n */\n\n/**\n * An utility function that updates {@link module:engine/model/operation/operation~Operation#baseVersion base versions}\n * of passed operations.\n *\n * The function simply sets `baseVersion` as a base version of the first passed operation and then increments it for\n * each following operation in `operations`.\n *\n * @private\n * @param {Array.<module:engine/model/operation/operation~Operation>} operations Operations to update.\n * @param {Number} baseVersion Base version to set for the first operation in `operations`.\n */\nfunction updateBaseVersions( operations, baseVersion ) {\n\tfor ( const operation of operations ) {\n\t\toperation.baseVersion = baseVersion++;\n\t}\n}\n\n/**\n * Adds `howMany` instances of {@link module:engine/model/operation/nooperation~NoOperation} to `operations` set.\n *\n * @private\n * @param {Array.<module:engine/model/operation/operation~Operation>} operations\n * @param {Number} howMany\n */\nfunction padWithNoOps( operations, howMany ) {\n\tfor ( let i = 0; i < howMany; i++ ) {\n\t\toperations.push( new NoOperation( 0 ) );\n\t}\n}\n\n// -----------------------\n\nsetTransformation( AttributeOperation, AttributeOperation, ( a, b, context ) => {\n\t// If operations in conflict, check if their ranges intersect and manage them properly.\n\t//\n\t// Operations can be in conflict only if:\n\t//\n\t// * their key is the same (they change the same attribute), and\n\t// * they are in the same parent (operations for ranges [ 1 ] - [ 3 ] and [ 2, 0 ] - [ 2, 5 ] change different\n\t// elements and can't be in conflict).\n\tif ( a.key === b.key && a.range.start.hasSameParentAs( b.range.start ) ) {\n\t\t// First, we want to apply change to the part of a range that has not been changed by the other operation.\n\t\tconst operations = a.range.getDifference( b.range ).map( range => {\n\t\t\treturn new AttributeOperation( range, a.key, a.oldValue, a.newValue, 0 );\n\t\t} );\n\n\t\t// Then we take care of the common part of ranges.\n\t\tconst common = a.range.getIntersection( b.range );\n\n\t\tif ( common ) {\n\t\t\t// If this operation is more important, we also want to apply change to the part of the\n\t\t\t// original range that has already been changed by the other operation. Since that range\n\t\t\t// got changed we also have to update `oldValue`.\n\t\t\tif ( context.aIsStrong ) {\n\t\t\t\toperations.push( new AttributeOperation( common, b.key, b.newValue, a.newValue, 0 ) );\n\t\t\t}\n\t\t}\n\n\t\tif ( operations.length == 0 ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\n\t\treturn operations;\n\t} else {\n\t\t// If operations don't conflict, simply return an array containing just a clone of this operation.\n\t\treturn [ a ];\n\t}\n} );\n\nsetTransformation( AttributeOperation, InsertOperation, ( a, b ) => {\n\t// Case 1:\n\t//\n\t// The attribute operation range includes the position where nodes were inserted.\n\t// There are two possible scenarios: the inserted nodes were text and they should receive attributes or\n\t// the inserted nodes were elements and they should not receive attributes.\n\t//\n\tif ( a.range.start.hasSameParentAs( b.position ) && a.range.containsPosition( b.position ) ) {\n\t\t// If new nodes should not receive attributes, two separated ranges will be returned.\n\t\t// Otherwise, one expanded range will be returned.\n\t\tconst range = a.range._getTransformedByInsertion( b.position, b.howMany, !b.shouldReceiveAttributes );\n\t\tconst result = range.map( r => {\n\t\t\treturn new AttributeOperation( r, a.key, a.oldValue, a.newValue, a.baseVersion );\n\t\t} );\n\n\t\tif ( b.shouldReceiveAttributes ) {\n\t\t\t// `AttributeOperation#range` includes some newly inserted text.\n\t\t\t// The operation should also change the attribute of that text. An example:\n\t\t\t//\n\t\t\t// Bold should be applied on the following range:\n\t\t\t// <p>Fo[zb]ar</p>\n\t\t\t//\n\t\t\t// In meantime, new text is typed:\n\t\t\t// <p>Fozxxbar</p>\n\t\t\t//\n\t\t\t// Bold should be applied also on the new text:\n\t\t\t// <p>Fo[zxxb]ar</p>\n\t\t\t// <p>Fo<$text bold=\"true\">zxxb</$text>ar</p>\n\t\t\t//\n\t\t\t// There is a special case to consider here to consider.\n\t\t\t//\n\t\t\t// Consider setting an attribute with multiple possible values, for example `highlight`. The inserted text might\n\t\t\t// have already an attribute value applied and the `oldValue` property of the attribute operation might be wrong:\n\t\t\t//\n\t\t\t// Attribute `highlight=\"yellow\"` should be applied on the following range:\n\t\t\t// <p>Fo[zb]ar<p>\n\t\t\t//\n\t\t\t// In meantime, character `x` with `highlight=\"red\"` is typed:\n\t\t\t// <p>Fo[z<$text highlight=\"red\">x</$text>b]ar</p>\n\t\t\t//\n\t\t\t// In this case we cannot simply apply operation changing the attribute value from `null` to `\"yellow\"` for the whole range\n\t\t\t// because that would lead to an exception (`oldValue` is incorrect for `x`).\n\t\t\t//\n\t\t\t// We also cannot break the original range as this would mess up a scenario when there are multiple following\n\t\t\t// insert operations, because then only the first inserted character is included in those ranges:\n\t\t\t// <p>Fo[z][x][b]ar</p>   -->   <p>Fo[z][x]x[b]ar</p>   -->   <p>Fo[z][x]xx[b]ar</p>\n\t\t\t//\n\t\t\t// So, the attribute range needs be expanded, no matter what attributes are set on the inserted nodes:\n\t\t\t//\n\t\t\t// <p>Fo[z<$text highlight=\"red\">x</$text>b]ar</p>      <--- Change from `null` to `yellow`, throwing an exception.\n\t\t\t//\n\t\t\t// But before that operation would be applied, we will add an additional attribute operation that will change\n\t\t\t// attributes on the inserted nodes in a way which would make the original operation correct:\n\t\t\t//\n\t\t\t// <p>Fo[z{<$text highlight=\"red\">}x</$text>b]ar</p>    <--- Change range `{}` from `red` to `null`.\n\t\t\t// <p>Fo[zxb]ar</p>                                     <--- Now change from `null` to `yellow` is completely fine.\n\t\t\t//\n\n\t\t\t// Generate complementary attribute operation. Be sure to add it before the original operation.\n\t\t\tconst op = _getComplementaryAttributeOperations( b, a.key, a.oldValue );\n\n\t\t\tif ( op ) {\n\t\t\t\tresult.unshift( op );\n\t\t\t}\n\t\t}\n\n\t\t// If nodes should not receive new attribute, we are done here.\n\t\treturn result;\n\t}\n\n\t// If insert operation is not expanding the attribute operation range, simply transform the range.\n\ta.range = a.range._getTransformedByInsertion( b.position, b.howMany, false )[ 0 ];\n\n\treturn [ a ];\n} );\n\n/**\n * Helper function for `AttributeOperation` x `InsertOperation` (and reverse) transformation.\n *\n * For given `insertOperation` it checks the inserted node if it has an attribute `key` set to a value different\n * than `newValue`. If so, it generates an `AttributeOperation` which changes the value of `key` attribute to `newValue`.\n *\n * @private\n * @param {module:engine/model/operation/insertoperation~InsertOperation} insertOperation\n * @param {String} key\n * @param {*} newValue\n * @returns {module:engine/model/operation/attributeoperation~AttributeOperation|null}\n */\nfunction _getComplementaryAttributeOperations( insertOperation, key, newValue ) {\n\tconst nodes = insertOperation.nodes;\n\n\t// At the beginning we store the attribute value from the first node.\n\tconst insertValue = nodes.getNode( 0 ).getAttribute( key );\n\n\tif ( insertValue == newValue ) {\n\t\treturn null;\n\t}\n\n\tconst range = new Range( insertOperation.position, insertOperation.position.getShiftedBy( insertOperation.howMany ) );\n\n\treturn new AttributeOperation( range, key, insertValue, newValue, 0 );\n}\n\nsetTransformation( AttributeOperation, MergeOperation, ( a, b ) => {\n\tconst ranges = [];\n\n\t// Case 1:\n\t//\n\t// Attribute change on the merged element. In this case, the merged element was moved to the graveyard.\n\t// An additional attribute operation that will change the (re)moved element needs to be generated.\n\t//\n\tif ( a.range.start.hasSameParentAs( b.deletionPosition ) ) {\n\t\tif ( a.range.containsPosition( b.deletionPosition ) || a.range.start.isEqual( b.deletionPosition ) ) {\n\t\t\tranges.push( Range._createFromPositionAndShift( b.graveyardPosition, 1 ) );\n\t\t}\n\t}\n\n\tconst range = a.range._getTransformedByMergeOperation( b );\n\n\t// Do not add empty (collapsed) ranges to the result. `range` may be collapsed if it contained only the merged element.\n\tif ( !range.isCollapsed ) {\n\t\tranges.push( range );\n\t}\n\n\t// Create `AttributeOperation`s out of the ranges.\n\treturn ranges.map( range => {\n\t\treturn new AttributeOperation( range, a.key, a.oldValue, a.newValue, a.baseVersion );\n\t} );\n} );\n\nsetTransformation( AttributeOperation, MoveOperation, ( a, b ) => {\n\tconst ranges = _breakRangeByMoveOperation( a.range, b );\n\n\t// Create `AttributeOperation`s out of the ranges.\n\treturn ranges.map( range => new AttributeOperation( range, a.key, a.oldValue, a.newValue, a.baseVersion ) );\n} );\n\n// Helper function for `AttributeOperation` x `MoveOperation` transformation.\n//\n// Takes the passed `range` and transforms it by move operation `moveOp` in a specific way. Only top-level nodes of `range`\n// are considered to be in the range. If move operation moves nodes deep from inside of the range, those nodes won't\n// be included in the result. In other words, top-level nodes of the ranges from the result are exactly the same as\n// top-level nodes of the original `range`.\n//\n// This is important for `AttributeOperation` because, for its range, it changes only the top-level nodes. So we need to\n// track only how those nodes have been affected by `MoveOperation`.\n//\n// @private\n// @param {module:engine/model/range~Range} range\n// @param {module:engine/model/operation/moveoperation~MoveOperation} moveOp\n// @returns {Array.<module:engine/model/range~Range>}\nfunction _breakRangeByMoveOperation( range, moveOp ) {\n\tconst moveRange = Range._createFromPositionAndShift( moveOp.sourcePosition, moveOp.howMany );\n\n\t// We are transforming `range` (original range) by `moveRange` (range moved by move operation). As usual when it comes to\n\t// transforming a ranges, we may have a common part of the ranges and we may have a difference part (zero to two ranges).\n\tlet common = null;\n\tlet difference = [];\n\n\t// Let's compare the ranges.\n\tif ( moveRange.containsRange( range, true ) ) {\n\t\t// If the whole original range is moved, treat it whole as a common part. There's also no difference part.\n\t\tcommon = range;\n\t} else if ( range.start.hasSameParentAs( moveRange.start ) ) {\n\t\t// If the ranges are \"on the same level\" (in the same parent) then move operation may move exactly those nodes\n\t\t// that are changed by the attribute operation. In this case we get common part and difference part in the usual way.\n\t\tdifference = range.getDifference( moveRange );\n\t\tcommon = range.getIntersection( moveRange );\n\t} else {\n\t\t// In any other situation we assume that original range is different than move range, that is that move operation\n\t\t// moves other nodes that attribute operation change. Even if the moved range is deep inside in the original range.\n\t\t//\n\t\t// Note that this is different than in `.getIntersection` (we would get a common part in that case) and different\n\t\t// than `.getDifference` (we would get two ranges).\n\t\tdifference = [ range ];\n\t}\n\n\tconst result = [];\n\n\t// The default behaviour of `_getTransformedByMove` might get wrong results for difference part, though, so\n\t// we do it by hand.\n\tfor ( let diff of difference ) {\n\t\t// First, transform the range by removing moved nodes. Since this is a difference, this is safe, `null` won't be returned\n\t\t// as the range is different than the moved range.\n\t\tdiff = diff._getTransformedByDeletion( moveOp.sourcePosition, moveOp.howMany );\n\n\t\t// Transform also `targetPosition`.\n\t\tconst targetPosition = moveOp.getMovedRangeStart();\n\n\t\t// Spread the range only if moved nodes are inserted only between the top-level nodes of the `diff` range.\n\t\tconst spread = diff.start.hasSameParentAs( targetPosition );\n\n\t\t// Transform by insertion of moved nodes.\n\t\tdiff = diff._getTransformedByInsertion( targetPosition, moveOp.howMany, spread );\n\n\t\tresult.push( ...diff );\n\t}\n\n\t// Common part can be simply transformed by the move operation. This is because move operation will not target to\n\t// that common part (the operation would have to target inside its own moved range).\n\tif ( common ) {\n\t\tresult.push(\n\t\t\tcommon._getTransformedByMove( moveOp.sourcePosition, moveOp.targetPosition, moveOp.howMany, false )[ 0 ]\n\t\t);\n\t}\n\n\treturn result;\n}\n\nsetTransformation( AttributeOperation, SplitOperation, ( a, b ) => {\n\t// Case 1:\n\t//\n\t// Split node is the last node in `AttributeOperation#range`.\n\t// `AttributeOperation#range` needs to be expanded to include the new (split) node.\n\t//\n\t// Attribute `type` to be changed to `numbered` but the `listItem` is split.\n\t// <listItem type=\"bulleted\">foobar</listItem>\n\t//\n\t// After split:\n\t// <listItem type=\"bulleted\">foo</listItem><listItem type=\"bulleted\">bar</listItem>\n\t//\n\t// After attribute change:\n\t// <listItem type=\"numbered\">foo</listItem><listItem type=\"numbered\">foo</listItem>\n\t//\n\tif ( a.range.end.isEqual( b.insertionPosition ) ) {\n\t\tif ( !b.graveyardPosition ) {\n\t\t\ta.range.end.offset++;\n\t\t}\n\n\t\treturn [ a ];\n\t}\n\n\t// Case 2:\n\t//\n\t// Split position is inside `AttributeOperation#range`, at the same level, so the nodes to change are\n\t// not going to make a flat range.\n\t//\n\t// Content with range-to-change and split position:\n\t// <p>Fo[zb^a]r</p>\n\t//\n\t// After split:\n\t// <p>Fozb</p><p>ar</p>\n\t//\n\t// Make two separate ranges containing all nodes to change:\n\t// <p>Fo[zb]</p><p>[a]r</p>\n\t//\n\tif ( a.range.start.hasSameParentAs( b.splitPosition ) && a.range.containsPosition( b.splitPosition ) ) {\n\t\tconst secondPart = a.clone();\n\n\t\tsecondPart.range = new Range(\n\t\t\tb.moveTargetPosition.clone(),\n\t\t\ta.range.end._getCombined( b.splitPosition, b.moveTargetPosition )\n\t\t);\n\n\t\ta.range.end = b.splitPosition.clone();\n\t\ta.range.end.stickiness = 'toPrevious';\n\n\t\treturn [ a, secondPart ];\n\t}\n\n\t// The default case.\n\t//\n\ta.range = a.range._getTransformedBySplitOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( InsertOperation, AttributeOperation, ( a, b ) => {\n\tconst result = [ a ];\n\n\t// Case 1:\n\t//\n\t// The attribute operation range includes the position where nodes were inserted.\n\t// There are two possible scenarios: the inserted nodes were text and they should receive attributes or\n\t// the inserted nodes were elements and they should not receive attributes.\n\t//\n\t// This is a mirror scenario to the one described in `AttributeOperation` x `InsertOperation` transformation,\n\t// although this case is a little less complicated. In this case we simply need to change attributes of the\n\t// inserted nodes and that's it.\n\t//\n\tif ( a.shouldReceiveAttributes && a.position.hasSameParentAs( b.range.start ) && b.range.containsPosition( a.position ) ) {\n\t\tconst op = _getComplementaryAttributeOperations( a, b.key, b.newValue );\n\n\t\tif ( op ) {\n\t\t\tresult.push( op );\n\t\t}\n\t}\n\n\t// The default case is: do nothing.\n\t// `AttributeOperation` does not change the model tree structure so `InsertOperation` does not need to be changed.\n\t//\n\treturn result;\n} );\n\nsetTransformation( InsertOperation, InsertOperation, ( a, b, context ) => {\n\t// Case 1:\n\t//\n\t// Two insert operations insert nodes at the same position. Since they are the same, it needs to be decided\n\t// what will be the order of inserted nodes. However, there is no additional information to help in that\n\t// decision. Also, when `b` will be transformed by `a`, the same order must be maintained.\n\t//\n\t// To achieve that, we will check if the operation is strong.\n\t// If it is, it won't get transformed. If it is not, it will be moved.\n\t//\n\tif ( a.position.isEqual( b.position ) && context.aIsStrong ) {\n\t\treturn [ a ];\n\t}\n\n\t// The default case.\n\t//\n\ta.position = a.position._getTransformedByInsertOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( InsertOperation, MoveOperation, ( a, b ) => {\n\t// The default case.\n\t//\n\ta.position = a.position._getTransformedByMoveOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( InsertOperation, SplitOperation, ( a, b ) => {\n\t// The default case.\n\t//\n\ta.position = a.position._getTransformedBySplitOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( InsertOperation, MergeOperation, ( a, b ) => {\n\ta.position = a.position._getTransformedByMergeOperation( b );\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( MarkerOperation, InsertOperation, ( a, b ) => {\n\tif ( a.oldRange ) {\n\t\ta.oldRange = a.oldRange._getTransformedByInsertOperation( b )[ 0 ];\n\t}\n\n\tif ( a.newRange ) {\n\t\ta.newRange = a.newRange._getTransformedByInsertOperation( b )[ 0 ];\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MarkerOperation, MarkerOperation, ( a, b, context ) => {\n\tif ( a.name == b.name ) {\n\t\tif ( context.aIsStrong ) {\n\t\t\ta.oldRange = b.newRange ? b.newRange.clone() : null;\n\t\t} else {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MarkerOperation, MergeOperation, ( a, b ) => {\n\tif ( a.oldRange ) {\n\t\ta.oldRange = a.oldRange._getTransformedByMergeOperation( b );\n\t}\n\n\tif ( a.newRange ) {\n\t\ta.newRange = a.newRange._getTransformedByMergeOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MarkerOperation, MoveOperation, ( a, b, context ) => {\n\tif ( a.oldRange ) {\n\t\ta.oldRange = Range._createFromRanges( a.oldRange._getTransformedByMoveOperation( b ) );\n\t}\n\n\tif ( a.newRange ) {\n\t\tif ( context.abRelation ) {\n\t\t\tconst aNewRange = Range._createFromRanges( a.newRange._getTransformedByMoveOperation( b ) );\n\n\t\t\tif ( context.abRelation.side == 'left' && b.targetPosition.isEqual( a.newRange.start ) ) {\n\t\t\t\ta.newRange.start.path = context.abRelation.path;\n\t\t\t\ta.newRange.end = aNewRange.end;\n\n\t\t\t\treturn [ a ];\n\t\t\t} else if ( context.abRelation.side == 'right' && b.targetPosition.isEqual( a.newRange.end ) ) {\n\t\t\t\ta.newRange.start = aNewRange.start;\n\t\t\t\ta.newRange.end.path = context.abRelation.path;\n\n\t\t\t\treturn [ a ];\n\t\t\t}\n\t\t}\n\n\t\ta.newRange = Range._createFromRanges( a.newRange._getTransformedByMoveOperation( b ) );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MarkerOperation, SplitOperation, ( a, b, context ) => {\n\tif ( a.oldRange ) {\n\t\ta.oldRange = a.oldRange._getTransformedBySplitOperation( b );\n\t}\n\n\tif ( a.newRange ) {\n\t\tif ( context.abRelation ) {\n\t\t\tconst aNewRange = a.newRange._getTransformedBySplitOperation( b );\n\n\t\t\tif ( a.newRange.start.isEqual( b.splitPosition ) && context.abRelation.wasStartBeforeMergedElement ) {\n\t\t\t\ta.newRange.start = Position._createAt( b.insertionPosition );\n\t\t\t} else if ( a.newRange.start.isEqual( b.splitPosition ) && !context.abRelation.wasInLeftElement ) {\n\t\t\t\ta.newRange.start = Position._createAt( b.moveTargetPosition );\n\t\t\t}\n\n\t\t\tif ( a.newRange.end.isEqual( b.splitPosition ) && context.abRelation.wasInRightElement ) {\n\t\t\t\ta.newRange.end = Position._createAt( b.moveTargetPosition );\n\t\t\t} else if ( a.newRange.end.isEqual( b.splitPosition ) && context.abRelation.wasEndBeforeMergedElement ) {\n\t\t\t\ta.newRange.end = Position._createAt( b.insertionPosition );\n\t\t\t} else {\n\t\t\t\ta.newRange.end = aNewRange.end;\n\t\t\t}\n\n\t\t\treturn [ a ];\n\t\t}\n\n\t\ta.newRange = a.newRange._getTransformedBySplitOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( MergeOperation, InsertOperation, ( a, b ) => {\n\tif ( a.sourcePosition.hasSameParentAs( b.position ) ) {\n\t\ta.howMany += b.howMany;\n\t}\n\n\ta.sourcePosition = a.sourcePosition._getTransformedByInsertOperation( b );\n\ta.targetPosition = a.targetPosition._getTransformedByInsertOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( MergeOperation, MergeOperation, ( a, b, context ) => {\n\t// Case 1:\n\t//\n\t// Same merge operations.\n\t//\n\t// Both operations have same source and target positions. So the element already got merged and there is\n\t// theoretically nothing to do.\n\t//\n\tif ( a.sourcePosition.isEqual( b.sourcePosition ) && a.targetPosition.isEqual( b.targetPosition ) ) {\n\t\t// There are two ways that we can provide a do-nothing operation.\n\t\t//\n\t\t// First is simply a NoOperation instance. We will use it if `b` operation was not undone.\n\t\t//\n\t\t// Second is a merge operation that has the source operation in the merged element - in the graveyard -\n\t\t// same target position and `howMany` equal to `0`. So it is basically merging an empty element from graveyard\n\t\t// which is almost the same as NoOperation.\n\t\t//\n\t\t// This way the merge operation can be later transformed by split operation\n\t\t// to provide correct undo. This will be used if `b` operation was undone (only then it is correct).\n\t\t//\n\t\tif ( !context.bWasUndone ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t} else {\n\t\t\tconst path = b.graveyardPosition.path.slice();\n\t\t\tpath.push( 0 );\n\n\t\t\ta.sourcePosition = new Position( b.graveyardPosition.root, path );\n\t\t\ta.howMany = 0;\n\n\t\t\treturn [ a ];\n\t\t}\n\t}\n\n\t// Case 2:\n\t//\n\t// Same merge source position but different target position.\n\t//\n\t// This can happen during collaboration. For example, if one client merged a paragraph to the previous paragraph\n\t// and the other person removed that paragraph and merged the same paragraph to something before:\n\t//\n\t// Client A:\n\t// <p>Foo</p><p>Bar</p><p>[]Xyz</p>\n\t// <p>Foo</p><p>BarXyz</p>\n\t//\n\t// Client B:\n\t// <p>Foo</p>[<p>Bar</p>]<p>Xyz</p>\n\t// <p>Foo</p><p>[]Xyz</p>\n\t// <p>FooXyz</p>\n\t//\n\t// In this case we need to decide where finally \"Xyz\" will land:\n\t//\n\t// <p>FooXyz</p>               graveyard: <p>Bar</p>\n\t// <p>Foo</p>                  graveyard: <p>BarXyz</p>\n\t//\n\t// Let's move it in a way so that a merge operation that does not target to graveyard is more important so that\n\t// nodes does not end up in the graveyard. It makes sense. Both for Client A and for Client B \"Xyz\" finally did not\n\t// end up in the graveyard (see above).\n\t//\n\t// If neither or both operations point to graveyard, then let `aIsStrong` decide.\n\t//\n\tif (\n\t\ta.sourcePosition.isEqual( b.sourcePosition ) && !a.targetPosition.isEqual( b.targetPosition ) &&\n\t\t!context.bWasUndone && context.abRelation != 'splitAtSource'\n\t) {\n\t\tconst aToGraveyard = a.targetPosition.root.rootName == '$graveyard';\n\t\tconst bToGraveyard = b.targetPosition.root.rootName == '$graveyard';\n\n\t\t// If `aIsWeak` it means that `a` points to graveyard while `b` doesn't. Don't move nodes then.\n\t\tconst aIsWeak = aToGraveyard && !bToGraveyard;\n\n\t\t// If `bIsWeak` it means that `b` points to graveyard while `a` doesn't. Force moving nodes then.\n\t\tconst bIsWeak = bToGraveyard && !aToGraveyard;\n\n\t\t// Force move if `b` is weak or neither operation is weak but `a` is stronger through `context.aIsStrong`.\n\t\tconst forceMove = bIsWeak || ( !aIsWeak && context.aIsStrong );\n\n\t\tif ( forceMove ) {\n\t\t\tconst sourcePosition = b.targetPosition._getTransformedByMergeOperation( b );\n\t\t\tconst targetPosition = a.targetPosition._getTransformedByMergeOperation( b );\n\n\t\t\treturn [ new MoveOperation( sourcePosition, a.howMany, targetPosition, 0 ) ];\n\t\t} else {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\t}\n\n\t// The default case.\n\t//\n\tif ( a.sourcePosition.hasSameParentAs( b.targetPosition ) ) {\n\t\ta.howMany += b.howMany;\n\t}\n\n\ta.sourcePosition = a.sourcePosition._getTransformedByMergeOperation( b );\n\ta.targetPosition = a.targetPosition._getTransformedByMergeOperation( b );\n\n\t// Handle positions in graveyard.\n\t// If graveyard positions are same and `a` operation is strong - do not transform.\n\tif ( !a.graveyardPosition.isEqual( b.graveyardPosition ) || !context.aIsStrong ) {\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedByMergeOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MergeOperation, MoveOperation, ( a, b, context ) => {\n\t// Case 1:\n\t//\n\t// The element to merge got removed.\n\t//\n\t// Merge operation does support merging elements which are not siblings. So it would not be a problem\n\t// from technical point of view. However, if the element was removed, the intention of the user deleting it\n\t// was to have it all deleted, together with its children. From user experience point of view, moving back the\n\t// removed nodes might be unexpected. This means that in this scenario we will block the merging.\n\t//\n\t// The exception of this rule would be if the remove operation was later undone.\n\t//\n\tconst removedRange = Range._createFromPositionAndShift( b.sourcePosition, b.howMany );\n\n\tif ( b.type == 'remove' && !context.bWasUndone && !context.forceWeakRemove ) {\n\t\tif ( a.deletionPosition.hasSameParentAs( b.sourcePosition ) && removedRange.containsPosition( a.sourcePosition ) ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\t}\n\n\t// The default case.\n\t//\n\tif ( a.sourcePosition.hasSameParentAs( b.targetPosition ) ) {\n\t\ta.howMany += b.howMany;\n\t}\n\n\tif ( a.sourcePosition.hasSameParentAs( b.sourcePosition ) ) {\n\t\ta.howMany -= b.howMany;\n\t}\n\n\ta.sourcePosition = a.sourcePosition._getTransformedByMoveOperation( b );\n\ta.targetPosition = a.targetPosition._getTransformedByMoveOperation( b );\n\n\t// `MergeOperation` graveyard position is like `MoveOperation` target position. It is a position where element(s) will\n\t// be moved. Like in other similar cases, we need to consider the scenario when those positions are same.\n\t// Here, we will treat `MergeOperation` like it is always strong (see `InsertOperation` x `InsertOperation` for comparison).\n\t// This means that we won't transform graveyard position if it is equal to move operation target position.\n\tif ( !a.graveyardPosition.isEqual( b.targetPosition ) ) {\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedByMoveOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MergeOperation, SplitOperation, ( a, b, context ) => {\n\tif ( b.graveyardPosition ) {\n\t\t// If `b` operation defines graveyard position, a node from graveyard will be moved. This means that we need to\n\t\t// transform `a.graveyardPosition` accordingly.\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedByDeletion( b.graveyardPosition, 1 );\n\n\t\t// This is a scenario foreseen in `MergeOperation` x `MergeOperation`, with two identical merge operations.\n\t\t//\n\t\t// So, there was `MergeOperation` x `MergeOperation` transformation earlier. Now, `a` is a merge operation which\n\t\t// source position is in graveyard. Interestingly, split operation wants to use the node to be merged by `a`. This\n\t\t// means that `b` is undoing that merge operation from earlier, which caused `a` to be in graveyard.\n\t\t//\n\t\t// If that's the case, at this point, we will only \"fix\" `a.howMany`. It was earlier set to `0` in\n\t\t// `MergeOperation` x `MergeOperation` transformation. Later transformations in this function will change other\n\t\t// properties.\n\t\t//\n\t\tif ( a.deletionPosition.isEqual( b.graveyardPosition ) ) {\n\t\t\ta.howMany = b.howMany;\n\t\t}\n\t}\n\n\t// Case 1:\n\t//\n\t// Merge operation moves nodes to the place where split happens.\n\t// This is a classic situation when there are two paragraphs, and there is a split (enter) after the first\n\t// paragraph and there is a merge (delete) at the beginning of the second paragraph:\n\t//\n\t// <p>Foo{}</p><p>[]Bar</p>.\n\t//\n\t// Split is after `Foo`, while merge is from `Bar` to the end of `Foo`.\n\t//\n\t// State after split:\n\t// <p>Foo</p><p></p><p>Bar</p>\n\t//\n\t// Now, `Bar` should be merged to the new paragraph:\n\t// <p>Foo</p><p>Bar</p>\n\t//\n\t// Instead of merging it to the original paragraph:\n\t// <p>FooBar</p><p></p>\n\t//\n\t// This means that `targetPosition` needs to be transformed. This is the default case though.\n\t// For example, if the split would be after `F`, `targetPosition` should also be transformed.\n\t//\n\t// There are three exceptions, though, when we want to keep `targetPosition` as it was.\n\t//\n\t// First exception is when the merge target position is inside an element (not at the end, as usual). This\n\t// happens when the merge operation earlier was transformed by \"the same\" merge operation. If merge operation\n\t// targets inside the element we want to keep the original target position (and not transform it) because\n\t// we have additional context telling us that we want to merge to the original element. We can check if the\n\t// merge operation points inside element by checking what is `SplitOperation#howMany`. Since merge target position\n\t// is same as split position, if `howMany` is non-zero, it means that the merge target position is inside an element.\n\t//\n\t// Second exception is when the element to merge is in the graveyard and split operation uses it. In that case\n\t// if target position would be transformed, the merge operation would target at the source position:\n\t//\n\t// root: <p>Foo</p>\t\t\t\tgraveyard: <p></p>\n\t//\n\t// SplitOperation: root [ 0, 3 ] using graveyard [ 0 ] (howMany = 0)\n\t// MergeOperation: graveyard [ 0, 0 ] -> root [ 0, 3 ] (howMany = 0)\n\t//\n\t// Since split operation moves the graveyard node back to the root, the merge operation source position changes.\n\t// We would like to merge from the empty <p> to the \"Foo\" <p>:\n\t//\n\t// root: <p>Foo</p><p></p>\t\t\tgraveyard:\n\t//\n\t// MergeOperation#sourcePosition = root [ 1, 0 ]\n\t//\n\t// If `targetPosition` is transformed, it would become root [ 1, 0 ] as well. It has to be kept as it was.\n\t//\n\t// Third exception is connected with relations. If this happens during undo and we have explicit information\n\t// that target position has not been affected by the operation which is undone by this split then this split should\n\t// not move the target position either.\n\t//\n\tif ( a.targetPosition.isEqual( b.splitPosition ) ) {\n\t\tconst mergeInside = b.howMany != 0;\n\t\tconst mergeSplittingElement = b.graveyardPosition && a.deletionPosition.isEqual( b.graveyardPosition );\n\n\t\tif ( mergeInside || mergeSplittingElement || context.abRelation == 'mergeTargetNotMoved' ) {\n\t\t\ta.sourcePosition = a.sourcePosition._getTransformedBySplitOperation( b );\n\n\t\t\treturn [ a ];\n\t\t}\n\t}\n\n\t// Case 2:\n\t//\n\t// Merge source is at the same position as split position. This sometimes happen, mostly during undo.\n\t// The decision here is mostly to choose whether merge source position should stay where it is (so it will be at the end of the\n\t// split element) or should be move to the beginning of the new element.\n\t//\n\tif ( a.sourcePosition.isEqual( b.splitPosition ) ) {\n\t\t// Use context to check if `SplitOperation` is not undoing a merge operation, that didn't change the `a` operation.\n\t\t// This scenario happens the undone merge operation moved nodes at the source position of `a` operation.\n\t\t// In that case `a` operation source position should stay where it is.\n\t\tif ( context.abRelation == 'mergeSourceNotMoved' ) {\n\t\t\ta.howMany = 0;\n\t\t\ta.targetPosition = a.targetPosition._getTransformedBySplitOperation( b );\n\n\t\t\treturn [ a ];\n\t\t}\n\n\t\t// This merge operation might have been earlier transformed by a merge operation which both merged the same element.\n\t\t// See that case in `MergeOperation` x `MergeOperation` transformation. In that scenario, if the merge operation has been undone,\n\t\t// the special case is not applied.\n\t\t//\n\t\t// Now, the merge operation is transformed by the split which has undone that previous merge operation.\n\t\t// So now we are fixing situation which was skipped in `MergeOperation` x `MergeOperation` case.\n\t\t//\n\t\tif ( context.abRelation == 'mergeSameElement' || a.sourcePosition.offset > 0 ) {\n\t\t\ta.sourcePosition = b.moveTargetPosition.clone();\n\t\t\ta.targetPosition = a.targetPosition._getTransformedBySplitOperation( b );\n\n\t\t\treturn [ a ];\n\t\t}\n\t}\n\n\t// The default case.\n\t//\n\tif ( a.sourcePosition.hasSameParentAs( b.splitPosition ) ) {\n\t\ta.howMany = b.splitPosition.offset;\n\t}\n\n\ta.sourcePosition = a.sourcePosition._getTransformedBySplitOperation( b );\n\ta.targetPosition = a.targetPosition._getTransformedBySplitOperation( b );\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( MoveOperation, InsertOperation, ( a, b ) => {\n\tconst moveRange = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );\n\tconst transformed = moveRange._getTransformedByInsertOperation( b, false )[ 0 ];\n\n\ta.sourcePosition = transformed.start;\n\ta.howMany = transformed.end.offset - transformed.start.offset;\n\n\t// See `InsertOperation` x `MoveOperation` transformation for details on this case.\n\t//\n\t// In summary, both operations point to the same place, so the order of nodes needs to be decided.\n\t// `MoveOperation` is considered weaker, so it is always transformed, unless there was a certain relation\n\t// between operations.\n\t//\n\tif ( !a.targetPosition.isEqual( b.position ) ) {\n\t\ta.targetPosition = a.targetPosition._getTransformedByInsertOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MoveOperation, MoveOperation, ( a, b, context ) => {\n\t//\n\t// Setting and evaluating some variables that will be used in special cases and default algorithm.\n\t//\n\t// Create ranges from `MoveOperations` properties.\n\tconst rangeA = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );\n\tconst rangeB = Range._createFromPositionAndShift( b.sourcePosition, b.howMany );\n\n\t// Assign `context.aIsStrong` to a different variable, because the value may change during execution of\n\t// this algorithm and we do not want to override original `context.aIsStrong` that will be used in later transformations.\n\tlet aIsStrong = context.aIsStrong;\n\n\t// This will be used to decide the order of nodes if both operations target at the same position.\n\t// By default, use strong/weak operation mechanism.\n\tlet insertBefore = !context.aIsStrong;\n\n\t// If the relation is set, then use it to decide nodes order.\n\tif ( context.abRelation == 'insertBefore' || context.baRelation == 'insertAfter' ) {\n\t\tinsertBefore = true;\n\t} else if ( context.abRelation == 'insertAfter' || context.baRelation == 'insertBefore' ) {\n\t\tinsertBefore = false;\n\t}\n\n\t// `a.targetPosition` could be affected by the `b` operation. We will transform it.\n\tlet newTargetPosition;\n\n\tif ( a.targetPosition.isEqual( b.targetPosition ) && insertBefore ) {\n\t\tnewTargetPosition = a.targetPosition._getTransformedByDeletion(\n\t\t\tb.sourcePosition,\n\t\t\tb.howMany\n\t\t);\n\t} else {\n\t\tnewTargetPosition = a.targetPosition._getTransformedByMove(\n\t\t\tb.sourcePosition,\n\t\t\tb.targetPosition,\n\t\t\tb.howMany\n\t\t);\n\t}\n\n\t//\n\t// Special case #1 + mirror.\n\t//\n\t// Special case when both move operations' target positions are inside nodes that are\n\t// being moved by the other move operation. So in other words, we move ranges into inside of each other.\n\t// This case can't be solved reasonably (on the other hand, it should not happen often).\n\tif ( _moveTargetIntoMovedRange( a, b ) && _moveTargetIntoMovedRange( b, a ) ) {\n\t\t// Instead of transforming operation, we return a reverse of the operation that we transform by.\n\t\t// So when the results of this \"transformation\" will be applied, `b` MoveOperation will get reversed.\n\t\treturn [ b.getReversed() ];\n\t}\n\t//\n\t// End of special case #1.\n\t//\n\n\t//\n\t// Special case #2.\n\t//\n\t// Check if `b` operation targets inside `rangeA`.\n\tconst bTargetsToA = rangeA.containsPosition( b.targetPosition );\n\n\t// If `b` targets to `rangeA` and `rangeA` contains `rangeB`, `b` operation has no influence on `a` operation.\n\t// You might say that operation `b` is captured inside operation `a`.\n\tif ( bTargetsToA && rangeA.containsRange( rangeB, true ) ) {\n\t\t// There is a mini-special case here, where `rangeB` is on other level than `rangeA`. That's why\n\t\t// we need to transform `a` operation anyway.\n\t\trangeA.start = rangeA.start._getTransformedByMove( b.sourcePosition, b.targetPosition, b.howMany );\n\t\trangeA.end = rangeA.end._getTransformedByMove( b.sourcePosition, b.targetPosition, b.howMany );\n\n\t\treturn _makeMoveOperationsFromRanges( [ rangeA ], newTargetPosition );\n\t}\n\n\t//\n\t// Special case #2 mirror.\n\t//\n\tconst aTargetsToB = rangeB.containsPosition( a.targetPosition );\n\n\tif ( aTargetsToB && rangeB.containsRange( rangeA, true ) ) {\n\t\t// `a` operation is \"moved together\" with `b` operation.\n\t\t// Here, just move `rangeA` \"inside\" `rangeB`.\n\t\trangeA.start = rangeA.start._getCombined( b.sourcePosition, b.getMovedRangeStart() );\n\t\trangeA.end = rangeA.end._getCombined( b.sourcePosition, b.getMovedRangeStart() );\n\n\t\treturn _makeMoveOperationsFromRanges( [ rangeA ], newTargetPosition );\n\t}\n\t//\n\t// End of special case #2.\n\t//\n\n\t//\n\t// Special case #3 + mirror.\n\t//\n\t// `rangeA` has a node which is an ancestor of `rangeB`. In other words, `rangeB` is inside `rangeA`\n\t// but not on the same tree level. In such case ranges have common part but we have to treat it\n\t// differently, because in such case those ranges are not really conflicting and should be treated like\n\t// two separate ranges. Also we have to discard two difference parts.\n\tconst aCompB = compareArrays( a.sourcePosition.getParentPath(), b.sourcePosition.getParentPath() );\n\n\tif ( aCompB == 'prefix' || aCompB == 'extension' ) {\n\t\t// Transform `rangeA` by `b` operation and make operation out of it, and that's all.\n\t\t// Note that this is a simplified version of default case, but here we treat the common part (whole `rangeA`)\n\t\t// like a one difference part.\n\t\trangeA.start = rangeA.start._getTransformedByMove( b.sourcePosition, b.targetPosition, b.howMany );\n\t\trangeA.end = rangeA.end._getTransformedByMove( b.sourcePosition, b.targetPosition, b.howMany );\n\n\t\treturn _makeMoveOperationsFromRanges( [ rangeA ], newTargetPosition );\n\t}\n\t//\n\t// End of special case #3.\n\t//\n\n\t//\n\t// Default case - ranges are on the same level or are not connected with each other.\n\t//\n\t// Modifier for default case.\n\t// Modifies `aIsStrong` flag in certain conditions.\n\t//\n\t// If only one of operations is a remove operation, we force remove operation to be the \"stronger\" one\n\t// to provide more expected results.\n\tif ( a.type == 'remove' && b.type != 'remove' && !context.aWasUndone && !context.forceWeakRemove ) {\n\t\taIsStrong = true;\n\t} else if ( a.type != 'remove' && b.type == 'remove' && !context.bWasUndone && !context.forceWeakRemove ) {\n\t\taIsStrong = false;\n\t}\n\n\t// Handle operation's source ranges - check how `rangeA` is affected by `b` operation.\n\t// This will aggregate transformed ranges.\n\tconst ranges = [];\n\n\t// Get the \"difference part\" of `a` operation source range.\n\t// This is an array with one or two ranges. Two ranges if `rangeB` is inside `rangeA`.\n\tconst difference = rangeA.getDifference( rangeB );\n\n\tfor ( const range of difference ) {\n\t\t// Transform those ranges by `b` operation. For example if `b` moved range from before those ranges, fix those ranges.\n\t\trange.start = range.start._getTransformedByDeletion( b.sourcePosition, b.howMany );\n\t\trange.end = range.end._getTransformedByDeletion( b.sourcePosition, b.howMany );\n\n\t\t// If `b` operation targets into `rangeA` on the same level, spread `rangeA` into two ranges.\n\t\tconst shouldSpread = compareArrays( range.start.getParentPath(), b.getMovedRangeStart().getParentPath() ) == 'same';\n\t\tconst newRanges = range._getTransformedByInsertion( b.getMovedRangeStart(), b.howMany, shouldSpread );\n\n\t\tranges.push( ...newRanges );\n\t}\n\n\t// Then, we have to manage the \"common part\" of both move ranges.\n\tconst common = rangeA.getIntersection( rangeB );\n\n\tif ( common !== null && aIsStrong ) {\n\t\t// Calculate the new position of that part of original range.\n\t\tcommon.start = common.start._getCombined( b.sourcePosition, b.getMovedRangeStart() );\n\t\tcommon.end = common.end._getCombined( b.sourcePosition, b.getMovedRangeStart() );\n\n\t\t// Take care of proper range order.\n\t\t//\n\t\t// Put `common` at appropriate place. Keep in mind that we are interested in original order.\n\t\t// Basically there are only three cases: there is zero, one or two difference ranges.\n\t\t//\n\t\t// If there is zero difference ranges, just push `common` in the array.\n\t\tif ( ranges.length === 0 ) {\n\t\t\tranges.push( common );\n\t\t}\n\t\t// If there is one difference range, we need to check whether common part was before it or after it.\n\t\telse if ( ranges.length == 1 ) {\n\t\t\tif ( rangeB.start.isBefore( rangeA.start ) || rangeB.start.isEqual( rangeA.start ) ) {\n\t\t\t\tranges.unshift( common );\n\t\t\t} else {\n\t\t\t\tranges.push( common );\n\t\t\t}\n\t\t}\n\t\t// If there are more ranges (which means two), put common part between them. This is the only scenario\n\t\t// where there could be two difference ranges so we don't have to make any comparisons.\n\t\telse {\n\t\t\tranges.splice( 1, 0, common );\n\t\t}\n\t}\n\n\tif ( ranges.length === 0 ) {\n\t\t// If there are no \"source ranges\", nothing should be changed.\n\t\t// Note that this can happen only if `aIsStrong == false` and `rangeA.isEqual( rangeB )`.\n\t\treturn [ new NoOperation( a.baseVersion ) ];\n\t}\n\n\treturn _makeMoveOperationsFromRanges( ranges, newTargetPosition );\n} );\n\nsetTransformation( MoveOperation, SplitOperation, ( a, b, context ) => {\n\tlet newTargetPosition = a.targetPosition.clone();\n\n\t// Do not transform if target position is same as split insertion position and this split comes from undo.\n\t// This should be done on relations but it is too much work for now as it would require relations working in collaboration.\n\t// We need to make a decision how we will resolve such conflict and this is less harmful way.\n\tif ( !a.targetPosition.isEqual( b.insertionPosition ) || !b.graveyardPosition || context.abRelation == 'moveTargetAfter' ) {\n\t\tnewTargetPosition = a.targetPosition._getTransformedBySplitOperation( b );\n\t}\n\n\t// Case 1:\n\t//\n\t// Last element in the moved range got split.\n\t//\n\t// In this case the default range transformation will not work correctly as the element created by\n\t// split operation would be outside the range. The range to move needs to be fixed manually.\n\t//\n\tconst moveRange = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );\n\n\tif ( moveRange.end.isEqual( b.insertionPosition ) ) {\n\t\t// Do it only if this is a \"natural\" split, not a one that comes from undo.\n\t\t// If this is undo split, only `targetPosition` needs to be changed (if the move is a remove).\n\t\tif ( !b.graveyardPosition ) {\n\t\t\ta.howMany++;\n\t\t}\n\n\t\ta.targetPosition = newTargetPosition;\n\n\t\treturn [ a ];\n\t}\n\n\t// Case 2:\n\t//\n\t// Split happened between the moved nodes. In this case two ranges to move need to be generated.\n\t//\n\t// Characters `ozba` are moved to the end of paragraph `Xyz` but split happened.\n\t// <p>F[oz|ba]r</p><p>Xyz</p>\n\t//\n\t// After split:\n\t// <p>F[oz</p><p>ba]r</p><p>Xyz</p>\n\t//\n\t// Correct ranges:\n\t// <p>F[oz]</p><p>[ba]r</p><p>Xyz</p>\n\t//\n\t// After move:\n\t// <p>F</p><p>r</p><p>Xyzozba</p>\n\t//\n\tif ( moveRange.start.hasSameParentAs( b.splitPosition ) && moveRange.containsPosition( b.splitPosition ) ) {\n\t\tlet rightRange = new Range( b.splitPosition, moveRange.end );\n\t\trightRange = rightRange._getTransformedBySplitOperation( b );\n\n\t\tconst ranges = [\n\t\t\tnew Range( moveRange.start, b.splitPosition ),\n\t\t\trightRange\n\t\t];\n\n\t\treturn _makeMoveOperationsFromRanges( ranges, newTargetPosition );\n\t}\n\n\t// Case 3:\n\t//\n\t// Move operation targets at the split position. We need to decide if the nodes should be inserted\n\t// at the end of the split element or at the beginning of the new element.\n\t//\n\tif ( a.targetPosition.isEqual( b.splitPosition ) && context.abRelation == 'insertAtSource' ) {\n\t\tnewTargetPosition = b.moveTargetPosition;\n\t}\n\n\t// Case 4:\n\t//\n\t// Move operation targets just after the split element. We need to decide if the nodes should be inserted\n\t// between two parts of split element, or after the new element.\n\t//\n\t// Split at `|`, while move operation moves `<p>Xyz</p>` and targets at `^`:\n\t// <p>Foo|bar</p>^<p>baz</p>\n\t// <p>Foo</p>^<p>bar</p><p>baz</p> or <p>Foo</p><p>bar</p>^<p>baz</p>?\n\t//\n\t// If there is no contextual information between operations (for example, they come from collaborative\n\t// editing), we don't want to put some unrelated content (move) between parts of related content (split parts).\n\t// However, if the split is from undo, in the past, the moved content might be targeting between the\n\t// split parts, meaning that was exactly user's intention:\n\t//\n\t// <p>Foo</p>^<p>bar</p>\t\t<--- original situation, in \"past\".\n\t// <p>Foobar</p>^\t\t\t\t<--- after merge target position is transformed.\n\t// <p>Foo|bar</p>^\t\t\t\t<--- then the merge is undone, and split happens, which leads us to current situation.\n\t//\n\t// In this case it is pretty clear that the intention was to put new paragraph between those nodes,\n\t// so we need to transform accordingly. We can detect this scenario thanks to relations.\n\t//\n\tif ( a.targetPosition.isEqual( b.insertionPosition ) && context.abRelation == 'insertBetween' ) {\n\t\tnewTargetPosition = a.targetPosition;\n\t}\n\n\t// The default case.\n\t//\n\tconst transformed = moveRange._getTransformedBySplitOperation( b );\n\tconst ranges = [ transformed ];\n\n\t// Case 5:\n\t//\n\t// Moved range contains graveyard element used by split operation. Add extra move operation to the result.\n\t//\n\tif ( b.graveyardPosition ) {\n\t\tconst movesGraveyardElement = moveRange.start.isEqual( b.graveyardPosition ) || moveRange.containsPosition( b.graveyardPosition );\n\n\t\tif ( a.howMany > 1 && movesGraveyardElement && !context.aWasUndone ) {\n\t\t\tranges.push( Range._createFromPositionAndShift( b.insertionPosition, 1 ) );\n\t\t}\n\t}\n\n\treturn _makeMoveOperationsFromRanges( ranges, newTargetPosition );\n} );\n\nsetTransformation( MoveOperation, MergeOperation, ( a, b, context ) => {\n\tconst movedRange = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );\n\n\tif ( b.deletionPosition.hasSameParentAs( a.sourcePosition ) && movedRange.containsPosition( b.sourcePosition ) ) {\n\t\tif ( a.type == 'remove' && !context.forceWeakRemove ) {\n\t\t\t// Case 1:\n\t\t\t//\n\t\t\t// The element to remove got merged.\n\t\t\t//\n\t\t\t// Merge operation does support merging elements which are not siblings. So it would not be a problem\n\t\t\t// from technical point of view. However, if the element was removed, the intention of the user\n\t\t\t// deleting it was to have it all deleted. From user experience point of view, moving back the\n\t\t\t// removed nodes might be unexpected. This means that in this scenario we will reverse merging and remove the element.\n\t\t\t//\n\t\t\tif ( !context.aWasUndone ) {\n\t\t\t\tconst results = [];\n\n\t\t\t\tlet gyMoveSource = b.graveyardPosition.clone();\n\t\t\t\tlet splitNodesMoveSource = b.targetPosition._getTransformedByMergeOperation( b );\n\n\t\t\t\tif ( a.howMany > 1 ) {\n\t\t\t\t\tresults.push( new MoveOperation( a.sourcePosition, a.howMany - 1, a.targetPosition, 0 ) );\n\n\t\t\t\t\tgyMoveSource = gyMoveSource._getTransformedByMove( a.sourcePosition, a.targetPosition, a.howMany - 1 );\n\t\t\t\t\tsplitNodesMoveSource = splitNodesMoveSource._getTransformedByMove( a.sourcePosition, a.targetPosition, a.howMany - 1 );\n\t\t\t\t}\n\n\t\t\t\tconst gyMoveTarget = b.deletionPosition._getCombined( a.sourcePosition, a.targetPosition );\n\t\t\t\tconst gyMove = new MoveOperation( gyMoveSource, 1, gyMoveTarget, 0 );\n\n\t\t\t\tconst splitNodesMoveTargetPath = gyMove.getMovedRangeStart().path.slice();\n\t\t\t\tsplitNodesMoveTargetPath.push( 0 );\n\n\t\t\t\tconst splitNodesMoveTarget = new Position( gyMove.targetPosition.root, splitNodesMoveTargetPath );\n\t\t\t\tsplitNodesMoveSource = splitNodesMoveSource._getTransformedByMove( gyMoveSource, gyMoveTarget, 1 );\n\t\t\t\tconst splitNodesMove = new MoveOperation( splitNodesMoveSource, b.howMany, splitNodesMoveTarget, 0 );\n\n\t\t\t\tresults.push( gyMove );\n\t\t\t\tresults.push( splitNodesMove );\n\n\t\t\t\treturn results;\n\t\t\t}\n\t\t} else {\n\t\t\t// Case 2:\n\t\t\t//\n\t\t\t// The element to move got merged and it was the only element to move.\n\t\t\t// In this case just don't do anything, leave the node in the graveyard. Without special case\n\t\t\t// it would be a move operation that moves 0 nodes, so maybe it is better just to return no-op.\n\t\t\t//\n\t\t\tif ( a.howMany == 1 ) {\n\t\t\t\tif ( !context.bWasUndone ) {\n\t\t\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t\t\t} else {\n\t\t\t\t\ta.sourcePosition = b.graveyardPosition.clone();\n\t\t\t\t\ta.targetPosition = a.targetPosition._getTransformedByMergeOperation( b );\n\n\t\t\t\t\treturn [ a ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// The default case.\n\t//\n\tconst moveRange = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );\n\tconst transformed = moveRange._getTransformedByMergeOperation( b );\n\n\ta.sourcePosition = transformed.start;\n\ta.howMany = transformed.end.offset - transformed.start.offset;\n\ta.targetPosition = a.targetPosition._getTransformedByMergeOperation( b );\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( RenameOperation, InsertOperation, ( a, b ) => {\n\ta.position = a.position._getTransformedByInsertOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( RenameOperation, MergeOperation, ( a, b ) => {\n\t// Case 1:\n\t//\n\t// Element to rename got merged, so it was moved to `b.graveyardPosition`.\n\t//\n\tif ( a.position.isEqual( b.deletionPosition ) ) {\n\t\ta.position = b.graveyardPosition.clone();\n\t\ta.position.stickiness = 'toNext';\n\n\t\treturn [ a ];\n\t}\n\n\ta.position = a.position._getTransformedByMergeOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( RenameOperation, MoveOperation, ( a, b ) => {\n\ta.position = a.position._getTransformedByMoveOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( RenameOperation, RenameOperation, ( a, b, context ) => {\n\tif ( a.position.isEqual( b.position ) ) {\n\t\tif ( context.aIsStrong ) {\n\t\t\ta.oldName = b.newName;\n\t\t} else {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( RenameOperation, SplitOperation, ( a, b ) => {\n\t// Case 1:\n\t//\n\t// The element to rename has been split. In this case, the new element should be also renamed.\n\t//\n\t// User decides to change the paragraph to a list item:\n\t// <paragraph>Foobar</paragraph>\n\t//\n\t// However, in meantime, split happens:\n\t// <paragraph>Foo</paragraph><paragraph>bar</paragraph>\n\t//\n\t// As a result, rename both elements:\n\t// <listItem>Foo</listItem><listItem>bar</listItem>\n\t//\n\tconst renamePath = a.position.path;\n\tconst splitPath = b.splitPosition.getParentPath();\n\n\tif ( compareArrays( renamePath, splitPath ) == 'same' && !b.graveyardPosition ) {\n\t\tconst extraRename = new RenameOperation( a.position.getShiftedBy( 1 ), a.oldName, a.newName, 0 );\n\n\t\treturn [ a, extraRename ];\n\t}\n\n\t// The default case.\n\t//\n\ta.position = a.position._getTransformedBySplitOperation( b );\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( RootAttributeOperation, RootAttributeOperation, ( a, b, context ) => {\n\tif ( a.root === b.root && a.key === b.key ) {\n\t\tif ( !context.aIsStrong || a.newValue === b.newValue ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t} else {\n\t\t\ta.oldValue = b.newValue;\n\t\t}\n\t}\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( SplitOperation, InsertOperation, ( a, b ) => {\n\t// The default case.\n\t//\n\tif ( a.splitPosition.hasSameParentAs( b.position ) && a.splitPosition.offset < b.position.offset ) {\n\t\ta.howMany += b.howMany;\n\t}\n\n\ta.splitPosition = a.splitPosition._getTransformedByInsertOperation( b );\n\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\n\treturn [ a ];\n} );\n\nsetTransformation( SplitOperation, MergeOperation, ( a, b, context ) => {\n\t// Case 1:\n\t//\n\t// Split element got merged. If two different elements were merged, clients will have different content.\n\t//\n\t// Example. Merge at `{}`, split at `[]`:\n\t// <heading>Foo</heading>{}<paragraph>B[]ar</paragraph>\n\t//\n\t// On merge side it will look like this:\n\t// <heading>FooB[]ar</heading>\n\t// <heading>FooB</heading><heading>ar</heading>\n\t//\n\t// On split side it will look like this:\n\t// <heading>Foo</heading>{}<paragraph>B</paragraph><paragraph>ar</paragraph>\n\t// <heading>FooB</heading><paragraph>ar</paragraph>\n\t//\n\t// Clearly, the second element is different for both clients.\n\t//\n\t// We could use the removed merge element from graveyard as a split element but then clients would have a different\n\t// model state (in graveyard), because the split side client would still have an element in graveyard (removed by merge).\n\t//\n\t// To overcome this, in `SplitOperation` x `MergeOperation` transformation we will add additional `SplitOperation`\n\t// in the graveyard, which will actually clone the merged-and-deleted element. Then, that cloned element will be\n\t// used for splitting. Example below.\n\t//\n\t// Original state:\n\t// <heading>Foo</heading>{}<paragraph>B[]ar</paragraph>\n\t//\n\t// Merge side client:\n\t//\n\t// After merge:\n\t// <heading>FooB[]ar</heading>                                 graveyard: <paragraph></paragraph>\n\t//\n\t// Extra split:\n\t// <heading>FooB[]ar</heading>                                 graveyard: <paragraph></paragraph><paragraph></paragraph>\n\t//\n\t// Use the \"cloned\" element from graveyard:\n\t// <heading>FooB</heading><paragraph>ar</paragraph>            graveyard: <paragraph></paragraph>\n\t//\n\t// Split side client:\n\t//\n\t// After split:\n\t// <heading>Foo</heading>{}<paragraph>B</paragraph><paragraph>ar</paragraph>\n\t//\n\t// After merge:\n\t// <heading>FooB</heading><paragraph>ar</paragraph>            graveyard: <paragraph></paragraph>\n\t//\n\t// This special case scenario only applies if the original split operation clones the split element.\n\t// If the original split operation has `graveyardPosition` set, it all doesn't have sense because split operation\n\t// knows exactly which element it should use. So there would be no original problem with different contents.\n\t//\n\t// Additionally, the special case applies only if the merge wasn't already undone.\n\t//\n\tif ( !a.graveyardPosition && !context.bWasUndone && a.splitPosition.hasSameParentAs( b.sourcePosition ) ) {\n\t\tconst splitPath = b.graveyardPosition.path.slice();\n\t\tsplitPath.push( 0 );\n\n\t\tconst splitPosition = new Position( b.graveyardPosition.root, splitPath );\n\t\tconst insertionPosition = SplitOperation.getInsertionPosition( new Position( b.graveyardPosition.root, splitPath ) );\n\n\t\tconst additionalSplit = new SplitOperation( splitPosition, 0, null, 0 );\n\t\tadditionalSplit.insertionPosition = insertionPosition;\n\n\t\ta.splitPosition = a.splitPosition._getTransformedByMergeOperation( b );\n\t\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\t\ta.graveyardPosition = additionalSplit.insertionPosition.clone();\n\t\ta.graveyardPosition.stickiness = 'toNext';\n\n\t\treturn [ additionalSplit, a ];\n\t}\n\n\t// The default case.\n\t//\n\tif ( a.splitPosition.hasSameParentAs( b.deletionPosition ) && !a.splitPosition.isAfter( b.deletionPosition ) ) {\n\t\ta.howMany--;\n\t}\n\n\tif ( a.splitPosition.hasSameParentAs( b.targetPosition ) ) {\n\t\ta.howMany += b.howMany;\n\t}\n\n\ta.splitPosition = a.splitPosition._getTransformedByMergeOperation( b );\n\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\n\tif ( a.graveyardPosition ) {\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedByMergeOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( SplitOperation, MoveOperation, ( a, b, context ) => {\n\tconst rangeToMove = Range._createFromPositionAndShift( b.sourcePosition, b.howMany );\n\n\tif ( a.graveyardPosition ) {\n\t\t// Case 1:\n\t\t//\n\t\t// Split operation graveyard node was moved. In this case move operation is stronger. Since graveyard element\n\t\t// is already moved to the correct position, we need to only move the nodes after the split position.\n\t\t// This will be done by `MoveOperation` instead of `SplitOperation`.\n\t\t//\n\t\tconst gyElementMoved = rangeToMove.start.isEqual( a.graveyardPosition ) || rangeToMove.containsPosition( a.graveyardPosition );\n\n\t\tif ( !context.bWasUndone && gyElementMoved ) {\n\t\t\tconst sourcePosition = a.splitPosition._getTransformedByMoveOperation( b );\n\n\t\t\tconst newParentPosition = a.graveyardPosition._getTransformedByMoveOperation( b );\n\t\t\tconst newTargetPath = newParentPosition.path.slice();\n\t\t\tnewTargetPath.push( 0 );\n\n\t\t\tconst newTargetPosition = new Position( newParentPosition.root, newTargetPath );\n\t\t\tconst moveOp = new MoveOperation( sourcePosition, a.howMany, newTargetPosition, 0 );\n\n\t\t\treturn [ moveOp ];\n\t\t}\n\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedByMoveOperation( b );\n\t}\n\n\t// Case 2:\n\t//\n\t// If the split position is inside the moved range, we need to shift the split position to a proper place.\n\t// The position cannot be moved together with moved range because that would result in splitting of an incorrect element.\n\t//\n\t// Characters `bc` should be moved to the second paragraph while split position is between them:\n\t// <paragraph>A[b|c]d</paragraph><paragraph>Xyz</paragraph>\n\t//\n\t// After move, new split position is incorrect:\n\t// <paragraph>Ad</paragraph><paragraph>Xb|cyz</paragraph>\n\t//\n\t// Correct split position:\n\t// <paragraph>A|d</paragraph><paragraph>Xbcyz</paragraph>\n\t//\n\t// After split:\n\t// <paragraph>A</paragraph><paragraph>d</paragraph><paragraph>Xbcyz</paragraph>\n\t//\n\tif ( a.splitPosition.hasSameParentAs( b.sourcePosition ) && rangeToMove.containsPosition( a.splitPosition ) ) {\n\t\tconst howManyRemoved = b.howMany - ( a.splitPosition.offset - b.sourcePosition.offset );\n\t\ta.howMany -= howManyRemoved;\n\n\t\tif ( a.splitPosition.hasSameParentAs( b.targetPosition ) && a.splitPosition.offset < b.targetPosition.offset ) {\n\t\t\ta.howMany += b.howMany;\n\t\t}\n\n\t\ta.splitPosition = b.sourcePosition.clone();\n\t\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\n\t\treturn [ a ];\n\t}\n\n\t// Case 3:\n\t//\n\t// Split is at a position where nodes were moved.\n\t//\n\t// This is a scenario described in `MoveOperation` x `SplitOperation` transformation but from the\n\t// \"split operation point of view\".\n\t//\n\tconst splitAtTarget = a.splitPosition.isEqual( b.targetPosition );\n\n\tif ( splitAtTarget && ( context.baRelation == 'insertAtSource' || context.abRelation == 'splitBefore' ) ) {\n\t\ta.howMany += b.howMany;\n\t\ta.splitPosition = a.splitPosition._getTransformedByDeletion( b.sourcePosition, b.howMany );\n\t\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\n\t\treturn [ a ];\n\t}\n\n\t// The default case.\n\t// Don't change `howMany` if move operation does not really move anything.\n\t//\n\tif ( !b.sourcePosition.isEqual( b.targetPosition ) ) {\n\t\tif ( a.splitPosition.hasSameParentAs( b.sourcePosition ) && a.splitPosition.offset <= b.sourcePosition.offset ) {\n\t\t\ta.howMany -= b.howMany;\n\t\t}\n\n\t\tif ( a.splitPosition.hasSameParentAs( b.targetPosition ) && a.splitPosition.offset < b.targetPosition.offset ) {\n\t\t\ta.howMany += b.howMany;\n\t\t}\n\t}\n\n\t// Change position stickiness to force a correct transformation.\n\ta.splitPosition.stickiness = 'toNone';\n\ta.splitPosition = a.splitPosition._getTransformedByMoveOperation( b );\n\ta.splitPosition.stickiness = 'toNext';\n\n\tif ( a.graveyardPosition ) {\n\t\ta.insertionPosition = a.insertionPosition._getTransformedByMoveOperation( b );\n\t} else {\n\t\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( SplitOperation, SplitOperation, ( a, b, context ) => {\n\t// Case 1:\n\t//\n\t// Split at the same position.\n\t//\n\t// If there already was a split at the same position as in `a` operation, it means that the intention\n\t// conveyed by `a` operation has already been fulfilled and `a` should not do anything (to avoid double split).\n\t//\n\t// However, there is a difference if these are new splits or splits created by undo. These have different\n\t// intentions. Also splits moving back different elements from graveyard have different intentions. They\n\t// are just different operations.\n\t//\n\t// So we cancel split operation only if it was really identical.\n\t//\n\t// Also, there is additional case, where split operations aren't identical and should not be cancelled, however the\n\t// default transformation is incorrect too.\n\t//\n\tif ( a.splitPosition.isEqual( b.splitPosition ) ) {\n\t\tif ( !a.graveyardPosition && !b.graveyardPosition ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\n\t\tif ( a.graveyardPosition && b.graveyardPosition && a.graveyardPosition.isEqual( b.graveyardPosition ) ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\n\t\t// Use context to know that the `a.splitPosition` should stay where it is.\n\t\t// This happens during undo when first a merge operation moved nodes to `a.splitPosition` and now `b` operation undoes that merge.\n\t\tif ( context.abRelation == 'splitBefore' ) {\n\t\t\t// Since split is at the same position, there are no nodes left to split.\n\t\t\ta.howMany = 0;\n\n\t\t\t// Note: there was `if ( a.graveyardPosition )` here but it was uncovered in tests and I couldn't find any scenarios for now.\n\t\t\t// That would have to be a `SplitOperation` that didn't come from undo but is transformed by operations that were undone.\n\t\t\t// It could happen if `context` is enabled in collaboration.\n\t\t\ta.graveyardPosition = a.graveyardPosition._getTransformedBySplitOperation( b );\n\n\t\t\treturn [ a ];\n\t\t}\n\t}\n\n\t// Case 2:\n\t//\n\t// Same node is using to split different elements. This happens in undo when previously same element was merged to\n\t// two different elements. This is described in `MergeOperation` x `MergeOperation` transformation.\n\t//\n\t// In this case we will follow the same logic. We will assume that `insertionPosition` is same for both\n\t// split operations. This might not always be true but in the real cases that were experienced it was. After all,\n\t// if these splits are reverses of merge operations that were merging the same element, then the `insertionPosition`\n\t// should be same for both of those splits.\n\t//\n\t// Again, we will decide which operation is stronger by checking if split happens in graveyard or in non-graveyard root.\n\t//\n\tif ( a.graveyardPosition && b.graveyardPosition && a.graveyardPosition.isEqual( b.graveyardPosition ) ) {\n\t\tconst aInGraveyard = a.splitPosition.root.rootName == '$graveyard';\n\t\tconst bInGraveyard = b.splitPosition.root.rootName == '$graveyard';\n\n\t\t// If `aIsWeak` it means that `a` points to graveyard while `b` doesn't. Don't move nodes then.\n\t\tconst aIsWeak = aInGraveyard && !bInGraveyard;\n\n\t\t// If `bIsWeak` it means that `b` points to graveyard while `a` doesn't. Force moving nodes then.\n\t\tconst bIsWeak = bInGraveyard && !aInGraveyard;\n\n\t\t// Force move if `b` is weak or neither operation is weak but `a` is stronger through `context.aIsStrong`.\n\t\tconst forceMove = bIsWeak || ( !aIsWeak && context.aIsStrong );\n\n\t\tif ( forceMove ) {\n\t\t\tconst result = [];\n\n\t\t\t// First we need to move any nodes split by `b` back to where they were.\n\t\t\t// Do it only if `b` actually moved something.\n\t\t\tif ( b.howMany ) {\n\t\t\t\tresult.push( new MoveOperation( b.moveTargetPosition, b.howMany, b.splitPosition, 0 ) );\n\t\t\t}\n\n\t\t\t// Then we need to move nodes from `a` split position to their new element.\n\t\t\t// Do it only if `a` actually should move something.\n\t\t\tif ( a.howMany ) {\n\t\t\t\tresult.push( new MoveOperation( a.splitPosition, a.howMany, a.moveTargetPosition, 0 ) );\n\t\t\t}\n\n\t\t\treturn result;\n\t\t} else {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\t}\n\n\tif ( a.graveyardPosition ) {\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedBySplitOperation( b );\n\t}\n\n\t// Case 3:\n\t//\n\t// Position where operation `b` inserted a new node after split is the same as the operation `a` split position.\n\t// As in similar cases, there is ambiguity if the split should be before the new node (created by `b`) or after.\n\t//\n\tif ( a.splitPosition.isEqual( b.insertionPosition ) && context.abRelation == 'splitBefore' ) {\n\t\ta.howMany++;\n\n\t\treturn [ a ];\n\t}\n\n\t// Case 4:\n\t//\n\t// This is a mirror to the case 2. above.\n\t//\n\tif ( b.splitPosition.isEqual( a.insertionPosition ) && context.baRelation == 'splitBefore' ) {\n\t\tconst newPositionPath = b.insertionPosition.path.slice();\n\t\tnewPositionPath.push( 0 );\n\n\t\tconst newPosition = new Position( b.insertionPosition.root, newPositionPath );\n\t\tconst moveOp = new MoveOperation( a.insertionPosition, 1, newPosition, 0 );\n\n\t\treturn [ a, moveOp ];\n\t}\n\n\t// The default case.\n\t//\n\tif ( a.splitPosition.hasSameParentAs( b.splitPosition ) && a.splitPosition.offset < b.splitPosition.offset ) {\n\t\ta.howMany -= b.howMany;\n\t}\n\n\ta.splitPosition = a.splitPosition._getTransformedBySplitOperation( b );\n\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\n\treturn [ a ];\n} );\n\n// Checks whether `MoveOperation` `targetPosition` is inside a node from the moved range of the other `MoveOperation`.\n//\n// @private\n// @param {module:engine/model/operation/moveoperation~MoveOperation} a\n// @param {module:engine/model/operation/moveoperation~MoveOperation} b\n// @returns {Boolean}\nfunction _moveTargetIntoMovedRange( a, b ) {\n\treturn a.targetPosition._getTransformedByDeletion( b.sourcePosition, b.howMany ) === null;\n}\n\n// Helper function for `MoveOperation` x `MoveOperation` transformation. Converts given ranges and target position to\n// move operations and returns them.\n//\n// Ranges and target position will be transformed on-the-fly when generating operations.\n//\n// Given `ranges` should be in the order of how they were in the original transformed operation.\n//\n// Given `targetPosition` is the target position of the first range from `ranges`.\n//\n// @private\n// @param {Array.<module:engine/model/range~Range>} ranges\n// @param {module:engine/model/position~Position} targetPosition\n// @returns {Array.<module:engine/model/operation/moveoperation~MoveOperation>}\nfunction _makeMoveOperationsFromRanges( ranges, targetPosition ) {\n\t// At this moment we have some ranges and a target position, to which those ranges should be moved.\n\t// Order in `ranges` array is the go-to order of after transformation.\n\t//\n\t// We are almost done. We have `ranges` and `targetPosition` to make operations from.\n\t// Unfortunately, those operations may affect each other. Precisely, first operation after move\n\t// may affect source range and target position of second and third operation. Same with second\n\t// operation affecting third.\n\t//\n\t// We need to fix those source ranges and target positions once again, before converting `ranges` to operations.\n\tconst operations = [];\n\n\t// Keep in mind that nothing will be transformed if there is just one range in `ranges`.\n\tfor ( let i = 0; i < ranges.length; i++ ) {\n\t\t// Create new operation out of a range and target position.\n\t\tconst range = ranges[ i ];\n\t\tconst op = new MoveOperation(\n\t\t\trange.start,\n\t\t\trange.end.offset - range.start.offset,\n\t\t\ttargetPosition,\n\t\t\t0\n\t\t);\n\n\t\toperations.push( op );\n\n\t\t// Transform other ranges by the generated operation.\n\t\tfor ( let j = i + 1; j < ranges.length; j++ ) {\n\t\t\t// All ranges in `ranges` array should be:\n\t\t\t//\n\t\t\t// * non-intersecting (these are part of original operation source range), and\n\t\t\t// * `targetPosition` does not target into them (opposite would mean that transformed operation targets \"inside itself\").\n\t\t\t//\n\t\t\t// This means that the transformation will be \"clean\" and always return one result.\n\t\t\tranges[ j ] = ranges[ j ]._getTransformedByMove( op.sourcePosition, op.targetPosition, op.howMany )[ 0 ];\n\t\t}\n\n\t\ttargetPosition = targetPosition._getTransformedByMove( op.sourcePosition, op.targetPosition, op.howMany );\n\t}\n\n\treturn operations;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module undo/basecommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { transformSets } from '@ckeditor/ckeditor5-engine/src/model/operation/transform';\n\n/**\n * Base class for undo feature commands: {@link module:undo/undocommand~UndoCommand} and {@link module:undo/redocommand~RedoCommand}.\n *\n * @protected\n * @extends module:core/command~Command\n */\nexport default class BaseCommand extends Command {\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * Stack of items stored by the command. These are pairs of:\n\t\t *\n\t\t * * {@link module:engine/model/batch~Batch batch} saved by the command,\n\t\t * * {@link module:engine/model/selection~Selection selection} state at the moment of saving the batch.\n\t\t *\n\t\t * @protected\n\t\t * @member {Array} #_stack\n\t\t */\n\t\tthis._stack = [];\n\n\t\t/**\n\t\t * Stores all batches that were created by this command.\n\t\t *\n\t\t * @protected\n\t\t * @member {WeakSet.<module:engine/model/batch~Batch>} #_createdBatches\n\t\t */\n\t\tthis._createdBatches = new WeakSet();\n\n\t\t// Refresh state, so the command is inactive right after initialization.\n\t\tthis.refresh();\n\n\t\tthis.listenTo( editor.data, 'set', () => this.clearStack() );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.isEnabled = this._stack.length > 0;\n\t}\n\n\t/**\n\t * Stores a batch in the command, together with the selection state of the {@link module:engine/model/document~Document document}\n\t * created by the editor which this command is registered to.\n\t *\n\t * @param {module:engine/model/batch~Batch} batch The batch to add.\n\t */\n\taddBatch( batch ) {\n\t\tconst docSelection = this.editor.model.document.selection;\n\n\t\tconst selection = {\n\t\t\tranges: docSelection.hasOwnRange ? Array.from( docSelection.getRanges() ) : [],\n\t\t\tisBackward: docSelection.isBackward\n\t\t};\n\n\t\tthis._stack.push( { batch, selection } );\n\t\tthis.refresh();\n\t}\n\n\t/**\n\t * Removes all items from the stack.\n\t */\n\tclearStack() {\n\t\tthis._stack = [];\n\t\tthis.refresh();\n\t}\n\n\t/**\n\t * Restores the {@link module:engine/model/document~Document#selection document selection} state after a batch was undone.\n\t *\n\t * @protected\n\t * @param {Array.<module:engine/model/range~Range>} ranges Ranges to be restored.\n\t * @param {Boolean} isBackward A flag describing whether the restored range was selected forward or backward.\n\t * @param {Array.<module:engine/model/operation/operation~Operation>} operations Operations which has been applied\n\t * since selection has been stored.\n\t */\n\t_restoreSelection( ranges, isBackward, operations ) {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\n\t\t// This will keep the transformed selection ranges.\n\t\tconst selectionRanges = [];\n\n\t\t// Transform all ranges from the restored selection.\n\t\tconst transformedRangeGroups = ranges.map( range => range.getTransformedByOperations( operations ) );\n\t\tconst allRanges = transformedRangeGroups.flat();\n\n\t\tfor ( const rangeGroup of transformedRangeGroups ) {\n\t\t\t// While transforming there could appear ranges that are contained by other ranges, we shall ignore them.\n\t\t\tconst transformed = rangeGroup\n\t\t\t\t.filter( range => range.root != document.graveyard )\n\t\t\t\t.filter( range => !isRangeContainedByAnyOtherRange( range, allRanges ) );\n\n\t\t\t// All the transformed ranges ended up in graveyard.\n\t\t\tif ( !transformed.length ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// After the range got transformed, we have an array of ranges. Some of those\n\t\t\t// ranges may be \"touching\" -- they can be next to each other and could be merged.\n\t\t\tnormalizeRanges( transformed );\n\n\t\t\t// For each `range` from `ranges`, we take only one transformed range.\n\t\t\t// This is because we want to prevent situation where single-range selection\n\t\t\t// got transformed to multi-range selection.\n\t\t\tselectionRanges.push( transformed[ 0 ] );\n\t\t}\n\n\t\t// @if CK_DEBUG_ENGINE // console.log( `Restored selection by undo: ${ selectionRanges.join( ', ' ) }` );\n\n\t\t// `selectionRanges` may be empty if all ranges ended up in graveyard. If that is the case, do not restore selection.\n\t\tif ( selectionRanges.length ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\twriter.setSelection( selectionRanges, { backward: isBackward } );\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Undoes a batch by reversing that batch, transforming reversed batch and finally applying it.\n\t * This is a helper method for {@link #execute}.\n\t *\n\t * @protected\n\t * @param {module:engine/model/batch~Batch} batchToUndo The batch to be undone.\n\t * @param {module:engine/model/batch~Batch} undoingBatch The batch that will contain undoing changes.\n\t */\n\t_undo( batchToUndo, undoingBatch ) {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\n\t\t// All changes done by the command execution will be saved as one batch.\n\t\tthis._createdBatches.add( undoingBatch );\n\n\t\tconst operationsToUndo = batchToUndo.operations.slice().filter( operation => operation.isDocumentOperation );\n\t\toperationsToUndo.reverse();\n\n\t\t// We will process each operation from `batchToUndo`, in reverse order. If there were operations A, B and C in undone batch,\n\t\t// we need to revert them in reverse order, so first C' (reversed C), then B', then A'.\n\t\tfor ( const operationToUndo of operationsToUndo ) {\n\t\t\tconst nextBaseVersion = operationToUndo.baseVersion + 1;\n\t\t\tconst historyOperations = Array.from( document.history.getOperations( nextBaseVersion ) );\n\n\t\t\tconst transformedSets = transformSets(\n\t\t\t\t[ operationToUndo.getReversed() ],\n\t\t\t\thistoryOperations,\n\t\t\t\t{\n\t\t\t\t\tuseRelations: true,\n\t\t\t\t\tdocument: this.editor.model.document,\n\t\t\t\t\tpadWithNoOps: false,\n\t\t\t\t\tforceWeakRemove: true\n\t\t\t\t}\n\t\t\t);\n\n\t\t\tconst reversedOperations = transformedSets.operationsA;\n\n\t\t\t// After reversed operation has been transformed by all history operations, apply it.\n\t\t\tfor ( const operation of reversedOperations ) {\n\t\t\t\t// Before applying, add the operation to the `undoingBatch`.\n\t\t\t\tundoingBatch.addOperation( operation );\n\t\t\t\tmodel.applyOperation( operation );\n\n\t\t\t\tdocument.history.setOperationAsUndone( operationToUndo, operation );\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Normalizes list of ranges by joining intersecting or \"touching\" ranges.\n//\n// @param {Array.<module:engine/model/range~Range>} ranges\n//\nfunction normalizeRanges( ranges ) {\n\tranges.sort( ( a, b ) => a.start.isBefore( b.start ) ? -1 : 1 );\n\n\tfor ( let i = 1; i < ranges.length; i++ ) {\n\t\tconst previousRange = ranges[ i - 1 ];\n\t\tconst joinedRange = previousRange.getJoined( ranges[ i ], true );\n\n\t\tif ( joinedRange ) {\n\t\t\t// Replace the ranges on the list with the new joined range.\n\t\t\ti--;\n\t\t\tranges.splice( i, 2, joinedRange );\n\t\t}\n\t}\n}\n\nfunction isRangeContainedByAnyOtherRange( range, ranges ) {\n\treturn ranges.some( otherRange => otherRange !== range && otherRange.containsRange( range, true ) );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module undo/undocommand\n */\n\nimport BaseCommand from './basecommand';\n\n/**\n * The undo command stores {@link module:engine/model/batch~Batch batches} applied to the\n * {@link module:engine/model/document~Document document} and is able to undo a batch by reversing it and transforming by\n * batches from {@link module:engine/model/document~Document#history history} that happened after the reversed batch.\n *\n * The undo command also takes care of restoring the {@link module:engine/model/document~Document#selection document selection}.\n *\n * @extends module:undo/basecommand~BaseCommand\n */\nexport default class UndoCommand extends BaseCommand {\n\t/**\n\t * Executes the command. This method reverts a {@link module:engine/model/batch~Batch batch} added to the command's stack, transforms\n\t * and applies the reverted version on the {@link module:engine/model/document~Document document} and removes the batch from the stack.\n\t * Then, it restores the {@link module:engine/model/document~Document#selection document selection}.\n\t *\n\t * @fires execute\n\t * @fires revert\n\t * @param {module:engine/model/batch~Batch} [batch] A batch that should be undone. If not set, the last added batch will be undone.\n\t */\n\texecute( batch = null ) {\n\t\t// If batch is not given, set `batchIndex` to the last index in command stack.\n\t\tconst batchIndex = batch ? this._stack.findIndex( a => a.batch == batch ) : this._stack.length - 1;\n\n\t\tconst item = this._stack.splice( batchIndex, 1 )[ 0 ];\n\t\tconst undoingBatch = this.editor.model.createBatch( 'transparent' );\n\n\t\t// All changes has to be done in one `enqueueChange` callback so other listeners will not\n\t\t// step between consecutive operations, or won't do changes to the document before selection is properly restored.\n\t\tthis.editor.model.enqueueChange( undoingBatch, () => {\n\t\t\tthis._undo( item.batch, undoingBatch );\n\n\t\t\tconst operations = this.editor.model.document.history.getOperations( item.batch.baseVersion );\n\t\t\tthis._restoreSelection( item.selection.ranges, item.selection.isBackward, operations );\n\n\t\t\tthis.fire( 'revert', item.batch, undoingBatch );\n\t\t} );\n\n\t\tthis.refresh();\n\t}\n}\n\n/**\n * Fired when execution of the command reverts some batch.\n *\n * @event revert\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module undo/redocommand\n */\n\nimport BaseCommand from './basecommand';\n\n/**\n * The redo command stores {@link module:engine/model/batch~Batch batches} that were used to undo a batch by\n * {@link module:undo/undocommand~UndoCommand}. It is able to redo a previously undone batch by reversing the undoing\n * batches created by `UndoCommand`. The reversed batch is transformed by all the batches from\n * {@link module:engine/model/document~Document#history history} that happened after the reversed undo batch.\n *\n * The redo command also takes care of restoring the {@link module:engine/model/document~Document#selection document selection}.\n *\n * @extends module:undo/basecommand~BaseCommand\n */\nexport default class RedoCommand extends BaseCommand {\n\t/**\n\t * Executes the command. This method reverts the last {@link module:engine/model/batch~Batch batch} added to\n\t * the command's stack, applies the reverted and transformed version on the\n\t * {@link module:engine/model/document~Document document} and removes the batch from the stack.\n\t * Then, it restores the {@link module:engine/model/document~Document#selection document selection}.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst item = this._stack.pop();\n\t\tconst redoingBatch = this.editor.model.createBatch( 'transparent' );\n\n\t\t// All changes have to be done in one `enqueueChange` callback so other listeners will not step between consecutive\n\t\t// operations, or won't do changes to the document before selection is properly restored.\n\t\tthis.editor.model.enqueueChange( redoingBatch, () => {\n\t\t\tconst lastOperation = item.batch.operations[ item.batch.operations.length - 1 ];\n\t\t\tconst nextBaseVersion = lastOperation.baseVersion + 1;\n\t\t\tconst operations = this.editor.model.document.history.getOperations( nextBaseVersion );\n\n\t\t\tthis._restoreSelection( item.selection.ranges, item.selection.isBackward, operations );\n\t\t\tthis._undo( item.batch, redoingBatch );\n\t\t} );\n\n\t\tthis.refresh();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module undo/undoediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport UndoCommand from './undocommand';\nimport RedoCommand from './redocommand';\n\n/**\n * The undo engine feature.\n *\n * It introduces the `'undo'` and `'redo'` commands to the editor.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class UndoEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'UndoEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The command that manages undo {@link module:engine/model/batch~Batch batches} stack (history).\n\t\t * Created and registered during the {@link #init feature initialization}.\n\t\t *\n\t\t * @private\n\t\t * @member {module:undo/undocommand~UndoCommand} #_undoCommand\n\t\t */\n\n\t\t/**\n\t\t * The command that manages redo {@link module:engine/model/batch~Batch batches} stack (history).\n\t\t * Created and registered during the {@link #init feature initialization}.\n\t\t *\n\t\t * @private\n\t\t * @member {module:undo/undocommand~UndoCommand} #_redoCommand\n\t\t */\n\n\t\t/**\n\t\t * Keeps track of which batches were registered in undo.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakSet.<module:engine/model/batch~Batch>}\n\t\t */\n\t\tthis._batchRegistry = new WeakSet();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Create commands.\n\t\tthis._undoCommand = new UndoCommand( editor );\n\t\tthis._redoCommand = new RedoCommand( editor );\n\n\t\t// Register command to the editor.\n\t\teditor.commands.add( 'undo', this._undoCommand );\n\t\teditor.commands.add( 'redo', this._redoCommand );\n\n\t\tthis.listenTo( editor.model, 'applyOperation', ( evt, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\t// Do not register batch if the operation is not a document operation.\n\t\t\t// This prevents from creating empty undo steps, where all operations where non-document operations.\n\t\t\t// Non-document operations creates and alters content in detached tree fragments (for example, document fragments).\n\t\t\t// Most of time this is preparing data before it is inserted into actual tree (for example during copy & paste).\n\t\t\t// Such operations should not be reversed.\n\t\t\tif ( !operation.isDocumentOperation ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst batch = operation.batch;\n\n\t\t\tconst isRedoBatch = this._redoCommand._createdBatches.has( batch );\n\t\t\tconst isUndoBatch = this._undoCommand._createdBatches.has( batch );\n\t\t\tconst isRegisteredBatch = this._batchRegistry.has( batch );\n\n\t\t\t// If changes are not a part of a batch or this is not a new batch, omit those changes.\n\t\t\tif ( isRegisteredBatch || ( batch.type == 'transparent' && !isRedoBatch && !isUndoBatch ) ) {\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\tif ( isRedoBatch ) {\n\t\t\t\t\t// If this batch comes from `redoCommand`, add it to `undoCommand` stack.\n\t\t\t\t\tthis._undoCommand.addBatch( batch );\n\t\t\t\t} else if ( !isUndoBatch ) {\n\t\t\t\t\t// A default batch - these are new changes in the document, not introduced by undo feature.\n\t\t\t\t\t// Add them to `undoCommand` stack and clear `redoCommand` stack.\n\t\t\t\t\tthis._undoCommand.addBatch( batch );\n\t\t\t\t\tthis._redoCommand.clearStack();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add the batch to the registry so it will not be processed again.\n\t\t\tthis._batchRegistry.add( batch );\n\t\t}, { priority: 'highest' } );\n\n\t\tthis.listenTo( this._undoCommand, 'revert', ( evt, undoneBatch, undoingBatch ) => {\n\t\t\tthis._redoCommand.addBatch( undoingBatch );\n\t\t} );\n\n\t\teditor.keystrokes.set( 'CTRL+Z', 'undo' );\n\t\teditor.keystrokes.set( 'CTRL+Y', 'redo' );\n\t\teditor.keystrokes.set( 'CTRL+SHIFT+Z', 'redo' );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M5.042 9.367l2.189 1.837a.75.75 0 0 1-.965 1.149l-3.788-3.18a.747.747 0 0 1-.21-.284.75.75 0 0 1 .17-.945L6.23 4.762a.75.75 0 1 1 .964 1.15L4.863 7.866h8.917A.75.75 0 0 1 14 7.9a4 4 0 1 1-1.477 7.718l.344-1.489a2.5 2.5 0 1 0 1.094-4.73l.008-.032H5.042z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M14.958 9.367l-2.189 1.837a.75.75 0 0 0 .965 1.149l3.788-3.18a.747.747 0 0 0 .21-.284.75.75 0 0 0-.17-.945L13.77 4.762a.75.75 0 1 0-.964 1.15l2.331 1.955H6.22A.75.75 0 0 0 6 7.9a4 4 0 1 0 1.477 7.718l-.344-1.489A2.5 2.5 0 1 1 6.039 9.4l-.008-.032h8.927z\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module undo/undoui\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\n\nimport undoIcon from '../theme/icons/undo.svg';\nimport redoIcon from '../theme/icons/redo.svg';\n\n/**\n * The undo UI feature. It introduces the `'undo'` and `'redo'` buttons to the editor.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class UndoUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst locale = editor.locale;\n\t\tconst t = editor.t;\n\n\t\tconst localizedUndoIcon = locale.uiLanguageDirection == 'ltr' ? undoIcon : redoIcon;\n\t\tconst localizedRedoIcon = locale.uiLanguageDirection == 'ltr' ? redoIcon : undoIcon;\n\n\t\tthis._addButton( 'undo', t( 'Undo' ), 'CTRL+Z', localizedUndoIcon );\n\t\tthis._addButton( 'redo', t( 'Redo' ), 'CTRL+Y', localizedRedoIcon );\n\t}\n\n\t/**\n\t * Creates a button for the specified command.\n\t *\n\t * @private\n\t * @param {String} name Command name.\n\t * @param {String} label Button label.\n\t * @param {String} keystroke Command keystroke.\n\t * @param {String} Icon Source of the icon.\n\t */\n\t_addButton( name, label, keystroke, Icon ) {\n\t\tconst editor = this.editor;\n\n\t\teditor.ui.componentFactory.add( name, locale => {\n\t\t\tconst command = editor.commands.get( name );\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel,\n\t\t\t\ticon: Icon,\n\t\t\t\tkeystroke,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isEnabled' ).to( command, 'isEnabled' );\n\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\teditor.execute( name );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module undo/undo\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport UndoEditing from './undoediting';\nimport UndoUI from './undoui';\n\n/**\n * The undo feature.\n *\n * This is a \"glue\" plugin which loads the {@link module:undo/undoediting~UndoEditing undo editing feature}\n * and {@link module:undo/undoui~UndoUI undo UI feature}.\n *\n * Below is the explanation of the undo mechanism working together with {@link module:engine/model/history~History History}:\n *\n * Whenever a {@link module:engine/model/operation/operation~Operation operation} is applied to the\n * {@link module:engine/model/document~Document document}, it is saved to `History` as is.\n * The {@link module:engine/model/batch~Batch batch} that owns that operation is also saved, in\n * {@link module:undo/undocommand~UndoCommand}, together with the selection that was present in the document before the\n * operation was applied. A batch is saved instead of the operation because changes are undone batch-by-batch, not operation-by-operation\n * and a batch is seen as one undo step.\n *\n * After some changes happen to the document, the `History` and `UndoCommand` stack can be represented as follows:\n *\n *\t\t    History                            Undo stack\n *\t\t==============             ==================================\n *\t\t[operation A1]                         [batch A]\n *\t\t[operation B1]                         [batch B]\n *\t\t[operation B2]                         [batch C]\n *\t\t[operation C1]\n *\t\t[operation C2]\n *\t\t[operation B3]\n *\t\t[operation C3]\n *\n * Where operations starting with the same letter are from same batch.\n *\n * Undoing a batch means that a set of operations which will reverse the effects of that batch needs to be generated.\n * For example, if a batch added several letters, undoing the batch should remove them. It is important to apply undoing\n * operations in the reversed order, so if a batch has operation `X`, `Y`, `Z`, reversed operations `Zr`, `Yr` and `Xr`\n * need to be applied. Otherwise reversed operation `Xr` would operate on a wrong document state, because operation `X`\n * does not know that operations `Y` and `Z` happened.\n *\n * After operations from an undone batch got {@link module:engine/model/operation/operation~Operation#getReversed reversed},\n * one needs to make sure if they are ready to be applied. In the scenario above, operation `C3` is the last operation and `C3r`\n * bases on up-to-date document state, so it can be applied to the document.\n *\n *\t\t     History                             Undo stack\n *\t\t=================             ==================================\n *\t\t[ operation A1  ]                      [  batch A  ]\n *\t\t[ operation B1  ]                      [  batch B  ]\n *\t\t[ operation B2  ]             [   processing undoing batch C   ]\n *\t\t[ operation C1  ]\n *\t\t[ operation C2  ]\n *\t\t[ operation B3  ]\n *\t\t[ operation C3  ]\n *\t\t[ operation C3r ]\n *\n * Next is operation `C2`, reversed to `C2r`. `C2r` bases on `C2`, so it bases on the wrong document state. It needs to be\n * transformed by operations from history that happened after it, so it \"knows\" about them. Let us assume that `C2' = C2r * B3 * C3 * C3r`,\n * where `*` means \"transformed by\". Rest of operations from that batch are processed in the same fashion.\n *\n *\t\t     History                             Undo stack                                      Redo stack\n *\t\t=================             ==================================             ==================================\n *\t\t[ operation A1  ]                      [  batch A  ]                                    [ batch Cr ]\n *\t\t[ operation B1  ]                      [  batch B  ]\n *\t\t[ operation B2  ]\n *\t\t[ operation C1  ]\n *\t\t[ operation C2  ]\n *\t\t[ operation B3  ]\n *\t\t[ operation C3  ]\n *\t\t[ operation C3r ]\n *\t\t[ operation C2' ]\n *\t\t[ operation C1' ]\n *\n * Selective undo works on the same basis, however, instead of undoing the last batch in the undo stack, any batch can be undone.\n * The same algorithm applies: operations from a batch (i.e. `A1`) are reversed and then transformed by operations stored in history.\n *\n * Redo also is very similar to undo. It has its own stack that is filled with undoing (reversed batches). Operations from\n * batch that is re-done are reversed-back, transformed in proper order and applied to the document.\n *\n *\t\t     History                             Undo stack                                      Redo stack\n *\t\t=================             ==================================             ==================================\n *\t\t[ operation A1  ]                      [  batch A  ]\n *\t\t[ operation B1  ]                      [  batch B  ]\n *\t\t[ operation B2  ]                      [ batch Crr ]\n *\t\t[ operation C1  ]\n *\t\t[ operation C2  ]\n *\t\t[ operation B3  ]\n *\t\t[ operation C3  ]\n *\t\t[ operation C3r ]\n *\t\t[ operation C2' ]\n *\t\t[ operation C1' ]\n *\t\t[ operation C1'r]\n *\t\t[ operation C2'r]\n *\t\t[ operation C3rr]\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Undo extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ UndoEditing, UndoUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Undo';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module core/contextplugin\n */\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * The base class for {@link module:core/context~Context} plugin classes.\n *\n * A context plugin can either be initialized for an {@link module:core/editor/editor~Editor editor} or for\n * a {@link module:core/context~Context context}. In other words, it can either\n * work within one editor instance or with one or more editor instances that use a single context.\n * It is the context plugin's role to implement handling for both modes.\n *\n * There are a few rules for interaction between the editor plugins and context plugins:\n *\n * * A context plugin can require another context plugin.\n * * An {@link module:core/plugin~Plugin editor plugin} can require a context plugin.\n * * A context plugin MUST NOT require an {@link module:core/plugin~Plugin editor plugin}.\n *\n * @implements module:core/plugin~PluginInterface\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class ContextPlugin {\n\t/**\n\t * Creates a new plugin instance.\n\t *\n\t * @param {module:core/context~Context|module:core/editor/editor~Editor} context\n\t */\n\tconstructor( context ) {\n\t\t/**\n\t\t * The context instance.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:core/context~Context|module:core/editor/editor~Editor}\n\t\t */\n\t\tthis.context = context;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get isContextPlugin() {\n\t\treturn true;\n\t}\n}\n\nmix( ContextPlugin, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module core/pendingactions\n */\n\nimport ContextPlugin from './contextplugin';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * The list of pending editor actions.\n *\n * This plugin should be used to synchronise plugins that execute long-lasting actions\n * (e.g. file upload) with the editor integration. It gives the developer who integrates the editor\n * an easy way to check if there are any actions pending whenever such information is needed.\n * All plugins that register a pending action also provide a message about the action that is ongoing\n * which can be displayed to the user. This lets them decide if they want to interrupt the action or wait.\n *\n * Adding and updating a pending action:\n *\n * \t\tconst pendingActions = editor.plugins.get( 'PendingActions' );\n * \t\tconst action = pendingActions.add( 'Upload in progress: 0%.' );\n *\n *\t\t// You can update the message:\n * \t\taction.message = 'Upload in progress: 10%.';\n *\n * Removing a pending action:\n *\n * \t\tconst pendingActions = editor.plugins.get( 'PendingActions' );\n * \t\tconst action = pendingActions.add( 'Unsaved changes.' );\n *\n * \t\tpendingActions.remove( action );\n *\n * Getting pending actions:\n *\n * \t\tconst pendingActions = editor.plugins.get( 'PendingActions' );\n *\n * \t\tconst action1 = pendingActions.add( 'Action 1' );\n * \t\tconst action2 = pendingActions.add( 'Action 2' );\n *\n * \t\tpendingActions.first; // Returns action1\n * \t\tArray.from( pendingActions ); // Returns [ action1, action2 ]\n *\n * This plugin is used by features like {@link module:upload/filerepository~FileRepository} to register their ongoing actions\n * and by features like {@link module:autosave/autosave~Autosave} to detect whether there are any ongoing actions.\n * Read more about saving the data in the {@glink builds/guides/integration/saving-data Saving and getting data} guide.\n *\n * @extends module:core/contextplugin~ContextPlugin\n */\nexport default class PendingActions extends ContextPlugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'PendingActions';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\t/**\n\t\t * Defines whether there is any registered pending action.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #hasAny\n\t\t */\n\t\tthis.set( 'hasAny', false );\n\n\t\t/**\n\t\t * A list of pending actions.\n\t\t *\n\t\t * @private\n\t\t * @type {module:utils/collection~Collection}\n\t\t */\n\t\tthis._actions = new Collection( { idProperty: '_id' } );\n\t\tthis._actions.delegate( 'add', 'remove' ).to( this );\n\t}\n\n\t/**\n\t * Adds an action to the list of pending actions.\n\t *\n\t * This method returns an action object with an observable message property.\n\t * The action object can be later used in the {@link #remove} method. It also allows you to change the message.\n\t *\n\t * @param {String} message The action message.\n\t * @returns {Object} An observable object that represents a pending action.\n\t */\n\tadd( message ) {\n\t\tif ( typeof message !== 'string' ) {\n\t\t\t/**\n\t\t\t * The message must be a string.\n\t\t\t *\n\t\t\t * @error pendingactions-add-invalid-message\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'pendingactions-add-invalid-message', this );\n\t\t}\n\n\t\tconst action = Object.create( ObservableMixin );\n\n\t\taction.set( 'message', message );\n\t\tthis._actions.add( action );\n\t\tthis.hasAny = true;\n\n\t\treturn action;\n\t}\n\n\t/**\n\t * Removes an action from the list of pending actions.\n\t *\n\t * @param {Object} action An action object.\n\t */\n\tremove( action ) {\n\t\tthis._actions.remove( action );\n\t\tthis.hasAny = !!this._actions.length;\n\t}\n\n\t/**\n\t * Returns the first action from the list or null when list is empty\n\t *\n\t * returns {Object|null} The pending action object.\n\t */\n\tget first() {\n\t\treturn this._actions.get( 0 );\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._actions[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Fired when an action is added to the list.\n\t *\n\t * @event add\n\t * @param {Object} action The added action.\n\t */\n\n\t/**\n\t * Fired when an action is removed from the list.\n\t *\n\t * @event remove\n\t * @param {Object} action The removed action.\n\t */\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module upload/filereader\n */\n\n/* globals window */\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Wrapper over the native `FileReader`.\n */\nexport default class FileReader {\n\t/**\n\t * Creates an instance of the FileReader.\n\t */\n\tconstructor() {\n\t\tconst reader = new window.FileReader();\n\n\t\t/**\n\t\t * Instance of native FileReader.\n\t\t *\n\t\t * @private\n\t\t * @member {FileReader} #_reader\n\t\t */\n\t\tthis._reader = reader;\n\n\t\tthis._data = undefined;\n\n\t\t/**\n\t\t * Number of bytes loaded.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number} #loaded\n\t\t */\n\t\tthis.set( 'loaded', 0 );\n\n\t\treader.onprogress = evt => {\n\t\t\tthis.loaded = evt.loaded;\n\t\t};\n\t}\n\n\t/**\n\t * Returns error that occurred during file reading.\n\t *\n\t * @returns {Error}\n\t */\n\tget error() {\n\t\treturn this._reader.error;\n\t}\n\n\t/**\n\t * Holds the data of an already loaded file. The file must be first loaded\n\t * by using {@link module:upload/filereader~FileReader#read `read()`}.\n\t *\n\t * @type {File|undefined}\n\t */\n\tget data() {\n\t\treturn this._data;\n\t}\n\n\t/**\n\t * Reads the provided file.\n\t *\n\t * @param {File} file Native File object.\n\t * @returns {Promise.<String>} Returns a promise that will be resolved with file's content.\n\t * The promise will be rejected in case of an error or when the reading process is aborted.\n\t */\n\tread( file ) {\n\t\tconst reader = this._reader;\n\t\tthis.total = file.size;\n\n\t\treturn new Promise( ( resolve, reject ) => {\n\t\t\treader.onload = () => {\n\t\t\t\tconst result = reader.result;\n\n\t\t\t\tthis._data = result;\n\n\t\t\t\tresolve( result );\n\t\t\t};\n\n\t\t\treader.onerror = () => {\n\t\t\t\treject( 'error' );\n\t\t\t};\n\n\t\t\treader.onabort = () => {\n\t\t\t\treject( 'aborted' );\n\t\t\t};\n\n\t\t\tthis._reader.readAsDataURL( file );\n\t\t} );\n\t}\n\n\t/**\n\t * Aborts file reader.\n\t */\n\tabort() {\n\t\tthis._reader.abort();\n\t}\n}\n\nmix( FileReader, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module upload/filerepository\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport PendingActions from '@ckeditor/ckeditor5-core/src/pendingactions';\nimport CKEditorError, { logWarning } from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\nimport FileReader from './filereader.js';\n\nimport uid from '@ckeditor/ckeditor5-utils/src/uid.js';\n\n/**\n * File repository plugin. A central point for managing file upload.\n *\n * To use it, first you need an upload adapter. Upload adapter's job is to handle communication with the server\n * (sending the file and handling server's response). You can use one of the existing plugins introducing upload adapters\n * (e.g. {@link module:easy-image/cloudservicesuploadadapter~CloudServicesUploadAdapter} or\n * {@link module:adapter-ckfinder/uploadadapter~CKFinderUploadAdapter}) or write your own one – see\n * the {@glink framework/guides/deep-dive/upload-adapter \"Custom image upload adapter\" deep dive guide}.\n *\n * Then, you can use {@link module:upload/filerepository~FileRepository#createLoader `createLoader()`} and the returned\n * {@link module:upload/filerepository~FileLoader} instance to load and upload files.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FileRepository extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FileRepository';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ PendingActions ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\t/**\n\t\t * Collection of loaders associated with this repository.\n\t\t *\n\t\t * @member {module:utils/collection~Collection} #loaders\n\t\t */\n\t\tthis.loaders = new Collection();\n\n\t\t// Keeps upload in a sync with pending actions.\n\t\tthis.loaders.on( 'add', () => this._updatePendingAction() );\n\t\tthis.loaders.on( 'remove', () => this._updatePendingAction() );\n\n\t\t/**\n\t\t * Loaders mappings used to retrieve loaders references.\n\t\t *\n\t\t * @private\n\t\t * @member {Map<File|Promise, FileLoader>} #_loadersMap\n\t\t */\n\t\tthis._loadersMap = new Map();\n\n\t\t/**\n\t\t * Reference to a pending action registered in a {@link module:core/pendingactions~PendingActions} plugin\n\t\t * while upload is in progress. When there is no upload then value is `null`.\n\t\t *\n\t\t * @private\n\t\t * @member {Object} #_pendingAction\n\t\t */\n\t\tthis._pendingAction = null;\n\n\t\t/**\n\t\t * A factory function which should be defined before using `FileRepository`.\n\t\t *\n\t\t * It should return a new instance of {@link module:upload/filerepository~UploadAdapter} that will be used to upload files.\n\t\t * {@link module:upload/filerepository~FileLoader} instance associated with the adapter\n\t\t * will be passed to that function.\n\t\t *\n\t\t * For more information and example see {@link module:upload/filerepository~UploadAdapter}.\n\t\t *\n\t\t * @member {Function} #createUploadAdapter\n\t\t */\n\n\t\t/**\n\t\t * Number of bytes uploaded.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number} #uploaded\n\t\t */\n\t\tthis.set( 'uploaded', 0 );\n\n\t\t/**\n\t\t * Number of total bytes to upload.\n\t\t *\n\t\t * It might be different than the file size because of headers and additional data.\n\t\t * It contains `null` if value is not available yet, so it's better to use {@link #uploadedPercent} to monitor\n\t\t * the progress.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number|null} #uploadTotal\n\t\t */\n\t\tthis.set( 'uploadTotal', null );\n\n\t\t/**\n\t\t * Upload progress in percents.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number} #uploadedPercent\n\t\t */\n\t\tthis.bind( 'uploadedPercent' ).to( this, 'uploaded', this, 'uploadTotal', ( uploaded, total ) => {\n\t\t\treturn total ? ( uploaded / total * 100 ) : 0;\n\t\t} );\n\t}\n\n\t/**\n\t * Returns the loader associated with specified file or promise.\n\t *\n\t * To get loader by id use `fileRepository.loaders.get( id )`.\n\t *\n\t * @param {File|Promise.<File>} fileOrPromise Native file or promise handle.\n\t * @returns {module:upload/filerepository~FileLoader|null}\n\t */\n\tgetLoader( fileOrPromise ) {\n\t\treturn this._loadersMap.get( fileOrPromise ) || null;\n\t}\n\n\t/**\n\t * Creates a loader instance for the given file.\n\t *\n\t * Requires {@link #createUploadAdapter} factory to be defined.\n\t *\n\t * @param {File|Promise.<File>} fileOrPromise Native File object or native Promise object which resolves to a File.\n\t * @returns {module:upload/filerepository~FileLoader|null}\n\t */\n\tcreateLoader( fileOrPromise ) {\n\t\tif ( !this.createUploadAdapter ) {\n\t\t\t/**\n\t\t\t * You need to enable an upload adapter in order to be able to upload files.\n\t\t\t *\n\t\t\t * This warning shows up when {@link module:upload/filerepository~FileRepository} is being used\n\t\t\t * without {@link #createUploadAdapter definining an upload adapter}.\n\t\t\t *\n\t\t\t * **If you see this warning when using one of the {@glink builds/index CKEditor 5 Builds}**\n\t\t\t * it means that you did not configure any of the upload adapters available by default in those builds.\n\t\t\t *\n\t\t\t * See the {@glink features/image-upload/image-upload comprehensive \"Image upload overview\"} to learn which upload\n\t\t\t * adapters are available in the builds and how to configure them.\n\t\t\t *\n\t\t\t * **If you see this warning when using a custom build** there is a chance that you enabled\n\t\t\t * a feature like {@link module:image/imageupload~ImageUpload},\n\t\t\t * or {@link module:image/imageupload/imageuploadui~ImageUploadUI} but you did not enable any upload adapter.\n\t\t\t * You can choose one of the existing upload adapters listed in the\n\t\t\t * {@glink features/image-upload/image-upload \"Image upload overview\"}.\n\t\t\t *\n\t\t\t * You can also implement your {@glink framework/guides/deep-dive/upload-adapter own image upload adapter}.\n\t\t\t *\n\t\t\t * @error filerepository-no-upload-adapter\n\t\t\t */\n\t\t\tlogWarning( 'filerepository-no-upload-adapter' );\n\n\t\t\treturn null;\n\t\t}\n\n\t\tconst loader = new FileLoader( Promise.resolve( fileOrPromise ), this.createUploadAdapter );\n\n\t\tthis.loaders.add( loader );\n\t\tthis._loadersMap.set( fileOrPromise, loader );\n\n\t\t// Store also file => loader mapping so loader can be retrieved by file instance returned upon Promise resolution.\n\t\tif ( fileOrPromise instanceof Promise ) {\n\t\t\tloader.file\n\t\t\t\t.then( file => {\n\t\t\t\t\tthis._loadersMap.set( file, loader );\n\t\t\t\t} )\n\t\t\t\t// Every then() must have a catch().\n\t\t\t\t// File loader state (and rejections) are handled in read() and upload().\n\t\t\t\t// Also, see the \"does not swallow the file promise rejection\" test.\n\t\t\t\t.catch( () => {} );\n\t\t}\n\n\t\tloader.on( 'change:uploaded', () => {\n\t\t\tlet aggregatedUploaded = 0;\n\n\t\t\tfor ( const loader of this.loaders ) {\n\t\t\t\taggregatedUploaded += loader.uploaded;\n\t\t\t}\n\n\t\t\tthis.uploaded = aggregatedUploaded;\n\t\t} );\n\n\t\tloader.on( 'change:uploadTotal', () => {\n\t\t\tlet aggregatedTotal = 0;\n\n\t\t\tfor ( const loader of this.loaders ) {\n\t\t\t\tif ( loader.uploadTotal ) {\n\t\t\t\t\taggregatedTotal += loader.uploadTotal;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.uploadTotal = aggregatedTotal;\n\t\t} );\n\n\t\treturn loader;\n\t}\n\n\t/**\n\t * Destroys the given loader.\n\t *\n\t * @param {File|Promise|module:upload/filerepository~FileLoader} fileOrPromiseOrLoader File or Promise associated\n\t * with that loader or loader itself.\n\t */\n\tdestroyLoader( fileOrPromiseOrLoader ) {\n\t\tconst loader = fileOrPromiseOrLoader instanceof FileLoader ? fileOrPromiseOrLoader : this.getLoader( fileOrPromiseOrLoader );\n\n\t\tloader._destroy();\n\n\t\tthis.loaders.remove( loader );\n\n\t\tthis._loadersMap.forEach( ( value, key ) => {\n\t\t\tif ( value === loader ) {\n\t\t\t\tthis._loadersMap.delete( key );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Registers or deregisters pending action bound with upload progress.\n\t *\n\t * @private\n\t */\n\t_updatePendingAction() {\n\t\tconst pendingActions = this.editor.plugins.get( PendingActions );\n\n\t\tif ( this.loaders.length ) {\n\t\t\tif ( !this._pendingAction ) {\n\t\t\t\tconst t = this.editor.t;\n\t\t\t\tconst getMessage = value => `${ t( 'Upload in progress' ) } ${ parseInt( value ) }%.`;\n\n\t\t\t\tthis._pendingAction = pendingActions.add( getMessage( this.uploadedPercent ) );\n\t\t\t\tthis._pendingAction.bind( 'message' ).to( this, 'uploadedPercent', getMessage );\n\t\t\t}\n\t\t} else {\n\t\t\tpendingActions.remove( this._pendingAction );\n\t\t\tthis._pendingAction = null;\n\t\t}\n\t}\n}\n\nmix( FileRepository, ObservableMixin );\n\n/**\n * File loader class.\n *\n * It is used to control the process of reading the file and uploading it using the specified upload adapter.\n */\nclass FileLoader {\n\t/**\n\t * Creates a new instance of `FileLoader`.\n\t *\n\t * @param {Promise.<File>} filePromise A promise which resolves to a file instance.\n\t * @param {Function} uploadAdapterCreator The function which returns {@link module:upload/filerepository~UploadAdapter} instance.\n\t */\n\tconstructor( filePromise, uploadAdapterCreator ) {\n\t\t/**\n\t\t * Unique id of FileLoader instance.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.id = uid();\n\n\t\t/**\n\t\t * Additional wrapper over the initial file promise passed to this loader.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:upload/filerepository~FilePromiseWrapper}\n\t\t */\n\t\tthis._filePromiseWrapper = this._createFilePromiseWrapper( filePromise );\n\n\t\t/**\n\t\t * Adapter instance associated with this file loader.\n\t\t *\n\t\t * @private\n\t\t * @member {module:upload/filerepository~UploadAdapter}\n\t\t */\n\t\tthis._adapter = uploadAdapterCreator( this );\n\n\t\t/**\n\t\t * FileReader used by FileLoader.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:upload/filereader~FileReader}\n\t\t */\n\t\tthis._reader = new FileReader();\n\n\t\t/**\n\t\t * Current status of FileLoader. It can be one of the following:\n\t\t *\n\t\t * * 'idle',\n\t\t * * 'reading',\n\t\t * * 'uploading',\n\t\t * * 'aborted',\n\t\t * * 'error'.\n\t\t *\n\t\t * When reading status can change in a following way:\n\t\t *\n\t\t * `idle` -> `reading` -> `idle`\n\t\t * `idle` -> `reading -> `aborted`\n\t\t * `idle` -> `reading -> `error`\n\t\t *\n\t\t * When uploading status can change in a following way:\n\t\t *\n\t\t * `idle` -> `uploading` -> `idle`\n\t\t * `idle` -> `uploading` -> `aborted`\n\t\t * `idle` -> `uploading` -> `error`\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {String} #status\n\t\t */\n\t\tthis.set( 'status', 'idle' );\n\n\t\t/**\n\t\t * Number of bytes uploaded.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number} #uploaded\n\t\t */\n\t\tthis.set( 'uploaded', 0 );\n\n\t\t/**\n\t\t * Number of total bytes to upload.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number|null} #uploadTotal\n\t\t */\n\t\tthis.set( 'uploadTotal', null );\n\n\t\t/**\n\t\t * Upload progress in percents.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number} #uploadedPercent\n\t\t */\n\t\tthis.bind( 'uploadedPercent' ).to( this, 'uploaded', this, 'uploadTotal', ( uploaded, total ) => {\n\t\t\treturn total ? ( uploaded / total * 100 ) : 0;\n\t\t} );\n\n\t\t/**\n\t\t * Response of the upload.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Object|null} #uploadResponse\n\t\t */\n\t\tthis.set( 'uploadResponse', null );\n\t}\n\n\t/**\n\t * A `Promise` which resolves to a `File` instance associated with this file loader.\n\t *\n\t * @type {Promise.<File|null>}\n\t */\n\tget file() {\n\t\tif ( !this._filePromiseWrapper ) {\n\t\t\t// Loader was destroyed, return promise which resolves to null.\n\t\t\treturn Promise.resolve( null );\n\t\t} else {\n\t\t\t// The `this._filePromiseWrapper.promise` is chained and not simply returned to handle a case when:\n\t\t\t//\n\t\t\t//\t\t* The `loader.file.then( ... )` is called by external code (returned promise is pending).\n\t\t\t//\t\t* Then `loader._destroy()` is called (call is synchronous) which destroys the `loader`.\n\t\t\t//\t\t* Promise returned by the first `loader.file.then( ... )` call is resolved.\n\t\t\t//\n\t\t\t// Returning `this._filePromiseWrapper.promise` will still resolve to a `File` instance so there\n\t\t\t// is an additional check needed in the chain to see if `loader` was destroyed in the meantime.\n\t\t\treturn this._filePromiseWrapper.promise.then( file => this._filePromiseWrapper ? file : null );\n\t\t}\n\t}\n\n\t/**\n\t * Returns the file data. To read its data, you need for first load the file\n\t * by using the {@link module:upload/filerepository~FileLoader#read `read()`} method.\n\t *\n\t * @type {File|undefined}\n\t */\n\tget data() {\n\t\treturn this._reader.data;\n\t}\n\n\t/**\n\t * Reads file using {@link module:upload/filereader~FileReader}.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `filerepository-read-wrong-status` when status\n\t * is different than `idle`.\n\t *\n\t * Example usage:\n\t *\n\t *\tfileLoader.read()\n\t *\t\t.then( data => { ... } )\n\t *\t\t.catch( err => {\n\t *\t\t\tif ( err === 'aborted' ) {\n\t *\t\t\t\tconsole.log( 'Reading aborted.' );\n\t *\t\t\t} else {\n\t *\t\t\t\tconsole.log( 'Reading error.', err );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * @returns {Promise.<String>} Returns promise that will be resolved with read data. Promise will be rejected if error\n\t * occurs or if read process is aborted.\n\t */\n\tread() {\n\t\tif ( this.status != 'idle' ) {\n\t\t\t/**\n\t\t\t * You cannot call read if the status is different than idle.\n\t\t\t *\n\t\t\t * @error filerepository-read-wrong-status\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'filerepository-read-wrong-status', this );\n\t\t}\n\n\t\tthis.status = 'reading';\n\n\t\treturn this.file\n\t\t\t.then( file => this._reader.read( file ) )\n\t\t\t.then( data => {\n\t\t\t\t// Edge case: reader was aborted after file was read - double check for proper status.\n\t\t\t\t// It can happen when image was deleted during its upload.\n\t\t\t\tif ( this.status !== 'reading' ) {\n\t\t\t\t\tthrow this.status;\n\t\t\t\t}\n\n\t\t\t\tthis.status = 'idle';\n\n\t\t\t\treturn data;\n\t\t\t} )\n\t\t\t.catch( err => {\n\t\t\t\tif ( err === 'aborted' ) {\n\t\t\t\t\tthis.status = 'aborted';\n\t\t\t\t\tthrow 'aborted';\n\t\t\t\t}\n\n\t\t\t\tthis.status = 'error';\n\t\t\t\tthrow this._reader.error ? this._reader.error : err;\n\t\t\t} );\n\t}\n\n\t/**\n\t * Reads file using the provided {@link module:upload/filerepository~UploadAdapter}.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `filerepository-upload-wrong-status` when status\n\t * is different than `idle`.\n\t * Example usage:\n\t *\n\t *\tfileLoader.upload()\n\t *\t\t.then( data => { ... } )\n\t *\t\t.catch( e => {\n\t *\t\t\tif ( e === 'aborted' ) {\n\t *\t\t\t\tconsole.log( 'Uploading aborted.' );\n\t *\t\t\t} else {\n\t *\t\t\t\tconsole.log( 'Uploading error.', e );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * @returns {Promise.<Object>} Returns promise that will be resolved with response data. Promise will be rejected if error\n\t * occurs or if read process is aborted.\n\t */\n\tupload() {\n\t\tif ( this.status != 'idle' ) {\n\t\t\t/**\n\t\t\t * You cannot call upload if the status is different than idle.\n\t\t\t *\n\t\t\t * @error filerepository-upload-wrong-status\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'filerepository-upload-wrong-status', this );\n\t\t}\n\n\t\tthis.status = 'uploading';\n\n\t\treturn this.file\n\t\t\t.then( () => this._adapter.upload() )\n\t\t\t.then( data => {\n\t\t\t\tthis.uploadResponse = data;\n\t\t\t\tthis.status = 'idle';\n\n\t\t\t\treturn data;\n\t\t\t} )\n\t\t\t.catch( err => {\n\t\t\t\tif ( this.status === 'aborted' ) {\n\t\t\t\t\tthrow 'aborted';\n\t\t\t\t}\n\n\t\t\t\tthis.status = 'error';\n\t\t\t\tthrow err;\n\t\t\t} );\n\t}\n\n\t/**\n\t * Aborts loading process.\n\t */\n\tabort() {\n\t\tconst status = this.status;\n\t\tthis.status = 'aborted';\n\n\t\tif ( !this._filePromiseWrapper.isFulfilled ) {\n\t\t\t// Edge case: file loader is aborted before read() is called\n\t\t\t// so it might happen that no one handled the rejection of this promise.\n\t\t\t// See https://github.com/ckeditor/ckeditor5-upload/pull/100\n\t\t\tthis._filePromiseWrapper.promise.catch( () => {} );\n\n\t\t\tthis._filePromiseWrapper.rejecter( 'aborted' );\n\t\t} else if ( status == 'reading' ) {\n\t\t\tthis._reader.abort();\n\t\t} else if ( status == 'uploading' && this._adapter.abort ) {\n\t\t\tthis._adapter.abort();\n\t\t}\n\n\t\tthis._destroy();\n\t}\n\n\t/**\n\t * Performs cleanup.\n\t *\n\t * @private\n\t */\n\t_destroy() {\n\t\tthis._filePromiseWrapper = undefined;\n\t\tthis._reader = undefined;\n\t\tthis._adapter = undefined;\n\t\tthis.uploadResponse = undefined;\n\t}\n\n\t/**\n\t * Wraps a given file promise into another promise giving additional\n\t * control (resolving, rejecting, checking if fulfilled) over it.\n\t *\n\t * @private\n\t * @param filePromise The initial file promise to be wrapped.\n\t * @returns {module:upload/filerepository~FilePromiseWrapper}\n\t */\n\t_createFilePromiseWrapper( filePromise ) {\n\t\tconst wrapper = {};\n\n\t\twrapper.promise = new Promise( ( resolve, reject ) => {\n\t\t\twrapper.rejecter = reject;\n\t\t\twrapper.isFulfilled = false;\n\n\t\t\tfilePromise\n\t\t\t\t.then( file => {\n\t\t\t\t\twrapper.isFulfilled = true;\n\t\t\t\t\tresolve( file );\n\t\t\t\t} )\n\t\t\t\t.catch( err => {\n\t\t\t\t\twrapper.isFulfilled = true;\n\t\t\t\t\treject( err );\n\t\t\t\t} );\n\t\t} );\n\n\t\treturn wrapper;\n\t}\n}\n\nmix( FileLoader, ObservableMixin );\n\n/**\n * Upload adapter interface used by the {@link module:upload/filerepository~FileRepository file repository}\n * to handle file upload. An upload adapter is a bridge between the editor and server that handles file uploads.\n * It should contain a logic necessary to initiate an upload process and monitor its progress.\n *\n * Learn how to develop your own upload adapter for CKEditor 5 in the\n * {@glink framework/guides/deep-dive/upload-adapter \"Custom upload adapter\" guide}.\n *\n * @interface UploadAdapter\n */\n\n/**\n * Executes the upload process.\n * This method should return a promise that will resolve when data will be uploaded to server. Promise should be\n * resolved with an object containing information about uploaded file:\n *\n *\t\t{\n *\t\t\tdefault: 'http://server/default-size.image.png'\n *\t\t}\n *\n * Additionally, other image sizes can be provided:\n *\n *\t\t{\n *\t\t\tdefault: 'http://server/default-size.image.png',\n *\t\t\t'160': 'http://server/size-160.image.png',\n *\t\t\t'500': 'http://server/size-500.image.png',\n *\t\t\t'1000': 'http://server/size-1000.image.png',\n *\t\t\t'1052': 'http://server/default-size.image.png'\n *\t\t}\n *\n * NOTE: When returning multiple images, the widest returned one should equal the default one. It is essential to\n * correctly set `width` attribute of the image. See this discussion:\n * https://github.com/ckeditor/ckeditor5-easy-image/issues/4 for more information.\n *\n * Take a look at {@link module:upload/filerepository~UploadAdapter example Adapter implementation} and\n * {@link module:upload/filerepository~FileRepository#createUploadAdapter createUploadAdapter method}.\n *\n * @method module:upload/filerepository~UploadAdapter#upload\n * @returns {Promise.<Object>} Promise that should be resolved when data is uploaded.\n */\n\n/**\n * Aborts the upload process.\n * After aborting it should reject promise returned from {@link #upload upload()}.\n *\n * Take a look at {@link module:upload/filerepository~UploadAdapter example Adapter implementation} and\n * {@link module:upload/filerepository~FileRepository#createUploadAdapter createUploadAdapter method}.\n *\n * @method module:upload/filerepository~UploadAdapter#abort\n */\n\n/**\n * Object returned by {@link module:upload/filerepository~FileLoader#_createFilePromiseWrapper} method\n * to add more control over the initial file promise passed to {@link module:upload/filerepository~FileLoader}.\n *\n * @protected\n * @typedef {Object} module:upload/filerepository~FilePromiseWrapper\n * @property {Promise.<File>} promise Wrapper promise which can be chained for further processing.\n * @property {Function} rejecter Rejects the promise when called.\n * @property {Boolean} isFulfilled Whether original promise is already fulfilled.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* globals window, document */\n\n/**\n * @module adapter-ckfinder/utils\n */\n\nconst TOKEN_COOKIE_NAME = 'ckCsrfToken';\nconst TOKEN_LENGTH = 40;\nconst tokenCharset = 'abcdefghijklmnopqrstuvwxyz0123456789';\n\n/**\n * Returns the CSRF token value. The value is a hash stored in `document.cookie`\n * under the `ckCsrfToken` key. The CSRF token can be used to secure the communication\n * between the web browser and the CKFinder server.\n *\n * @returns {String}\n */\nexport function getCsrfToken() {\n\tlet token = getCookie( TOKEN_COOKIE_NAME );\n\n\tif ( !token || token.length != TOKEN_LENGTH ) {\n\t\ttoken = generateToken( TOKEN_LENGTH );\n\t\tsetCookie( TOKEN_COOKIE_NAME, token );\n\t}\n\n\treturn token;\n}\n\n/**\n * Returns the value of the cookie with a given name or `null` if the cookie is not found.\n *\n * @param {String} name\n * @returns {String|null}\n */\nexport function getCookie( name ) {\n\tname = name.toLowerCase();\n\tconst parts = document.cookie.split( ';' );\n\n\tfor ( const part of parts ) {\n\t\tconst pair = part.split( '=' );\n\t\tconst key = decodeURIComponent( pair[ 0 ].trim().toLowerCase() );\n\n\t\tif ( key === name ) {\n\t\t\treturn decodeURIComponent( pair[ 1 ] );\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Sets the value of the cookie with a given name.\n *\n * @param {String} name\n * @param {String} value\n */\nexport function setCookie( name, value ) {\n\tdocument.cookie = encodeURIComponent( name ) + '=' + encodeURIComponent( value ) + ';path=/';\n}\n\n// Generates the CSRF token with the given length.\n//\n// @private\n// @param {Number} length\n// @returns {string}\nfunction generateToken( length ) {\n\tlet result = '';\n\tconst randValues = new Uint8Array( length );\n\n\twindow.crypto.getRandomValues( randValues );\n\n\tfor ( let j = 0; j < randValues.length; j++ ) {\n\t\tconst character = tokenCharset.charAt( randValues[ j ] % tokenCharset.length );\n\t\tresult += Math.random() > 0.5 ? character.toUpperCase() : character;\n\t}\n\n\treturn result;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* globals XMLHttpRequest, FormData */\n\n/**\n * @module adapter-ckfinder/uploadadapter\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport FileRepository from '@ckeditor/ckeditor5-upload/src/filerepository';\nimport { getCsrfToken } from './utils';\n\n/**\n * A plugin that enables file uploads in CKEditor 5 using the CKFinder server–side connector.\n *\n * See the {@glink features/image-upload/ckfinder \"CKFinder file manager integration\" guide} to learn how to configure\n * and use this feature as well as find out more about the full integration with the file manager\n * provided by the {@link module:ckfinder/ckfinder~CKFinder} plugin.\n *\n * Check out the {@glink features/image-upload/image-upload comprehensive \"Image upload overview\"} to learn about\n * other ways to upload images into CKEditor 5.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class CKFinderUploadAdapter extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ FileRepository ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'CKFinderUploadAdapter';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst url = this.editor.config.get( 'ckfinder.uploadUrl' );\n\n\t\tif ( !url ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Register CKFinderAdapter\n\t\tthis.editor.plugins.get( FileRepository ).createUploadAdapter = loader => new UploadAdapter( loader, url, this.editor.t );\n\t}\n}\n\n/**\n * Upload adapter for CKFinder.\n *\n * @private\n * @implements module:upload/filerepository~UploadAdapter\n */\nclass UploadAdapter {\n\t/**\n\t * Creates a new adapter instance.\n\t *\n\t * @param {module:upload/filerepository~FileLoader} loader\n\t * @param {String} url\n\t * @param {module:utils/locale~Locale#t} t\n\t */\n\tconstructor( loader, url, t ) {\n\t\t/**\n\t\t * FileLoader instance to use during the upload.\n\t\t *\n\t\t * @member {module:upload/filerepository~FileLoader} #loader\n\t\t */\n\t\tthis.loader = loader;\n\n\t\t/**\n\t\t * Upload URL.\n\t\t *\n\t\t * @member {String} #url\n\t\t */\n\t\tthis.url = url;\n\n\t\t/**\n\t\t * Locale translation method.\n\t\t *\n\t\t * @member {module:utils/locale~Locale#t} #t\n\t\t */\n\t\tthis.t = t;\n\t}\n\n\t/**\n\t * Starts the upload process.\n\t *\n\t * @see module:upload/filerepository~UploadAdapter#upload\n\t * @returns {Promise.<Object>}\n\t */\n\tupload() {\n\t\treturn this.loader.file.then( file => {\n\t\t\treturn new Promise( ( resolve, reject ) => {\n\t\t\t\tthis._initRequest();\n\t\t\t\tthis._initListeners( resolve, reject, file );\n\t\t\t\tthis._sendRequest( file );\n\t\t\t} );\n\t\t} );\n\t}\n\n\t/**\n\t * Aborts the upload process.\n\t *\n\t * @see module:upload/filerepository~UploadAdapter#abort\n\t */\n\tabort() {\n\t\tif ( this.xhr ) {\n\t\t\tthis.xhr.abort();\n\t\t}\n\t}\n\n\t/**\n\t * Initializes the XMLHttpRequest object.\n\t *\n\t * @private\n\t */\n\t_initRequest() {\n\t\tconst xhr = this.xhr = new XMLHttpRequest();\n\n\t\txhr.open( 'POST', this.url, true );\n\t\txhr.responseType = 'json';\n\t}\n\n\t/**\n\t * Initializes XMLHttpRequest listeners.\n\t *\n\t * @private\n\t * @param {Function} resolve Callback function to be called when the request is successful.\n\t * @param {Function} reject Callback function to be called when the request cannot be completed.\n\t * @param {File} file File instance to be uploaded.\n\t */\n\t_initListeners( resolve, reject, file ) {\n\t\tconst xhr = this.xhr;\n\t\tconst loader = this.loader;\n\t\tconst t = this.t;\n\t\tconst genericError = t( 'Cannot upload file:' ) + ` ${ file.name }.`;\n\n\t\txhr.addEventListener( 'error', () => reject( genericError ) );\n\t\txhr.addEventListener( 'abort', () => reject() );\n\t\txhr.addEventListener( 'load', () => {\n\t\t\tconst response = xhr.response;\n\n\t\t\tif ( !response || !response.uploaded ) {\n\t\t\t\treturn reject( response && response.error && response.error.message ? response.error.message : genericError );\n\t\t\t}\n\n\t\t\tresolve( {\n\t\t\t\tdefault: response.url\n\t\t\t} );\n\t\t} );\n\n\t\t// Upload progress when it's supported.\n\t\t/* istanbul ignore else */\n\t\tif ( xhr.upload ) {\n\t\t\txhr.upload.addEventListener( 'progress', evt => {\n\t\t\t\tif ( evt.lengthComputable ) {\n\t\t\t\t\tloader.uploadTotal = evt.total;\n\t\t\t\t\tloader.uploaded = evt.loaded;\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Prepares the data and sends the request.\n\t *\n\t * @private\n\t * @param {File} file File instance to be uploaded.\n\t */\n\t_sendRequest( file ) {\n\t\t// Prepare form data.\n\t\tconst data = new FormData();\n\t\tdata.append( 'upload', file );\n\t\tdata.append( 'ckCsrfToken', getCsrfToken() );\n\n\t\t// Send request.\n\t\tthis.xhr.send( data );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/first\n */\n\n/**\n * Returns first item of the given `iterable`.\n *\n * @param {Iterable.<*>} iterable\n * @returns {*}\n */\nexport default function first( iterable ) {\n\tconst iteratorItem = iterable.next();\n\n\tif ( iteratorItem.done ) {\n\t\treturn null;\n\t}\n\n\treturn iteratorItem.value;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport LiveRange from '@ckeditor/ckeditor5-engine/src/model/liverange';\nimport first from '@ckeditor/ckeditor5-utils/src/first';\n\n/**\n * The block autoformatting engine. It allows to format various block patterns. For example,\n * it can be configured to turn a paragraph starting with `*` and followed by a space into a list item.\n *\n * The autoformatting operation is integrated with the undo manager,\n * so the autoformatting step can be undone if the user's intention was not to format the text.\n *\n * See the {@link module:autoformat/blockautoformatediting~blockAutoformatEditing `blockAutoformatEditing`} documentation\n * to learn how to create custom block autoformatters. You can also use\n * the {@link module:autoformat/autoformat~Autoformat} feature which enables a set of default autoformatters\n * (lists, headings, bold and italic).\n *\n * @module autoformat/blockautoformatediting\n */\n\n/**\n * Creates a listener triggered on {@link module:engine/model/document~Document#event:change:data `change:data`} event in the document.\n * Calls the callback when inserted text matches the regular expression or the command name\n * if provided instead of the callback.\n *\n * Examples of usage:\n *\n * To convert a paragraph to heading 1 when `- ` is typed, using just the command name:\n *\n *\t\tblockAutoformatEditing( editor, plugin, /^\\- $/, 'heading1' );\n *\n * To convert a paragraph to heading 1 when `- ` is typed, using just the callback:\n *\n *\t\tblockAutoformatEditing( editor, plugin, /^\\- $/, ( context ) => {\n *\t\t\tconst { match } = context;\n *\t\t\tconst headingLevel = match[ 1 ].length;\n *\n *\t\t\teditor.execute( 'heading', {\n *\t\t\t\tformatId: `heading${ headingLevel }`\n *\t\t\t} );\n * \t\t} );\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n * @param {module:autoformat/autoformat~Autoformat} plugin The autoformat plugin instance.\n * @param {RegExp} pattern The regular expression to execute on just inserted text. The regular expression is tested against the text\n * from the beginning until the caret position.\n * @param {Function|String} callbackOrCommand The callback to execute or the command to run when the text is matched.\n * In case of providing the callback, it receives the following parameter:\n * * {Object} match RegExp.exec() result of matching the pattern to inserted text.\n */\nexport default function blockAutoformatEditing( editor, plugin, pattern, callbackOrCommand ) {\n\tlet callback;\n\tlet command = null;\n\n\tif ( typeof callbackOrCommand == 'function' ) {\n\t\tcallback = callbackOrCommand;\n\t} else {\n\t\t// We assume that the actual command name was provided.\n\t\tcommand = editor.commands.get( callbackOrCommand );\n\n\t\tcallback = () => {\n\t\t\teditor.execute( callbackOrCommand );\n\t\t};\n\t}\n\n\teditor.model.document.on( 'change:data', ( evt, batch ) => {\n\t\tif ( command && !command.isEnabled || !plugin.isEnabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst range = first( editor.model.document.selection.getRanges() );\n\n\t\tif ( !range.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( batch.type == 'transparent' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst changes = Array.from( editor.model.document.differ.getChanges() );\n\t\tconst entry = changes[ 0 ];\n\n\t\t// Typing is represented by only a single change.\n\t\tif ( changes.length != 1 || entry.type !== 'insert' || entry.name != '$text' || entry.length != 1 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst blockToFormat = entry.position.parent;\n\n\t\t// Block formatting should be disabled in codeBlocks (#5800).\n\t\tif ( blockToFormat.is( 'element', 'codeBlock' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// In case a command is bound, do not re-execute it over an existing block style which would result with a style removal.\n\t\t// Instead just drop processing so that autoformat trigger text is not lost. E.g. writing \"# \" in a level 1 heading.\n\t\tif ( command && command.value === true ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst firstNode = blockToFormat.getChild( 0 );\n\t\tconst firstNodeRange = editor.model.createRangeOn( firstNode );\n\n\t\t// Range is only expected to be within or at the very end of the first text node.\n\t\tif ( !firstNodeRange.containsRange( range ) && !range.end.isEqual( firstNodeRange.end ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst match = pattern.exec( firstNode.data.substr( 0, range.end.offset ) );\n\n\t\t// ...and this text node's data match the pattern.\n\t\tif ( !match ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Use enqueueChange to create new batch to separate typing batch from the auto-format changes.\n\t\teditor.model.enqueueChange( writer => {\n\t\t\t// Matched range.\n\t\t\tconst start = writer.createPositionAt( blockToFormat, 0 );\n\t\t\tconst end = writer.createPositionAt( blockToFormat, match[ 0 ].length );\n\t\t\tconst range = new LiveRange( start, end );\n\n\t\t\tconst wasChanged = callback( { match } );\n\n\t\t\t// Remove matched text.\n\t\t\tif ( wasChanged !== false ) {\n\t\t\t\twriter.remove( range );\n\t\t\t}\n\n\t\t\trange.detach();\n\t\t} );\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * The inline autoformatting engine. It allows to format various inline patterns. For example,\n * it can be configured to make \"foo\" bold when typed `**foo**` (the `**` markers will be removed).\n *\n * The autoformatting operation is integrated with the undo manager,\n * so the autoformatting step can be undone if the user's intention was not to format the text.\n *\n * See the {@link module:autoformat/inlineautoformatediting~inlineAutoformatEditing `inlineAutoformatEditing`} documentation\n * to learn how to create custom inline autoformatters. You can also use\n * the {@link module:autoformat/autoformat~Autoformat} feature which enables a set of default autoformatters\n * (lists, headings, bold and italic).\n *\n * @module autoformat/inlineautoformatediting\n */\n\n/**\n * Enables autoformatting mechanism for a given {@link module:core/editor/editor~Editor}.\n *\n * It formats the matched text by applying the given model attribute or by running the provided formatting callback.\n * On every {@link module:engine/model/document~Document#event:change:data data change} in the model document\n * the autoformatting engine checks the text on the left of the selection\n * and executes the provided action if the text matches given criteria (regular expression or callback).\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n * @param {module:autoformat/autoformat~Autoformat} plugin The autoformat plugin instance.\n * @param {Function|RegExp} testRegexpOrCallback The regular expression or callback to execute on text.\n * Provided regular expression *must* have three capture groups. The first and the third capture group\n * should match opening and closing delimiters. The second capture group should match the text to format.\n *\n *\t\t// Matches the `**bold text**` pattern.\n *\t\t// There are three capturing groups:\n *\t\t// - The first to match the starting `**` delimiter.\n *\t\t// - The second to match the text to format.\n *\t\t// - The third to match the ending `**` delimiter.\n *\t\tinlineAutoformatEditing( editor, plugin, /(\\*\\*)([^\\*]+?)(\\*\\*)$/g, formatCallback );\n *\n * When a function is provided instead of the regular expression, it will be executed with the text to match as a parameter.\n * The function should return proper \"ranges\" to delete and format.\n *\n *\t\t{\n *\t\t\tremove: [\n *\t\t\t\t[ 0, 1 ],\t// Remove the first letter from the given text.\n *\t\t\t\t[ 5, 6 ]\t// Remove the 6th letter from the given text.\n *\t\t\t],\n *\t\t\tformat: [\n *\t\t\t\t[ 1, 5 ]\t// Format all letters from 2nd to 5th.\n *\t\t\t]\n *\t\t}\n *\n * @param {Function} formatCallback A callback to apply actual formatting.\n * It should return `false` if changes should not be applied (e.g. if a command is disabled).\n *\n *\t\tinlineAutoformatEditing( editor, plugin, /(\\*\\*)([^\\*]+?)(\\*\\*)$/g, ( writer, rangesToFormat ) => {\n *\t\t\tconst command = editor.commands.get( 'bold' );\n *\n *\t\t\tif ( !command.isEnabled ) {\n *\t\t\t\treturn false;\n *\t\t\t}\n *\n *\t\t\tconst validRanges = editor.model.schema.getValidRanges( rangesToFormat, 'bold' );\n *\n *\t\t\tfor ( let range of validRanges ) {\n *\t\t\t\twriter.setAttribute( 'bold', true, range );\n *\t\t\t}\n *\t\t} );\n */\nexport default function inlineAutoformatEditing( editor, plugin, testRegexpOrCallback, formatCallback ) {\n\tlet regExp;\n\tlet testCallback;\n\n\tif ( testRegexpOrCallback instanceof RegExp ) {\n\t\tregExp = testRegexpOrCallback;\n\t} else {\n\t\ttestCallback = testRegexpOrCallback;\n\t}\n\n\t// A test callback run on changed text.\n\ttestCallback = testCallback || ( text => {\n\t\tlet result;\n\t\tconst remove = [];\n\t\tconst format = [];\n\n\t\twhile ( ( result = regExp.exec( text ) ) !== null ) {\n\t\t\t// There should be full match and 3 capture groups.\n\t\t\tif ( result && result.length < 4 ) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tlet {\n\t\t\t\tindex,\n\t\t\t\t'1': leftDel,\n\t\t\t\t'2': content,\n\t\t\t\t'3': rightDel\n\t\t\t} = result;\n\n\t\t\t// Real matched string - there might be some non-capturing groups so we need to recalculate starting index.\n\t\t\tconst found = leftDel + content + rightDel;\n\t\t\tindex += result[ 0 ].length - found.length;\n\n\t\t\t// Start and End offsets of delimiters to remove.\n\t\t\tconst delStart = [\n\t\t\t\tindex,\n\t\t\t\tindex + leftDel.length\n\t\t\t];\n\t\t\tconst delEnd = [\n\t\t\t\tindex + leftDel.length + content.length,\n\t\t\t\tindex + leftDel.length + content.length + rightDel.length\n\t\t\t];\n\n\t\t\tremove.push( delStart );\n\t\t\tremove.push( delEnd );\n\n\t\t\tformat.push( [ index + leftDel.length, index + leftDel.length + content.length ] );\n\t\t}\n\n\t\treturn {\n\t\t\tremove,\n\t\t\tformat\n\t\t};\n\t} );\n\n\teditor.model.document.on( 'change:data', ( evt, batch ) => {\n\t\tif ( batch.type == 'transparent' || !plugin.isEnabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst model = editor.model;\n\t\tconst selection = model.document.selection;\n\n\t\t// Do nothing if selection is not collapsed.\n\t\tif ( !selection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst changes = Array.from( model.document.differ.getChanges() );\n\t\tconst entry = changes[ 0 ];\n\n\t\t// Typing is represented by only a single change.\n\t\tif ( changes.length != 1 || entry.type !== 'insert' || entry.name != '$text' || entry.length != 1 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst focus = selection.focus;\n\t\tconst block = focus.parent;\n\t\tconst { text, range } = getTextAfterCode( model.createRange( model.createPositionAt( block, 0 ), focus ), model );\n\t\tconst testOutput = testCallback( text );\n\t\tconst rangesToFormat = testOutputToRanges( range.start, testOutput.format, model );\n\t\tconst rangesToRemove = testOutputToRanges( range.start, testOutput.remove, model );\n\n\t\tif ( !( rangesToFormat.length && rangesToRemove.length ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Use enqueueChange to create new batch to separate typing batch from the auto-format changes.\n\t\tmodel.enqueueChange( writer => {\n\t\t\t// Apply format.\n\t\t\tconst hasChanged = formatCallback( writer, rangesToFormat );\n\n\t\t\t// Strict check on `false` to have backward compatibility (when callbacks were returning `undefined`).\n\t\t\tif ( hasChanged === false ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Remove delimiters - use reversed order to not mix the offsets while removing.\n\t\t\tfor ( const range of rangesToRemove.reverse() ) {\n\t\t\t\twriter.remove( range );\n\t\t\t}\n\t\t} );\n\t} );\n}\n\n// Converts output of the test function provided to the inlineAutoformatEditing and converts it to the model ranges\n// inside provided block.\n//\n// @private\n// @param {module:engine/model/position~Position} start\n// @param {Array.<Array>} arrays\n// @param {module:engine/model/model~Model} model\nfunction testOutputToRanges( start, arrays, model ) {\n\treturn arrays\n\t\t.filter( array => ( array[ 0 ] !== undefined && array[ 1 ] !== undefined ) )\n\t\t.map( array => {\n\t\t\treturn model.createRange( start.getShiftedBy( array[ 0 ] ), start.getShiftedBy( array[ 1 ] ) );\n\t\t} );\n}\n\n// Returns the last text line after the last code element from the given range.\n// It is similar to {@link module:typing/utils/getlasttextline.getLastTextLine `getLastTextLine()`},\n// but it ignores any text before the last `code`.\n//\n// @param {module:engine/model/range~Range} range\n// @param {module:engine/model/model~Model} model\n// @returns {module:typing/utils/getlasttextline~LastTextLineData}\nfunction getTextAfterCode( range, model ) {\n\tlet start = range.start;\n\n\tconst text = Array.from( range.getItems() ).reduce( ( rangeText, node ) => {\n\t\t// Trim text to a last occurrence of an inline element and update range start.\n\t\tif ( !( node.is( '$text' ) || node.is( '$textProxy' ) ) || node.getAttribute( 'code' ) ) {\n\t\t\tstart = model.createPositionAfter( node );\n\n\t\t\treturn '';\n\t\t}\n\n\t\treturn rangeText + node.data;\n\t}, '' );\n\n\treturn { text, range: model.createRange( start, range.end ) };\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module autoformat/autoformat\n */\n\nimport blockAutoformatEditing from './blockautoformatediting';\nimport inlineAutoformatEditing from './inlineautoformatediting';\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\n/**\n * Enables a set of predefined autoformatting actions.\n *\n * For a detailed overview, check the {@glink features/autoformat Autoformatting feature documentation}\n * and the {@glink api/autoformat package page}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Autoformat extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Autoformat';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tthis._addListAutoformats();\n\t\tthis._addBasicStylesAutoformats();\n\t\tthis._addHeadingAutoformats();\n\t\tthis._addBlockQuoteAutoformats();\n\t\tthis._addCodeBlockAutoformats();\n\t}\n\n\t/**\n\t * Adds autoformatting related to the {@link module:list/list~List}.\n\t *\n\t * When typed:\n\t * - `* ` or `- ` &ndash; A paragraph will be changed to a bulleted list.\n\t * - `1. ` or `1) ` &ndash; A paragraph will be changed to a numbered list (\"1\" can be any digit or a list of digits).\n\t *\n\t * @private\n\t */\n\t_addListAutoformats() {\n\t\tconst commands = this.editor.commands;\n\n\t\tif ( commands.get( 'bulletedList' ) ) {\n\t\t\tblockAutoformatEditing( this.editor, this, /^[*-]\\s$/, 'bulletedList' );\n\t\t}\n\n\t\tif ( commands.get( 'numberedList' ) ) {\n\t\t\tblockAutoformatEditing( this.editor, this, /^1[.|)]\\s$/, 'numberedList' );\n\t\t}\n\t}\n\n\t/**\n\t * Adds autoformatting related to the {@link module:basic-styles/bold~Bold},\n\t * {@link module:basic-styles/italic~Italic}, {@link module:basic-styles/code~Code}\n\t * and {@link module:basic-styles/strikethrough~Strikethrough}\n\t *\n\t * When typed:\n\t * - `**foobar**` &ndash; `**` characters are removed and `foobar` is set to bold,\n\t * - `__foobar__` &ndash; `__` characters are removed and `foobar` is set to bold,\n\t * - `*foobar*` &ndash; `*` characters are removed and `foobar` is set to italic,\n\t * - `_foobar_` &ndash; `_` characters are removed and `foobar` is set to italic,\n\t * - ``` `foobar` &ndash; ``` ` ``` characters are removed and `foobar` is set to code,\n\t * - `~~foobar~~` &ndash; `~~` characters are removed and `foobar` is set to strikethrough.\n\t *\n\t * @private\n\t */\n\t_addBasicStylesAutoformats() {\n\t\tconst commands = this.editor.commands;\n\n\t\tif ( commands.get( 'bold' ) ) {\n\t\t\tconst boldCallback = getCallbackFunctionForInlineAutoformat( this.editor, 'bold' );\n\n\t\t\tinlineAutoformatEditing( this.editor, this, /(\\*\\*)([^*]+)(\\*\\*)$/g, boldCallback );\n\t\t\tinlineAutoformatEditing( this.editor, this, /(__)([^_]+)(__)$/g, boldCallback );\n\t\t}\n\n\t\tif ( commands.get( 'italic' ) ) {\n\t\t\tconst italicCallback = getCallbackFunctionForInlineAutoformat( this.editor, 'italic' );\n\n\t\t\t// The italic autoformatter cannot be triggered by the bold markers, so we need to check the\n\t\t\t// text before the pattern (e.g. `(?:^|[^\\*])`).\n\t\t\tinlineAutoformatEditing( this.editor, this, /(?:^|[^*])(\\*)([^*_]+)(\\*)$/g, italicCallback );\n\t\t\tinlineAutoformatEditing( this.editor, this, /(?:^|[^_])(_)([^_]+)(_)$/g, italicCallback );\n\t\t}\n\n\t\tif ( commands.get( 'code' ) ) {\n\t\t\tconst codeCallback = getCallbackFunctionForInlineAutoformat( this.editor, 'code' );\n\n\t\t\tinlineAutoformatEditing( this.editor, this, /(`)([^`]+)(`)$/g, codeCallback );\n\t\t}\n\n\t\tif ( commands.get( 'strikethrough' ) ) {\n\t\t\tconst strikethroughCallback = getCallbackFunctionForInlineAutoformat( this.editor, 'strikethrough' );\n\n\t\t\tinlineAutoformatEditing( this.editor, this, /(~~)([^~]+)(~~)$/g, strikethroughCallback );\n\t\t}\n\t}\n\n\t/**\n\t * Adds autoformatting related to {@link module:heading/heading~Heading}.\n\t *\n\t * It is using a number at the end of the command name to associate it with the proper trigger:\n\t *\n\t * * `heading` with value `heading1` will be executed when typing `#`,\n\t * * `heading` with value `heading2` will be executed when typing `##`,\n\t * * ... up to `heading6` and `######`.\n\t *\n\t * @private\n\t */\n\t_addHeadingAutoformats() {\n\t\tconst command = this.editor.commands.get( 'heading' );\n\n\t\tif ( command ) {\n\t\t\tcommand.modelElements\n\t\t\t\t.filter( name => name.match( /^heading[1-6]$/ ) )\n\t\t\t\t.forEach( modelName => {\n\t\t\t\t\tconst level = modelName[ 7 ];\n\t\t\t\t\tconst pattern = new RegExp( `^(#{${ level }})\\\\s$` );\n\n\t\t\t\t\tblockAutoformatEditing( this.editor, this, pattern, () => {\n\t\t\t\t\t\t// Should only be active if command is enabled and heading style associated with pattern is inactive.\n\t\t\t\t\t\tif ( !command.isEnabled || command.value === modelName ) {\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthis.editor.execute( 'heading', { value: modelName } );\n\t\t\t\t\t} );\n\t\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Adds autoformatting related to {@link module:block-quote/blockquote~BlockQuote}.\n\t *\n\t * When typed:\n\t * * `> ` &ndash; A paragraph will be changed to a block quote.\n\t *\n\t * @private\n\t */\n\t_addBlockQuoteAutoformats() {\n\t\tif ( this.editor.commands.get( 'blockQuote' ) ) {\n\t\t\tblockAutoformatEditing( this.editor, this, /^>\\s$/, 'blockQuote' );\n\t\t}\n\t}\n\n\t/**\n\t * Adds autoformatting related to {@link module:code-block/codeblock~CodeBlock}.\n\t *\n\t * When typed:\n\t * - `` ``` `` &ndash; A paragraph will be changed to a code block.\n\t *\n\t * @private\n\t */\n\t_addCodeBlockAutoformats() {\n\t\tif ( this.editor.commands.get( 'codeBlock' ) ) {\n\t\t\tblockAutoformatEditing( this.editor, this, /^```$/, 'codeBlock' );\n\t\t}\n\t}\n}\n\n// Helper function for getting `inlineAutoformatEditing` callbacks that checks if command is enabled.\n//\n// @param {module:core/editor/editor~Editor} editor\n// @param {String} attributeKey\n// @returns {Function}\nfunction getCallbackFunctionForInlineAutoformat( editor, attributeKey ) {\n\treturn ( writer, rangesToFormat ) => {\n\t\tconst command = editor.commands.get( attributeKey );\n\n\t\tif ( !command.isEnabled ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst validRanges = editor.model.schema.getValidRanges( rangesToFormat, attributeKey );\n\n\t\tfor ( const range of validRanges ) {\n\t\t\twriter.setAttribute( attributeKey, true, range );\n\t\t}\n\n\t\t// After applying attribute to the text, remove given attribute from the selection.\n\t\t// This way user is able to type a text without attribute used by auto formatter.\n\t\twriter.removeSelectionAttribute( attributeKey );\n\t};\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/attributecommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\n/**\n * An extension of the base {@link module:core/command~Command} class, which provides utilities for a command\n * that toggles a single attribute on a text or an element.\n *\n * `AttributeCommand` uses {@link module:engine/model/document~Document#selection}\n * to decide which nodes (if any) should be changed, and applies or removes the attribute from them.\n *\n * The command checks the {@link module:engine/model/model~Model#schema} to decide if it can be enabled\n * for the current selection and to which nodes the attribute can be applied.\n *\n * @extends module:core/command~Command\n */\nexport default class AttributeCommand extends Command {\n\t/**\n\t * @param {module:core/editor/editor~Editor} editor\n\t * @param {String} attributeKey Attribute that will be set by the command.\n\t */\n\tconstructor( editor, attributeKey ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The attribute that will be set by the command.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.attributeKey = attributeKey;\n\n\t\t/**\n\t\t * Flag indicating whether the command is active. The command is active when the\n\t\t * {@link module:engine/model/selection~Selection#hasAttribute selection has the attribute} which means that:\n\t\t *\n\t\t * * If the selection is not empty &ndash; That the attribute is set on the first node in the selection that allows this attribute.\n\t\t * * If the selection is empty &ndash; That the selection has the attribute itself (which means that newly typed\n\t\t * text will have this attribute, too).\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #value\n\t\t */\n\t}\n\n\t/**\n\t * Updates the command's {@link #value} and {@link #isEnabled} based on the current selection.\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tthis.value = this._getValueFromFirstAllowedNode();\n\t\tthis.isEnabled = model.schema.checkAttributeInSelection( doc.selection, this.attributeKey );\n\t}\n\n\t/**\n\t * Executes the command &mdash; applies the attribute to the selection or removes it from the selection.\n\t *\n\t * If the command is active (`value == true`), it will remove attributes. Otherwise, it will set attributes.\n\t *\n\t * The execution result differs, depending on the {@link module:engine/model/document~Document#selection}:\n\t *\n\t * * If the selection is on a range, the command applies the attribute to all nodes in that range\n\t * (if they are allowed to have this attribute by the {@link module:engine/model/schema~Schema schema}).\n\t * * If the selection is collapsed in a non-empty node, the command applies the attribute to the\n\t * {@link module:engine/model/document~Document#selection} itself (note that typed characters copy attributes from the selection).\n\t * * If the selection is collapsed in an empty node, the command applies the attribute to the parent node of the selection (note\n\t * that the selection inherits all attributes from a node if it is in an empty node).\n\t *\n\t * @fires execute\n\t * @param {Object} [options] Command options.\n\t * @param {Boolean} [options.forceValue] If set, it will force the command behavior. If `true`, the command will apply the attribute,\n\t * otherwise the command will remove the attribute.\n\t * If not set, the command will look for its current value to decide what it should do.\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst selection = doc.selection;\n\t\tconst value = ( options.forceValue === undefined ) ? !this.value : options.forceValue;\n\n\t\tmodel.change( writer => {\n\t\t\tif ( selection.isCollapsed ) {\n\t\t\t\tif ( value ) {\n\t\t\t\t\twriter.setSelectionAttribute( this.attributeKey, true );\n\t\t\t\t} else {\n\t\t\t\t\twriter.removeSelectionAttribute( this.attributeKey );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst ranges = model.schema.getValidRanges( selection.getRanges(), this.attributeKey );\n\n\t\t\t\tfor ( const range of ranges ) {\n\t\t\t\t\tif ( value ) {\n\t\t\t\t\t\twriter.setAttribute( this.attributeKey, value, range );\n\t\t\t\t\t} else {\n\t\t\t\t\t\twriter.removeAttribute( this.attributeKey, range );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Checks the attribute value of the first node in the selection that allows the attribute.\n\t * For the collapsed selection returns the selection attribute.\n\t *\n\t * @private\n\t * @returns {Boolean} The attribute value.\n\t */\n\t_getValueFromFirstAllowedNode() {\n\t\tconst model = this.editor.model;\n\t\tconst schema = model.schema;\n\t\tconst selection = model.document.selection;\n\n\t\tif ( selection.isCollapsed ) {\n\t\t\treturn selection.hasAttribute( this.attributeKey );\n\t\t}\n\n\t\tfor ( const range of selection.getRanges() ) {\n\t\t\tfor ( const item of range.getItems() ) {\n\t\t\t\tif ( schema.checkAttribute( item, this.attributeKey ) ) {\n\t\t\t\t\treturn item.hasAttribute( this.attributeKey );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/bold/boldediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport AttributeCommand from '../attributecommand';\n\nconst BOLD = 'bold';\n\n/**\n * The bold editing feature.\n *\n * It registers the `'bold'` command and introduces the `bold` attribute in the model which renders to the view\n * as a `<strong>` element.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class BoldEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'BoldEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\t// Allow bold attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: BOLD } );\n\t\teditor.model.schema.setAttributeProperties( BOLD, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\n\t\t// Build converter from model to view for data and editing pipelines.\n\t\teditor.conversion.attributeToElement( {\n\t\t\tmodel: BOLD,\n\t\t\tview: 'strong',\n\t\t\tupcastAlso: [\n\t\t\t\t'b',\n\t\t\t\tviewElement => {\n\t\t\t\t\tconst fontWeight = viewElement.getStyle( 'font-weight' );\n\n\t\t\t\t\tif ( !fontWeight ) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Value of the `font-weight` attribute can be defined as a string or a number.\n\t\t\t\t\tif ( fontWeight == 'bold' || Number( fontWeight ) >= 600 ) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tname: true,\n\t\t\t\t\t\t\tstyles: [ 'font-weight' ]\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\t// Create bold command.\n\t\teditor.commands.add( BOLD, new AttributeCommand( editor, BOLD ) );\n\n\t\t// Set the Ctrl+B keystroke.\n\t\teditor.keystrokes.set( 'CTRL+B', BOLD );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/bold/boldui\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\n\nimport boldIcon from '../../theme/icons/bold.svg';\n\nconst BOLD = 'bold';\n\n/**\n * The bold UI feature. It introduces the Bold button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class BoldUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\t// Add bold button to feature components.\n\t\teditor.ui.componentFactory.add( BOLD, locale => {\n\t\t\tconst command = editor.commands.get( BOLD );\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: t( 'Bold' ),\n\t\t\t\ticon: boldIcon,\n\t\t\t\tkeystroke: 'CTRL+B',\n\t\t\t\ttooltip: true,\n\t\t\t\tisToggleable: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );\n\n\t\t\t// Execute command.\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\teditor.execute( BOLD );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M10.187 17H5.773c-.637 0-1.092-.138-1.364-.415-.273-.277-.409-.718-.409-1.323V4.738c0-.617.14-1.062.419-1.332.279-.27.73-.406 1.354-.406h4.68c.69 0 1.288.041 1.793.124.506.083.96.242 1.36.478.341.197.644.447.906.75a3.262 3.262 0 0 1 .808 2.162c0 1.401-.722 2.426-2.167 3.075C15.05 10.175 16 11.315 16 13.01a3.756 3.756 0 0 1-2.296 3.504 6.1 6.1 0 0 1-1.517.377c-.571.073-1.238.11-2 .11zm-.217-6.217H7v4.087h3.069c1.977 0 2.965-.69 2.965-2.072 0-.707-.256-1.22-.768-1.537-.512-.319-1.277-.478-2.296-.478zM7 5.13v3.619h2.606c.729 0 1.292-.067 1.69-.2a1.6 1.6 0 0 0 .91-.765c.165-.267.247-.566.247-.897 0-.707-.26-1.176-.778-1.409-.519-.232-1.31-.348-2.375-.348H7z\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/italic/italicediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport AttributeCommand from '../attributecommand';\n\nconst ITALIC = 'italic';\n\n/**\n * The italic editing feature.\n *\n * It registers the `'italic'` command, the <kbd>Ctrl+I</kbd> keystroke and introduces the `italic` attribute in the model\n * which renders to the view as an `<i>` element.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ItalicEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ItalicEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Allow italic attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: ITALIC } );\n\t\teditor.model.schema.setAttributeProperties( ITALIC, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\n\t\teditor.conversion.attributeToElement( {\n\t\t\tmodel: ITALIC,\n\t\t\tview: 'i',\n\t\t\tupcastAlso: [\n\t\t\t\t'em',\n\t\t\t\t{\n\t\t\t\t\tstyles: {\n\t\t\t\t\t\t'font-style': 'italic'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\t// Create italic command.\n\t\teditor.commands.add( ITALIC, new AttributeCommand( editor, ITALIC ) );\n\n\t\t// Set the Ctrl+I keystroke.\n\t\teditor.keystrokes.set( 'CTRL+I', ITALIC );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/italic/italicui\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\n\nimport italicIcon from '../../theme/icons/italic.svg';\n\nconst ITALIC = 'italic';\n\n/**\n * The italic UI feature. It introduces the Italic button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ItalicUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\t// Add bold button to feature components.\n\t\teditor.ui.componentFactory.add( ITALIC, locale => {\n\t\t\tconst command = editor.commands.get( ITALIC );\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: t( 'Italic' ),\n\t\t\t\ticon: italicIcon,\n\t\t\t\tkeystroke: 'CTRL+I',\n\t\t\t\ttooltip: true,\n\t\t\t\tisToggleable: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );\n\n\t\t\t// Execute command.\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\teditor.execute( ITALIC );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M9.586 14.633l.021.004c-.036.335.095.655.393.962.082.083.173.15.274.201h1.474a.6.6 0 1 1 0 1.2H5.304a.6.6 0 0 1 0-1.2h1.15c.474-.07.809-.182 1.005-.334.157-.122.291-.32.404-.597l2.416-9.55a1.053 1.053 0 0 0-.281-.823 1.12 1.12 0 0 0-.442-.296H8.15a.6.6 0 0 1 0-1.2h6.443a.6.6 0 1 1 0 1.2h-1.195c-.376.056-.65.155-.823.296-.215.175-.423.439-.623.79l-2.366 9.347z\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module block-quote/blockquotecommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\nimport first from '@ckeditor/ckeditor5-utils/src/first';\n\n/**\n * The block quote command plugin.\n *\n * @extends module:core/command~Command\n */\nexport default class BlockQuoteCommand extends Command {\n\t/**\n\t * Whether the selection starts in a block quote.\n\t *\n\t * @observable\n\t * @readonly\n\t * @member {Boolean} #value\n\t */\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.value = this._getValue();\n\t\tthis.isEnabled = this._checkEnabled();\n\t}\n\n\t/**\n\t * Executes the command. When the command {@link #value is on}, all top-most block quotes within\n\t * the selection will be removed. If it is off, all selected blocks will be wrapped with\n\t * a block quote.\n\t *\n\t * @fires execute\n\t * @param {Object} [options] Command options.\n\t * @param {Boolean} [options.forceValue] If set, it will force the command behavior. If `true`, the command will apply a block quote,\n\t * otherwise the command will remove the block quote. If not set, the command will act basing on its current value.\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst schema = model.schema;\n\t\tconst selection = model.document.selection;\n\n\t\tconst blocks = Array.from( selection.getSelectedBlocks() );\n\n\t\tconst value = ( options.forceValue === undefined ) ? !this.value : options.forceValue;\n\n\t\tmodel.change( writer => {\n\t\t\tif ( !value ) {\n\t\t\t\tthis._removeQuote( writer, blocks.filter( findQuote ) );\n\t\t\t} else {\n\t\t\t\tconst blocksToQuote = blocks.filter( block => {\n\t\t\t\t\t// Already quoted blocks needs to be considered while quoting too\n\t\t\t\t\t// in order to reuse their <bQ> elements.\n\t\t\t\t\treturn findQuote( block ) || checkCanBeQuoted( schema, block );\n\t\t\t\t} );\n\n\t\t\t\tthis._applyQuote( writer, blocksToQuote );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Checks the command's {@link #value}.\n\t *\n\t * @private\n\t * @returns {Boolean} The current value.\n\t */\n\t_getValue() {\n\t\tconst selection = this.editor.model.document.selection;\n\n\t\tconst firstBlock = first( selection.getSelectedBlocks() );\n\n\t\t// In the current implementation, the block quote must be an immediate parent of a block element.\n\t\treturn !!( firstBlock && findQuote( firstBlock ) );\n\t}\n\n\t/**\n\t * Checks whether the command can be enabled in the current context.\n\t *\n\t * @private\n\t * @returns {Boolean} Whether the command should be enabled.\n\t */\n\t_checkEnabled() {\n\t\tif ( this.value ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst selection = this.editor.model.document.selection;\n\t\tconst schema = this.editor.model.schema;\n\n\t\tconst firstBlock = first( selection.getSelectedBlocks() );\n\n\t\tif ( !firstBlock ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn checkCanBeQuoted( schema, firstBlock );\n\t}\n\n\t/**\n\t * Removes the quote from given blocks.\n\t *\n\t * If blocks which are supposed to be \"unquoted\" are in the middle of a quote,\n\t * start it or end it, then the quote will be split (if needed) and the blocks\n\t * will be moved out of it, so other quoted blocks remained quoted.\n\t *\n\t * @private\n\t * @param {module:engine/model/writer~Writer} writer\n\t * @param {Array.<module:engine/model/element~Element>} blocks\n\t */\n\t_removeQuote( writer, blocks ) {\n\t\t// Unquote all groups of block. Iterate in the reverse order to not break following ranges.\n\t\tgetRangesOfBlockGroups( writer, blocks ).reverse().forEach( groupRange => {\n\t\t\tif ( groupRange.start.isAtStart && groupRange.end.isAtEnd ) {\n\t\t\t\twriter.unwrap( groupRange.start.parent );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// The group of blocks are at the beginning of an <bQ> so let's move them left (out of the <bQ>).\n\t\t\tif ( groupRange.start.isAtStart ) {\n\t\t\t\tconst positionBefore = writer.createPositionBefore( groupRange.start.parent );\n\n\t\t\t\twriter.move( groupRange, positionBefore );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// The blocks are in the middle of an <bQ> so we need to split the <bQ> after the last block\n\t\t\t// so we move the items there.\n\t\t\tif ( !groupRange.end.isAtEnd ) {\n\t\t\t\twriter.split( groupRange.end );\n\t\t\t}\n\n\t\t\t// Now we are sure that groupRange.end.isAtEnd is true, so let's move the blocks right.\n\n\t\t\tconst positionAfter = writer.createPositionAfter( groupRange.end.parent );\n\n\t\t\twriter.move( groupRange, positionAfter );\n\t\t} );\n\t}\n\n\t/**\n\t * Applies the quote to given blocks.\n\t *\n\t * @private\n\t * @param {module:engine/model/writer~Writer} writer\n\t * @param {Array.<module:engine/model/element~Element>} blocks\n\t */\n\t_applyQuote( writer, blocks ) {\n\t\tconst quotesToMerge = [];\n\n\t\t// Quote all groups of block. Iterate in the reverse order to not break following ranges.\n\t\tgetRangesOfBlockGroups( writer, blocks ).reverse().forEach( groupRange => {\n\t\t\tlet quote = findQuote( groupRange.start );\n\n\t\t\tif ( !quote ) {\n\t\t\t\tquote = writer.createElement( 'blockQuote' );\n\n\t\t\t\twriter.wrap( groupRange, quote );\n\t\t\t}\n\n\t\t\tquotesToMerge.push( quote );\n\t\t} );\n\n\t\t// Merge subsequent <bQ> elements. Reverse the order again because this time we want to go through\n\t\t// the <bQ> elements in the source order (due to how merge works – it moves the right element's content\n\t\t// to the first element and removes the right one. Since we may need to merge a couple of subsequent `<bQ>` elements\n\t\t// we want to keep the reference to the first (furthest left) one.\n\t\tquotesToMerge.reverse().reduce( ( currentQuote, nextQuote ) => {\n\t\t\tif ( currentQuote.nextSibling == nextQuote ) {\n\t\t\t\twriter.merge( writer.createPositionAfter( currentQuote ) );\n\n\t\t\t\treturn currentQuote;\n\t\t\t}\n\n\t\t\treturn nextQuote;\n\t\t} );\n\t}\n}\n\nfunction findQuote( elementOrPosition ) {\n\treturn elementOrPosition.parent.name == 'blockQuote' ? elementOrPosition.parent : null;\n}\n\n// Returns a minimal array of ranges containing groups of subsequent blocks.\n//\n// content:         abcdefgh\n// blocks:          [ a, b, d, f, g, h ]\n// output ranges:   [ab]c[d]e[fgh]\n//\n// @param {Array.<module:engine/model/element~Element>} blocks\n// @returns {Array.<module:engine/model/range~Range>}\nfunction getRangesOfBlockGroups( writer, blocks ) {\n\tlet startPosition;\n\tlet i = 0;\n\tconst ranges = [];\n\n\twhile ( i < blocks.length ) {\n\t\tconst block = blocks[ i ];\n\t\tconst nextBlock = blocks[ i + 1 ];\n\n\t\tif ( !startPosition ) {\n\t\t\tstartPosition = writer.createPositionBefore( block );\n\t\t}\n\n\t\tif ( !nextBlock || block.nextSibling != nextBlock ) {\n\t\t\tranges.push( writer.createRange( startPosition, writer.createPositionAfter( block ) ) );\n\t\t\tstartPosition = null;\n\t\t}\n\n\t\ti++;\n\t}\n\n\treturn ranges;\n}\n\n// Checks whether <bQ> can wrap the block.\nfunction checkCanBeQuoted( schema, block ) {\n\t// TMP will be replaced with schema.checkWrap().\n\tconst isBQAllowed = schema.checkChild( block.parent, 'blockQuote' );\n\tconst isBlockAllowedInBQ = schema.checkChild( [ '$root', 'blockQuote' ], block );\n\n\treturn isBQAllowed && isBlockAllowedInBQ;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module block-quote/blockquoteediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport BlockQuoteCommand from './blockquotecommand';\n\n/**\n * The block quote editing.\n *\n * Introduces the `'blockQuote'` command and the `'blockQuote'` model element.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class BlockQuoteEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'BlockQuoteEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\n\t\teditor.commands.add( 'blockQuote', new BlockQuoteCommand( editor ) );\n\n\t\tschema.register( 'blockQuote', {\n\t\t\tallowWhere: '$block',\n\t\t\tallowContentOf: '$root'\n\t\t} );\n\n\t\t// Disallow blockQuote in blockQuote.\n\t\tschema.addChildCheck( ( ctx, childDef ) => {\n\t\t\tif ( ctx.endsWith( 'blockQuote' ) && childDef.name == 'blockQuote' ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} );\n\n\t\teditor.conversion.elementToElement( { model: 'blockQuote', view: 'blockquote' } );\n\n\t\t// Postfixer which cleans incorrect model states connected with block quotes.\n\t\teditor.model.document.registerPostFixer( writer => {\n\t\t\tconst changes = editor.model.document.differ.getChanges();\n\n\t\t\tfor ( const entry of changes ) {\n\t\t\t\tif ( entry.type == 'insert' ) {\n\t\t\t\t\tconst element = entry.position.nodeAfter;\n\n\t\t\t\t\tif ( !element ) {\n\t\t\t\t\t\t// We are inside a text node.\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( element.is( 'element', 'blockQuote' ) && element.isEmpty ) {\n\t\t\t\t\t\t// Added an empty blockQuote - remove it.\n\t\t\t\t\t\twriter.remove( element );\n\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t} else if ( element.is( 'element', 'blockQuote' ) && !schema.checkChild( entry.position, element ) ) {\n\t\t\t\t\t\t// Added a blockQuote in incorrect place - most likely inside another blockQuote. Unwrap it\n\t\t\t\t\t\t// so the content inside is not lost.\n\t\t\t\t\t\twriter.unwrap( element );\n\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t} else if ( element.is( 'element' ) ) {\n\t\t\t\t\t\t// Just added an element. Check its children to see if there are no nested blockQuotes somewhere inside.\n\t\t\t\t\t\tconst range = writer.createRangeIn( element );\n\n\t\t\t\t\t\tfor ( const child of range.getItems() ) {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tchild.is( 'element', 'blockQuote' ) &&\n\t\t\t\t\t\t\t\t!schema.checkChild( writer.createPositionBefore( child ), child )\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\twriter.unwrap( child );\n\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if ( entry.type == 'remove' ) {\n\t\t\t\t\tconst parent = entry.position.parent;\n\n\t\t\t\t\tif ( parent.is( 'element', 'blockQuote' ) && parent.isEmpty ) {\n\t\t\t\t\t\t// Something got removed and now blockQuote is empty. Remove the blockQuote as well.\n\t\t\t\t\t\twriter.remove( parent );\n\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tconst editor = this.editor;\n\t\tconst command = editor.commands.get( 'blockQuote' );\n\n\t\t// Overwrite default Enter key behavior.\n\t\t// If Enter key is pressed with selection collapsed in empty block inside a quote, break the quote.\n\t\t// This listener is added in afterInit in order to register it after list's feature listener.\n\t\t// We can't use a priority for this, because 'low' is already used by the enter feature, unless\n\t\t// we'd use numeric priority in this case.\n\t\tthis.listenTo( this.editor.editing.view.document, 'enter', ( evt, data ) => {\n\t\t\tconst doc = this.editor.model.document;\n\t\t\tconst positionParent = doc.selection.getLastPosition().parent;\n\n\t\t\tif ( doc.selection.isCollapsed && positionParent.isEmpty && command.value ) {\n\t\t\t\tthis.editor.execute( 'blockQuote' );\n\t\t\t\tthis.editor.editing.view.scrollToTheSelection();\n\n\t\t\t\tdata.preventDefault();\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module block-quote/blockquoteui\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\n\nimport quoteIcon from '@ckeditor/ckeditor5-core/theme/icons/quote.svg';\nimport '../theme/blockquote.css';\n\n/**\n * The block quote UI plugin.\n *\n * It introduces the `'blockQuote'` button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class BlockQuoteUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\teditor.ui.componentFactory.add( 'blockQuote', locale => {\n\t\t\tconst command = editor.commands.get( 'blockQuote' );\n\t\t\tconst buttonView = new ButtonView( locale );\n\n\t\t\tbuttonView.set( {\n\t\t\t\tlabel: t( 'Block quote' ),\n\t\t\t\ticon: quoteIcon,\n\t\t\t\ttooltip: true,\n\t\t\t\tisToggleable: true\n\t\t\t} );\n\n\t\t\t// Bind button model to command.\n\t\t\tbuttonView.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );\n\n\t\t\t// Execute command.\n\t\t\tthis.listenTo( buttonView, 'execute', () => {\n\t\t\t\teditor.execute( 'blockQuote' );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn buttonView;\n\t\t} );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M3 10.423a6.5 6.5 0 0 1 6.056-6.408l.038.67C6.448 5.423 5.354 7.663 5.22 10H9c.552 0 .5.432.5.986v4.511c0 .554-.448.503-1 .503h-5c-.552 0-.5-.449-.5-1.003v-4.574zm8 0a6.5 6.5 0 0 1 6.056-6.408l.038.67c-2.646.739-3.74 2.979-3.873 5.315H17c.552 0 .5.432.5.986v4.511c0 .554-.448.503-1 .503h-5c-.552 0-.5-.449-.5-1.003v-4.574z\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ckfinder/ckfinderui\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\n\nimport browseFilesIcon from '../theme/icons/browse-files.svg';\n\n/**\n * The CKFinder UI plugin. It introduces the `'ckfinder'` toolbar button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class CKFinderUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'CKFinderUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst componentFactory = editor.ui.componentFactory;\n\t\tconst t = editor.t;\n\n\t\tcomponentFactory.add( 'ckfinder', locale => {\n\t\t\tconst command = editor.commands.get( 'ckfinder' );\n\n\t\t\tconst button = new ButtonView( locale );\n\n\t\t\tbutton.set( {\n\t\t\t\tlabel: t( 'Insert image or file' ),\n\t\t\t\ticon: browseFilesIcon,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tbutton.bind( 'isEnabled' ).to( command );\n\n\t\t\tbutton.on( 'execute', () => {\n\t\t\t\teditor.execute( 'ckfinder' );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn button;\n\t\t} );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M11.627 16.5zm5.873-.196zm0-7.001V8h-13v8.5h4.341c.191.54.457 1.044.785 1.5H2a1.5 1.5 0 0 1-1.5-1.5v-13A1.5 1.5 0 0 1 2 2h4.5a1.5 1.5 0 0 1 1.06.44L9.122 4H16a1.5 1.5 0 0 1 1.5 1.5v1A1.5 1.5 0 0 1 19 8v2.531a6.027 6.027 0 0 0-1.5-1.228zM16 6.5v-1H8.5l-2-2H2v13h1V8a1.5 1.5 0 0 1 1.5-1.5H16z\\\"/><path d=\\\"M14.5 19.5a5 5 0 1 1 0-10 5 5 0 0 1 0 10zM15 14v-2h-1v2h-2v1h2v2h1v-2h2v-1h-2z\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/image/imageloadobserver\n */\n\nimport Observer from '@ckeditor/ckeditor5-engine/src/view/observer/observer';\n\n/**\n * Observes all new images added to the {@link module:engine/view/document~Document},\n * fires {@link module:engine/view/document~Document#event:imageLoaded} and\n * {@link module:engine/view/document~Document#event:layoutChanged} event every time when the new image\n * has been loaded.\n *\n * **Note:** This event is not fired for images that has been added to the document and rendered as `complete` (already loaded).\n *\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class ImageLoadObserver extends Observer {\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve( domRoot ) {\n\t\tthis.listenTo( domRoot, 'load', ( event, domEvent ) => {\n\t\t\tconst domElement = domEvent.target;\n\n\t\t\tif ( this.checkShouldIgnoreEventFromTarget( domElement ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( domElement.tagName == 'IMG' ) {\n\t\t\t\tthis._fireEvents( domEvent );\n\t\t\t}\n\t\t\t// Use capture phase for better performance (#4504).\n\t\t}, { useCapture: true } );\n\t}\n\n\t/**\n\t * Fires {@link module:engine/view/document~Document#event:layoutChanged} and\n\t * {@link module:engine/view/document~Document#event:imageLoaded}\n\t * if observer {@link #isEnabled is enabled}.\n\t *\n\t * @protected\n\t * @param {Event} domEvent The DOM event.\n\t */\n\t_fireEvents( domEvent ) {\n\t\tif ( this.isEnabled ) {\n\t\t\tthis.document.fire( 'layoutChanged' );\n\t\t\tthis.document.fire( 'imageLoaded', domEvent );\n\t\t}\n\t}\n}\n\n/**\n * Fired when an <img/> DOM element has been loaded in the DOM root.\n *\n * Introduced by {@link module:image/image/imageloadobserver~ImageLoadObserver}.\n *\n * @see module:image/image/imageloadobserver~ImageLoadObserver\n * @event module:engine/view/document~Document#event:imageLoaded\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module widget/highlightstack\n */\n\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Class used to handle correct order of highlights on elements.\n *\n * When different highlights are applied to same element correct order should be preserved:\n *\n * * highlight with highest priority should be applied,\n * * if two highlights have same priority - sort by CSS class provided in\n * {@link module:engine/conversion/downcasthelpers~HighlightDescriptor}.\n *\n * This way, highlight will be applied with the same rules it is applied on texts.\n */\nexport default class HighlightStack {\n\t/**\n\t * Creates class instance.\n\t */\n\tconstructor() {\n\t\tthis._stack = [];\n\t}\n\n\t/**\n\t * Adds highlight descriptor to the stack.\n\t *\n\t * @fires change:top\n\t * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} descriptor\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n\t */\n\tadd( descriptor, writer ) {\n\t\tconst stack = this._stack;\n\n\t\t// Save top descriptor and insert new one. If top is changed - fire event.\n\t\tconst oldTop = stack[ 0 ];\n\t\tthis._insertDescriptor( descriptor );\n\t\tconst newTop = stack[ 0 ];\n\n\t\t// When new object is at the top and stores different information.\n\t\tif ( oldTop !== newTop && !compareDescriptors( oldTop, newTop ) ) {\n\t\t\tthis.fire( 'change:top', {\n\t\t\t\toldDescriptor: oldTop,\n\t\t\t\tnewDescriptor: newTop,\n\t\t\t\twriter\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Removes highlight descriptor from the stack.\n\t *\n\t * @fires change:top\n\t * @param {String} id Id of the descriptor to remove.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n\t */\n\tremove( id, writer ) {\n\t\tconst stack = this._stack;\n\n\t\tconst oldTop = stack[ 0 ];\n\t\tthis._removeDescriptor( id );\n\t\tconst newTop = stack[ 0 ];\n\n\t\t// When new object is at the top and stores different information.\n\t\tif ( oldTop !== newTop && !compareDescriptors( oldTop, newTop ) ) {\n\t\t\tthis.fire( 'change:top', {\n\t\t\t\toldDescriptor: oldTop,\n\t\t\t\tnewDescriptor: newTop,\n\t\t\t\twriter\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Inserts given descriptor in correct place in the stack. It also takes care about updating information when\n\t * descriptor with same id is already present.\n\t *\n\t * @private\n\t * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} descriptor\n\t */\n\t_insertDescriptor( descriptor ) {\n\t\tconst stack = this._stack;\n\t\tconst index = stack.findIndex( item => item.id === descriptor.id );\n\n\t\t// Inserting exact same descriptor - do nothing.\n\t\tif ( compareDescriptors( descriptor, stack[ index ] ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If descriptor with same id but with different information is on the stack - remove it.\n\t\tif ( index > -1 ) {\n\t\t\tstack.splice( index, 1 );\n\t\t}\n\n\t\t// Find correct place to insert descriptor in the stack.\n\t\t// It have different information (for example priority) so it must be re-inserted in correct place.\n\t\tlet i = 0;\n\n\t\twhile ( stack[ i ] && shouldABeBeforeB( stack[ i ], descriptor ) ) {\n\t\t\ti++;\n\t\t}\n\n\t\tstack.splice( i, 0, descriptor );\n\t}\n\n\t/**\n\t * Removes descriptor with given id from the stack.\n\t *\n\t * @private\n\t * @param {String} id Descriptor's id.\n\t */\n\t_removeDescriptor( id ) {\n\t\tconst stack = this._stack;\n\t\tconst index = stack.findIndex( item => item.id === id );\n\n\t\t// If descriptor with same id is on the list - remove it.\n\t\tif ( index > -1 ) {\n\t\t\tstack.splice( index, 1 );\n\t\t}\n\t}\n}\n\nmix( HighlightStack, EmitterMixin );\n\n// Compares two descriptors by checking their priority and class list.\n//\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} a\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} b\n// @returns {Boolean} Returns true if both descriptors are defined and have same priority and classes.\nfunction compareDescriptors( a, b ) {\n\treturn a && b && a.priority == b.priority && classesToString( a.classes ) == classesToString( b.classes );\n}\n\n// Checks whenever first descriptor should be placed in the stack before second one.\n//\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} a\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} b\n// @returns {Boolean}\nfunction shouldABeBeforeB( a, b ) {\n\tif ( a.priority > b.priority ) {\n\t\treturn true;\n\t} else if ( a.priority < b.priority ) {\n\t\treturn false;\n\t}\n\n\t// When priorities are equal and names are different - use classes to compare.\n\treturn classesToString( a.classes ) > classesToString( b.classes );\n}\n\n// Converts CSS classes passed with {@link module:engine/conversion/downcasthelpers~HighlightDescriptor} to\n// sorted string.\n//\n// @param {String|Array<String>} descriptor\n// @returns {String}\nfunction classesToString( classes ) {\n\treturn Array.isArray( classes ) ? classes.sort().join( ',' ) : classes;\n}\n\n/**\n * Fired when top element on {@link module:widget/highlightstack~HighlightStack} has been changed\n *\n * @event change:top\n * @param {Object} data Additional information about the change.\n * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} [data.newDescriptor] New highlight\n * descriptor. It will be `undefined` when last descriptor is removed from the stack.\n * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} [data.oldDescriptor] Old highlight\n * descriptor. It will be `undefined` when first descriptor is added to the stack.\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that can be used to modify element.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module ui/panel/balloon/balloonpanelview\n */\n\nimport View from '../../view';\nimport { getOptimalPosition } from '@ckeditor/ckeditor5-utils/src/dom/position';\nimport isRange from '@ckeditor/ckeditor5-utils/src/dom/isrange';\nimport toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport { isElement } from 'lodash-es';\n\nimport '../../../theme/components/panel/balloonpanel.css';\n\nconst toPx = toUnit( 'px' );\nconst defaultLimiterElement = global.document.body;\n\n/**\n * The balloon panel view class.\n *\n * A floating container which can\n * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#pin pin} to any\n * {@link module:utils/dom/position~Options#target target} in the DOM and remain in that position\n * e.g. when the web page is scrolled.\n *\n * The balloon panel can be used to display contextual, non-blocking UI like forms, toolbars and\n * the like in its {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#content} view\n * collection.\n *\n * There is a number of {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}\n * that the balloon can use, automatically switching from one to another when the viewport space becomes\n * scarce to keep the balloon visible to the user as long as it is possible. The balloon will also\n * accept any custom position set provided by the user compatible with the\n * {@link module:utils/dom/position~Options options}.\n *\n *\t\tconst panel = new BalloonPanelView( locale );\n *\t\tconst childView = new ChildView();\n *\t\tconst positions = BalloonPanelView.defaultPositions;\n *\n *\t\tpanel.render();\n *\n *\t\t// Add a child view to the panel's content collection.\n *\t\tpanel.content.add( childView );\n *\n *\t\t// Start pinning the panel to an element with the \"target\" id DOM.\n *\t\t// The balloon will remain pinned until unpin() is called.\n *\t\tpanel.pin( {\n *\t\t\ttarget: document.querySelector( '#target' ),\n *\t\t\tpositions: [\n *\t\t\t\tpositions.northArrowSouth,\n *\t\t\t\tpositions.southArrowNorth\n *\t\t\t]\n *\t\t} );\n *\n * @extends module:ui/view~View\n */\nexport default class BalloonPanelView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * The absolute top position of the balloon panel in pixels.\n\t\t *\n\t\t * @observable\n\t\t * @default 0\n\t\t * @member {Number} #top\n\t\t */\n\t\tthis.set( 'top', 0 );\n\n\t\t/**\n\t\t * The absolute left position of the balloon panel in pixels.\n\t\t *\n\t\t * @observable\n\t\t * @default 0\n\t\t * @member {Number} #left\n\t\t */\n\t\tthis.set( 'left', 0 );\n\n\t\t/**\n\t\t * The balloon panel's current position. The position name is reflected in the CSS class set\n\t\t * to the balloon, i.e. `.ck-balloon-panel_arrow_nw` for the \"arrow_nw\" position. The class\n\t\t * controls the minor aspects of the balloon's visual appearance like the placement\n\t\t * of an {@link #withArrow arrow}. To support a new position, an additional CSS must be created.\n\t\t *\n\t\t * Default position names correspond with\n\t\t * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.\n\t\t *\n\t\t * See the {@link #attachTo} and {@link #pin} methods to learn about custom balloon positions.\n\t\t *\n\t\t * @observable\n\t\t * @default 'arrow_nw'\n\t\t * @member {'arrow_nw'|'arrow_ne'|'arrow_sw'|'arrow_se'} #position\n\t\t */\n\t\tthis.set( 'position', 'arrow_nw' );\n\n\t\t/**\n\t\t * Controls whether the balloon panel is visible or not.\n\t\t *\n\t\t * @observable\n\t\t * @default false\n\t\t * @member {Boolean} #isVisible\n\t\t */\n\t\tthis.set( 'isVisible', false );\n\n\t\t/**\n\t\t * Controls whether the balloon panel has an arrow. The presence of the arrow\n\t\t * is reflected in the `ck-balloon-panel_with-arrow` CSS class.\n\t\t *\n\t\t * @observable\n\t\t * @default true\n\t\t * @member {Boolean} #withArrow\n\t\t */\n\t\tthis.set( 'withArrow', true );\n\n\t\t/**\n\t\t * An additional CSS class added to the {@link #element}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #class\n\t\t */\n\t\tthis.set( 'class' );\n\n\t\t/**\n\t\t * A callback that starts pinning the panel when {@link #isVisible} gets\n\t\t * `true`. Used by {@link #pin}.\n\t\t *\n\t\t * @private\n\t\t * @member {Function} #_pinWhenIsVisibleCallback\n\t\t */\n\n\t\t/**\n\t\t * A collection of the child views that creates the balloon panel contents.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.content = this.createCollection();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-balloon-panel',\n\t\t\t\t\tbind.to( 'position', value => `ck-balloon-panel_${ value }` ),\n\t\t\t\t\tbind.if( 'isVisible', 'ck-balloon-panel_visible' ),\n\t\t\t\t\tbind.if( 'withArrow', 'ck-balloon-panel_with-arrow' ),\n\t\t\t\t\tbind.to( 'class' )\n\t\t\t\t],\n\n\t\t\t\tstyle: {\n\t\t\t\t\ttop: bind.to( 'top', toPx ),\n\t\t\t\t\tleft: bind.to( 'left', toPx )\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tchildren: this.content\n\t\t} );\n\t}\n\n\t/**\n\t * Shows the panel.\n\t *\n\t * See {@link #isVisible}.\n\t */\n\tshow() {\n\t\tthis.isVisible = true;\n\t}\n\n\t/**\n\t * Hides the panel.\n\t *\n\t * See {@link #isVisible}.\n\t */\n\thide() {\n\t\tthis.isVisible = false;\n\t}\n\n\t/**\n\t * Attaches the panel to a specified {@link module:utils/dom/position~Options#target} with a\n\t * smart positioning heuristics that chooses from available positions to make sure the panel\n\t * is visible to the user i.e. within the limits of the viewport.\n\t *\n\t * This method accepts configuration {@link module:utils/dom/position~Options options}\n\t * to set the `target`, optional `limiter` and `positions` the balloon should choose from.\n\t *\n\t *\t\tconst panel = new BalloonPanelView( locale );\n\t *\t\tconst positions = BalloonPanelView.defaultPositions;\n\t *\n\t *\t\tpanel.render();\n\t *\n\t *\t\t// Attach the panel to an element with the \"target\" id DOM.\n\t *\t\tpanel.attachTo( {\n\t *\t\t\ttarget: document.querySelector( '#target' ),\n\t *\t\t\tpositions: [\n\t *\t\t\t\tpositions.northArrowSouth,\n\t *\t\t\t\tpositions.southArrowNorth\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t * **Note**: Attaching the panel will also automatically {@link #show} it.\n\t *\n\t * **Note**: An attached panel will not follow its target when the window is scrolled or resized.\n\t * See the {@link #pin} method for a more permanent positioning strategy.\n\t *\n\t * @param {module:utils/dom/position~Options} options Positioning options compatible with\n\t * {@link module:utils/dom/position~getOptimalPosition}. Default `positions` array is\n\t * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.\n\t */\n\tattachTo( options ) {\n\t\tthis.show();\n\n\t\tconst defaultPositions = BalloonPanelView.defaultPositions;\n\t\tconst positionOptions = Object.assign( {}, {\n\t\t\telement: this.element,\n\t\t\tpositions: [\n\t\t\t\tdefaultPositions.southArrowNorth,\n\t\t\t\tdefaultPositions.southArrowNorthMiddleWest,\n\t\t\t\tdefaultPositions.southArrowNorthMiddleEast,\n\t\t\t\tdefaultPositions.southArrowNorthWest,\n\t\t\t\tdefaultPositions.southArrowNorthEast,\n\t\t\t\tdefaultPositions.northArrowSouth,\n\t\t\t\tdefaultPositions.northArrowSouthMiddleWest,\n\t\t\t\tdefaultPositions.northArrowSouthMiddleEast,\n\t\t\t\tdefaultPositions.northArrowSouthWest,\n\t\t\t\tdefaultPositions.northArrowSouthEast\n\t\t\t],\n\t\t\tlimiter: defaultLimiterElement,\n\t\t\tfitInViewport: true\n\t\t}, options );\n\n\t\tconst optimalPosition = BalloonPanelView._getOptimalPosition( positionOptions );\n\n\t\t// Usually browsers make some problems with super accurate values like 104.345px\n\t\t// so it is better to use int values.\n\t\tconst left = parseInt( optimalPosition.left );\n\t\tconst top = parseInt( optimalPosition.top );\n\t\tconst position = optimalPosition.name;\n\n\t\tObject.assign( this, { top, left, position } );\n\t}\n\n\t/**\n\t * Works the same way as the {@link #attachTo} method except that the position of the panel is\n\t * continuously updated when:\n\t *\n\t * * any ancestor of the {@link module:utils/dom/position~Options#target}\n\t * or {@link module:utils/dom/position~Options#limiter} is scrolled,\n\t * * the browser window gets resized or scrolled.\n\t *\n\t * Thanks to that, the panel always sticks to the {@link module:utils/dom/position~Options#target}\n\t * and is immune to the changing environment.\n\t *\n\t *\t\tconst panel = new BalloonPanelView( locale );\n\t *\t\tconst positions = BalloonPanelView.defaultPositions;\n\t *\n\t *\t\tpanel.render();\n\t *\n\t *\t\t// Pin the panel to an element with the \"target\" id DOM.\n\t *\t\tpanel.pin( {\n\t *\t\t\ttarget: document.querySelector( '#target' ),\n\t *\t\t\tpositions: [\n\t *\t\t\t\tpositions.northArrowSouth,\n\t *\t\t\t\tpositions.southArrowNorth\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t * To leave the pinned state, use the {@link #unpin} method.\n\t *\n\t * **Note**: Pinning the panel will also automatically {@link #show} it.\n\t *\n\t * @param {module:utils/dom/position~Options} options Positioning options compatible with\n\t * {@link module:utils/dom/position~getOptimalPosition}. Default `positions` array is\n\t * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.\n\t */\n\tpin( options ) {\n\t\tthis.unpin();\n\n\t\tthis._pinWhenIsVisibleCallback = () => {\n\t\t\tif ( this.isVisible ) {\n\t\t\t\tthis._startPinning( options );\n\t\t\t} else {\n\t\t\t\tthis._stopPinning();\n\t\t\t}\n\t\t};\n\n\t\tthis._startPinning( options );\n\n\t\t// Control the state of the listeners depending on whether the panel is visible\n\t\t// or not.\n\t\t// TODO: Use on() (https://github.com/ckeditor/ckeditor5-utils/issues/144).\n\t\tthis.listenTo( this, 'change:isVisible', this._pinWhenIsVisibleCallback );\n\t}\n\n\t/**\n\t * Stops pinning the panel, as set up by {@link #pin}.\n\t */\n\tunpin() {\n\t\tif ( this._pinWhenIsVisibleCallback ) {\n\t\t\t// Deactivate listeners attached by pin().\n\t\t\tthis._stopPinning();\n\n\t\t\t// Deactivate the panel pin() control logic.\n\t\t\t// TODO: Use off() (https://github.com/ckeditor/ckeditor5-utils/issues/144).\n\t\t\tthis.stopListening( this, 'change:isVisible', this._pinWhenIsVisibleCallback );\n\n\t\t\tthis._pinWhenIsVisibleCallback = null;\n\n\t\t\tthis.hide();\n\t\t}\n\t}\n\n\t/**\n\t * Starts managing the pinned state of the panel. See {@link #pin}.\n\t *\n\t * @private\n\t * @param {module:utils/dom/position~Options} options Positioning options compatible with\n\t * {@link module:utils/dom/position~getOptimalPosition}.\n\t */\n\t_startPinning( options ) {\n\t\tthis.attachTo( options );\n\n\t\tconst targetElement = getDomElement( options.target );\n\t\tconst limiterElement = options.limiter ? getDomElement( options.limiter ) : defaultLimiterElement;\n\n\t\t// Then we need to listen on scroll event of eny element in the document.\n\t\tthis.listenTo( global.document, 'scroll', ( evt, domEvt ) => {\n\t\t\tconst scrollTarget = domEvt.target;\n\n\t\t\t// The position needs to be updated if the positioning target is within the scrolled element.\n\t\t\tconst isWithinScrollTarget = targetElement && scrollTarget.contains( targetElement );\n\n\t\t\t// The position needs to be updated if the positioning limiter is within the scrolled element.\n\t\t\tconst isLimiterWithinScrollTarget = limiterElement && scrollTarget.contains( limiterElement );\n\n\t\t\t// The positioning target and/or limiter can be a Rect, object etc..\n\t\t\t// There's no way to optimize the listener then.\n\t\t\tif ( isWithinScrollTarget || isLimiterWithinScrollTarget || !targetElement || !limiterElement ) {\n\t\t\t\tthis.attachTo( options );\n\t\t\t}\n\t\t}, { useCapture: true } );\n\n\t\t// We need to listen on window resize event and update position.\n\t\tthis.listenTo( global.window, 'resize', () => {\n\t\t\tthis.attachTo( options );\n\t\t} );\n\t}\n\n\t/**\n\t * Stops managing the pinned state of the panel. See {@link #pin}.\n\t *\n\t * @private\n\t */\n\t_stopPinning() {\n\t\tthis.stopListening( global.document, 'scroll' );\n\t\tthis.stopListening( global.window, 'resize' );\n\t}\n}\n\n// Returns the DOM element for given object or null, if there is none,\n// e.g. when the passed object is a Rect instance or so.\n//\n// @private\n// @param {*} object\n// @returns {HTMLElement|null}\nfunction getDomElement( object ) {\n\tif ( isElement( object ) ) {\n\t\treturn object;\n\t}\n\n\tif ( isRange( object ) ) {\n\t\treturn object.commonAncestorContainer;\n\t}\n\n\tif ( typeof object == 'function' ) {\n\t\treturn getDomElement( object() );\n\t}\n\n\treturn null;\n}\n\n/**\n * A horizontal offset of the arrow tip from the edge of the balloon. Controlled by CSS.\n *\n *\t\t +-----|---------...\n *\t\t |     |\n *\t\t |     |\n *\t\t |     |\n *\t\t |     |\n *\t\t +--+  |  +------...\n *\t\t     \\ | /\n *\t\t      \\|/\n *\t    >|-----|<---------------- horizontal offset\n *\n * @default 30\n * @member {Number} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowHorizontalOffset\n */\nBalloonPanelView.arrowHorizontalOffset = 25;\n\n/**\n * A vertical offset of the arrow from the edge of the balloon. Controlled by CSS.\n *\n *\t\t +-------------...\n *\t\t |\n *\t\t |\n *\t\t |                      /-- vertical offset\n *\t\t |                     V\n *\t\t +--+    +-----...    ---------\n *\t\t     \\  /              |\n *\t\t      \\/               |\n *\t\t-------------------------------\n *\t\t                       ^\n *\n * @default 15\n * @member {Number} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowVerticalOffset\n */\nBalloonPanelView.arrowVerticalOffset = 10;\n\n/**\n * Function used to calculate the optimal position for the balloon.\n *\n * @protected\n * @member {Function} module:ui/panel/balloon/balloonpanelview~BalloonPanelView._getOptimalPosition\n */\nBalloonPanelView._getOptimalPosition = getOptimalPosition;\n\n/**\n * A default set of positioning functions used by the balloon panel view\n * when attaching using the {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#attachTo} method.\n *\n * The available positioning functions are as follows:\n *\n *\n *\n * **North west**\n *\n * * `northWestArrowSouthWest`\n *\n *\t\t+-----------------+\n *\t\t|     Balloon     |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n * * `northWestArrowSouthMiddleWest`\n *\n *\t\t+-----------------+\n *\t\t|     Balloon     |\n *\t\t+-----------------+\n *\t\t    V\n *\t\t    [ Target ]\n *\n * * `northWestArrowSouth`\n *\n *\t\t+-----------------+\n *\t\t|     Balloon     |\n *\t\t+-----------------+\n *\t\t         V\n *\t\t         [ Target ]\n *\n * * `northWestArrowSouthMiddleEast`\n *\n *\t\t+-----------------+\n *\t\t|     Balloon     |\n *\t\t+-----------------+\n *\t\t             V\n *\t\t             [ Target ]\n *\n * * `northWestArrowSouthEast`\n *\n *\t\t+-----------------+\n *\t\t|     Balloon     |\n *\t\t+-----------------+\n *\t\t                 V\n *\t\t                 [ Target ]\n *\n *\n *\n * **North**\n *\n * * `northArrowSouthWest`\n *\n *\t\t    +-----------------+\n *\t\t    |     Balloon     |\n *\t\t    +-----------------+\n *\t\t     V\n *\t\t[ Target ]\n *\n * * `northArrowSouthMiddleWest`\n *\n *\t\t +-----------------+\n *\t\t |     Balloon     |\n *\t\t +-----------------+\n *\t\t     V\n *\t\t[ Target ]\n *\n * * `northArrowSouth`\n *\n *\t\t+-----------------+\n *\t\t|     Balloon     |\n *\t\t+-----------------+\n *\t\t         V\n *\t\t    [ Target ]\n *\n * * `northArrowSouthMiddleEast`\n *\n *\t\t+-----------------+\n *\t\t|     Balloon     |\n *\t\t+-----------------+\n *\t\t             V\n *\t\t        [ Target ]\n *\n * * `northArrowSouthEast`\n *\n *\t\t+-----------------+\n *\t\t|     Balloon     |\n *\t\t+-----------------+\n *\t\t                V\n *\t\t           [ Target ]\n *\n * **North east**\n *\n * * `northEastArrowSouthWest`\n *\n *\t\t        +-----------------+\n *\t\t        |     Balloon     |\n *\t\t        +-----------------+\n *\t\t         V\n *\t\t[ Target ]\n *\n *\n * * `northEastArrowSouthMiddleWest`\n *\n *\t\t     +-----------------+\n *\t\t     |     Balloon     |\n *\t\t     +-----------------+\n *\t\t         V\n *\t\t[ Target ]\n *\n * * `northEastArrowSouth`\n *\n *\t\t+-----------------+\n *\t\t|     Balloon     |\n *\t\t+-----------------+\n *\t\t         V\n *\t\t[ Target ]\n *\n * * `northEastArrowSouthMiddleEast`\n *\n *\t\t+-----------------+\n *\t\t|     Balloon     |\n *\t\t+-----------------+\n *\t\t             V\n *\t\t    [ Target ]\n *\n * * `northEastArrowSouthEast`\n *\n *\t\t+-----------------+\n *\t\t|     Balloon     |\n *\t\t+-----------------+\n *\t\t                 V\n *\t\t        [ Target ]\n *\n *\n *\n * **South**\n *\n *\n * * `southArrowNorthWest`\n *\n *\t\t[ Target ]\n *\t\t     ^\n *\t\t    +-----------------+\n *\t\t    |     Balloon     |\n *\t\t    +-----------------+\n *\n * * `southArrowNorthMiddleWest`\n *\n *\t\t   [ Target ]\n *\t\t        ^\n *\t\t    +-----------------+\n *\t\t    |     Balloon     |\n *\t\t    +-----------------+\n *\n * * `southArrowNorth`\n *\n *\t\t    [ Target ]\n *\t\t         ^\n *\t\t+-----------------+\n *\t\t|     Balloon     |\n *\t\t+-----------------+\n *\n * * `southArrowNorthMiddleEast`\n *\n *\t\t            [ Target ]\n *\t\t                 ^\n *\t\t   +-----------------+\n *\t\t   |     Balloon     |\n *\t\t   +-----------------+\n *\n * * `southArrowNorthEast`\n *\n *\t\t            [ Target ]\n *\t\t                 ^\n *\t\t+-----------------+\n *\t\t|     Balloon     |\n *\t\t+-----------------+\n *\n *\n *\n * **South west**\n *\n * * `southWestArrowNorthWest`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t|     Balloon     |\n *\t\t+-----------------+\n *\n * * `southWestArrowNorthMiddleWest`\n *\n *\t\t     [ Target ]\n *\t\t     ^\n *\t\t +-----------------+\n *\t\t |     Balloon     |\n *\t\t +-----------------+\n *\n * * `southWestArrowNorth`\n *\n *\t\t         [ Target ]\n *\t\t         ^\n *\t\t+-----------------+\n *\t\t|     Balloon     |\n *\t\t+-----------------+\n *\n * * `southWestArrowNorthMiddleEast`\n *\n *\t\t              [ Target ]\n *\t\t              ^\n *\t\t+-----------------+\n *\t\t|     Balloon     |\n *\t\t+-----------------+\n *\n * * `southWestArrowNorthEast`\n *\n *\t\t                 [ Target ]\n *\t\t                 ^\n *\t\t+-----------------+\n *\t\t|     Balloon     |\n *\t\t+-----------------+\n *\n *\n *\n * **South east**\n *\n * * `southEastArrowNorthWest`\n *\n *\t\t[ Target ]\n *\t\t         ^\n *\t\t        +-----------------+\n *\t\t        |     Balloon     |\n *\t\t        +-----------------+\n* * `southEastArrowNorthMiddleWest`\n *\n *\t\t   [ Target ]\n *\t\t            ^\n *\t\t        +-----------------+\n *\t\t        |     Balloon     |\n *\t\t        +-----------------+\n *\n * * `southEastArrowNorth`\n *\n *\t\t[ Target ]\n *\t\t         ^\n *\t\t+-----------------+\n *\t\t|     Balloon     |\n *\t\t+-----------------+\n *\n * * `southEastArrowNorthMiddleEast`\n *\n *\t\t     [ Target ]\n *\t\t              ^\n *\t\t+-----------------+\n *\t\t|     Balloon     |\n *\t\t+-----------------+\n *\n * * `southEastArrowNorthEast`\n *\n *\t\t        [ Target ]\n *\t\t                 ^\n *\t\t+-----------------+\n *\t\t|     Balloon     |\n *\t\t+-----------------+\n *\n *\n * See {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#attachTo}.\n *\n * Positioning functions must be compatible with {@link module:utils/dom/position~Position}.\n *\n * The name that the position function returns will be reflected in the balloon panel's class that\n * controls the placement of the \"arrow\". See {@link #position} to learn more.\n *\n * @member {Object} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions\n */\nBalloonPanelView.defaultPositions = {\n\n\t// ------- North west\n\n\tnorthWestArrowSouthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sw'\n\t} ),\n\n\tnorthWestArrowSouthMiddleWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - ( balloonRect.width * .25 ) - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_smw'\n\t} ),\n\n\tnorthWestArrowSouth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - balloonRect.width / 2,\n\t\tname: 'arrow_s'\n\t} ),\n\n\tnorthWestArrowSouthMiddleEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - ( balloonRect.width * .75 ) + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sme'\n\t} ),\n\n\tnorthWestArrowSouthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_se'\n\t} ),\n\n\t// ------- North\n\n\tnorthArrowSouthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sw'\n\t} ),\n\n\tnorthArrowSouthMiddleWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - ( balloonRect.width * .25 ) - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_smw'\n\t} ),\n\n\tnorthArrowSouth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - balloonRect.width / 2,\n\t\tname: 'arrow_s'\n\t} ),\n\n\tnorthArrowSouthMiddleEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - ( balloonRect.width * .75 ) + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sme'\n\t} ),\n\n\tnorthArrowSouthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_se'\n\t} ),\n\n\t// ------- North east\n\n\tnorthEastArrowSouthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sw'\n\t} ),\n\n\tnorthEastArrowSouthMiddleWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - ( balloonRect.width * .25 ) - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_smw'\n\t} ),\n\tnorthEastArrowSouth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - balloonRect.width / 2,\n\t\tname: 'arrow_s'\n\t} ),\n\n\tnorthEastArrowSouthMiddleEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - ( balloonRect.width * .75 ) + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sme'\n\t} ),\n\n\tnorthEastArrowSouthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_se'\n\t} ),\n\t// ------- South west\n\n\tsouthWestArrowNorthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nw'\n\t} ),\n\n\tsouthWestArrowNorthMiddleWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - ( balloonRect.width * .25 ) - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nmw'\n\t} ),\n\n\tsouthWestArrowNorth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - balloonRect.width / 2,\n\t\tname: 'arrow_n'\n\t} ),\n\n\tsouthWestArrowNorthMiddleEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - ( balloonRect.width * .75 ) + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nme'\n\t} ),\n\n\tsouthWestArrowNorthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_ne'\n\t} ),\n\n\t// ------- South\n\n\tsouthArrowNorthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nw'\n\t} ),\n\tsouthArrowNorthMiddleWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - ( balloonRect.width * 0.25 ) - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nmw'\n\t} ),\n\n\tsouthArrowNorth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - balloonRect.width / 2,\n\t\tname: 'arrow_n'\n\t} ),\n\n\tsouthArrowNorthMiddleEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - ( balloonRect.width * 0.75 ) + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nme'\n\t} ),\n\n\tsouthArrowNorthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_ne'\n\t} ),\n\n\t// ------- South east\n\n\tsouthEastArrowNorthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nw'\n\t} ),\n\n\tsouthEastArrowNorthMiddleWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - ( balloonRect.width * .25 ) - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nmw'\n\t} ),\n\n\tsouthEastArrowNorth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - balloonRect.width / 2,\n\t\tname: 'arrow_n'\n\t} ),\n\n\tsouthEastArrowNorthMiddleEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - ( balloonRect.width * .75 ) + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nme'\n\t} ),\n\n\tsouthEastArrowNorthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_ne'\n\t} )\n\n};\n\n// Returns the top coordinate for positions starting with `north*`.\n//\n// @private\n// @param {utils/dom/rect~Rect} targetRect A rect of the target.\n// @param {utils/dom/rect~Rect} elementRect A rect of the balloon.\n// @returns {Number}\nfunction getNorthTop( targetRect, balloonRect ) {\n\treturn targetRect.top - balloonRect.height - BalloonPanelView.arrowVerticalOffset;\n}\n\n// Returns the top coordinate for positions starting with `south*`.\n//\n// @private\n// @param {utils/dom/rect~Rect} targetRect A rect of the target.\n// @param {utils/dom/rect~Rect} elementRect A rect of the balloon.\n// @returns {Number}\nfunction getSouthTop( targetRect ) {\n\treturn targetRect.bottom + BalloonPanelView.arrowVerticalOffset;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module widget/widgettypearound/utils\n */\n\nimport { isWidget } from '../utils';\n\n/**\n * The name of the type around model selection attribute responsible for\n * displaying a fake caret next to a selected widget.\n */\nexport const TYPE_AROUND_SELECTION_ATTRIBUTE = 'widget-type-around';\n\n/**\n * Checks if an element is a widget that qualifies to get the widget type around UI.\n *\n * @param {module:engine/view/element~Element} viewElement\n * @param {module:engine/model/element~Element} modelElement\n * @param {module:engine/model/schema~Schema} schema\n * @returns {Boolean}\n */\nexport function isTypeAroundWidget( viewElement, modelElement, schema ) {\n\treturn viewElement && isWidget( viewElement ) && !schema.isInline( modelElement );\n}\n\n/**\n * For the passed HTML element, this helper finds the closest widget type around button ancestor.\n *\n * @param {HTMLElement} domElement\n * @returns {HTMLElement|null}\n */\nexport function getClosestTypeAroundDomButton( domElement ) {\n\treturn domElement.closest( '.ck-widget__type-around__button' );\n}\n\n/**\n * For the passed widget type around button element, this helper determines at which position\n * the paragraph would be inserted into the content if, for instance, the button was\n * clicked by the user.\n *\n * @param {HTMLElement} domElement\n * @returns {'before'|'after'} The position of the button.\n */\nexport function getTypeAroundButtonPosition( domElement ) {\n\treturn domElement.classList.contains( 'ck-widget__type-around__button_before' ) ? 'before' : 'after';\n}\n\n/**\n * For the passed HTML element, this helper returns the closest view widget ancestor.\n *\n * @param {HTMLElement} domElement\n * @param {module:engine/view/domconverter~DomConverter} domConverter\n * @returns {module:engine/view/element~Element}\n */\nexport function getClosestWidgetViewElement( domElement, domConverter ) {\n\tconst widgetDomElement = domElement.closest( '.ck-widget' );\n\n\treturn domConverter.mapDomToView( widgetDomElement );\n}\n\n/**\n * For the passed selection instance, it returns the position of the fake caret displayed next to a widget.\n *\n * **Note**: If the fake caret is not currently displayed, `null` is returned.\n *\n * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n * @returns {'before'|'after'|null} The position of the fake caret or `null` when none is present.\n */\nexport function getTypeAroundFakeCaretPosition( selection ) {\n\treturn selection.getAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module widget/utils\n */\n\nimport HighlightStack from './highlightstack';\nimport IconView from '@ckeditor/ckeditor5-ui/src/icon/iconview';\nimport Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';\nimport BalloonPanelView from '@ckeditor/ckeditor5-ui/src/panel/balloon/balloonpanelview';\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport toArray from '@ckeditor/ckeditor5-utils/src/toarray';\n\nimport dragHandleIcon from '../theme/icons/drag-handle.svg';\nimport { getTypeAroundFakeCaretPosition } from './widgettypearound/utils';\n\n/**\n * CSS class added to each widget element.\n *\n * @const {String}\n */\nexport const WIDGET_CLASS_NAME = 'ck-widget';\n\n/**\n * CSS class added to currently selected widget element.\n *\n * @const {String}\n */\nexport const WIDGET_SELECTED_CLASS_NAME = 'ck-widget_selected';\n\n/**\n * Returns `true` if given {@link module:engine/view/node~Node} is an {@link module:engine/view/element~Element} and a widget.\n *\n * @param {module:engine/view/node~Node} node\n * @returns {Boolean}\n */\nexport function isWidget( node ) {\n\tif ( !node.is( 'element' ) ) {\n\t\treturn false;\n\t}\n\n\treturn !!node.getCustomProperty( 'widget' );\n}\n\n/**\n * Converts the given {@link module:engine/view/element~Element} to a widget in the following way:\n *\n * * sets the `contenteditable` attribute to `\"false\"`,\n * * adds the `ck-widget` CSS class,\n * * adds a custom {@link module:engine/view/element~Element#getFillerOffset `getFillerOffset()`} method returning `null`,\n * * adds a custom property allowing to recognize widget elements by using {@link ~isWidget `isWidget()`},\n * * implements the {@link ~setHighlightHandling view highlight on widgets}.\n *\n * This function needs to be used in conjunction with\n * {@link module:engine/conversion/downcasthelpers~DowncastHelpers downcast conversion helpers}\n * like {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`}.\n * Moreover, typically you will want to use `toWidget()` only for `editingDowncast`, while keeping the `dataDowncast` clean.\n *\n * For example, in order to convert a `<widget>` model element to `<div class=\"widget\">` in the view, you can define\n * such converters:\n *\n *\t\teditor.conversion.for( 'editingDowncast' )\n *\t\t\t.elementToElement( {\n *\t\t\t\tmodel: 'widget',\n *\t\t\t\tview: ( modelItem, { writer } ) => {\n *\t\t\t\t\tconst div = writer.createContainerElement( 'div', { class: 'widget' } );\n *\n *\t\t\t\t\treturn toWidget( div, writer, { label: 'some widget' } );\n *\t\t\t\t}\n *\t\t\t} );\n *\n *\t\teditor.conversion.for( 'dataDowncast' )\n *\t\t\t.elementToElement( {\n *\t\t\t\tmodel: 'widget',\n *\t\t\t\tview: ( modelItem, { writer } ) => {\n *\t\t\t\t\treturn writer.createContainerElement( 'div', { class: 'widget' } );\n *\t\t\t\t}\n *\t\t\t} );\n *\n * See the full source code of the widget (with a nested editable) schema definition and converters in\n * [this sample](https://github.com/ckeditor/ckeditor5-widget/blob/master/tests/manual/widget-with-nestededitable.js).\n *\n * @param {module:engine/view/element~Element} element\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {Object} [options={}]\n * @param {String|Function} [options.label] Element's label provided to the {@link ~setLabel} function. It can be passed as\n * a plain string or a function returning a string. It represents the widget for assistive technologies (like screen readers).\n * @param {Boolean} [options.hasSelectionHandle=false] If `true`, the widget will have a selection handle added.\n * @returns {module:engine/view/element~Element} Returns the same element.\n */\nexport function toWidget( element, writer, options = {} ) {\n\tif ( !element.is( 'containerElement' ) ) {\n\t\t/**\n\t\t * The element passed to `toWidget()` must be a {@link module:engine/view/containerelement~ContainerElement}\n\t\t * instance.\n\t\t *\n\t\t * @error widget-to-widget-wrong-element-type\n\t\t * @param {String} element The view element passed to `toWidget()`.\n\t\t */\n\t\tthrow new CKEditorError(\n\t\t\t'widget-to-widget-wrong-element-type',\n\t\t\tnull,\n\t\t\t{ element }\n\t\t);\n\t}\n\n\twriter.setAttribute( 'contenteditable', 'false', element );\n\n\twriter.addClass( WIDGET_CLASS_NAME, element );\n\twriter.setCustomProperty( 'widget', true, element );\n\telement.getFillerOffset = getFillerOffset;\n\n\tif ( options.label ) {\n\t\tsetLabel( element, options.label, writer );\n\t}\n\n\tif ( options.hasSelectionHandle ) {\n\t\taddSelectionHandle( element, writer );\n\t}\n\n\tsetHighlightHandling(\n\t\telement,\n\t\twriter,\n\t\t( element, descriptor, writer ) => writer.addClass( toArray( descriptor.classes ), element ),\n\t\t( element, descriptor, writer ) => writer.removeClass( toArray( descriptor.classes ), element )\n\t);\n\n\treturn element;\n}\n\n/**\n * Sets highlight handling methods. Uses {@link module:widget/highlightstack~HighlightStack} to\n * properly determine which highlight descriptor should be used at given time.\n *\n * @param {module:engine/view/element~Element} element\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {Function} add\n * @param {Function} remove\n */\nexport function setHighlightHandling( element, writer, add, remove ) {\n\tconst stack = new HighlightStack();\n\n\tstack.on( 'change:top', ( evt, data ) => {\n\t\tif ( data.oldDescriptor ) {\n\t\t\tremove( element, data.oldDescriptor, data.writer );\n\t\t}\n\n\t\tif ( data.newDescriptor ) {\n\t\t\tadd( element, data.newDescriptor, data.writer );\n\t\t}\n\t} );\n\n\twriter.setCustomProperty( 'addHighlight', ( element, descriptor, writer ) => stack.add( descriptor, writer ), element );\n\twriter.setCustomProperty( 'removeHighlight', ( element, id, writer ) => stack.remove( id, writer ), element );\n}\n\n/**\n * Sets label for given element.\n * It can be passed as a plain string or a function returning a string. Function will be called each time label is retrieved by\n * {@link ~getLabel `getLabel()`}.\n *\n * @param {module:engine/view/element~Element} element\n * @param {String|Function} labelOrCreator\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n */\nexport function setLabel( element, labelOrCreator, writer ) {\n\twriter.setCustomProperty( 'widgetLabel', labelOrCreator, element );\n}\n\n/**\n * Returns the label of the provided element.\n *\n * @param {module:engine/view/element~Element} element\n * @returns {String}\n */\nexport function getLabel( element ) {\n\tconst labelCreator = element.getCustomProperty( 'widgetLabel' );\n\n\tif ( !labelCreator ) {\n\t\treturn '';\n\t}\n\n\treturn typeof labelCreator == 'function' ? labelCreator() : labelCreator;\n}\n\n/**\n * Adds functionality to the provided {@link module:engine/view/editableelement~EditableElement} to act as a widget's editable:\n *\n * * sets the `contenteditable` attribute to `true` when {@link module:engine/view/editableelement~EditableElement#isReadOnly} is `false`,\n * otherwise sets it to `false`,\n * * adds the `ck-editor__editable` and `ck-editor__nested-editable` CSS classes,\n * * adds the `ck-editor__nested-editable_focused` CSS class when the editable is focused and removes it when it is blurred.\n *\n * Similarly to {@link ~toWidget `toWidget()`} this function should be used in `editingDowncast` only and it is usually\n * used together with {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`}.\n *\n * For example, in order to convert a `<nested>` model element to `<div class=\"nested\">` in the view, you can define\n * such converters:\n *\n *\t\teditor.conversion.for( 'editingDowncast' )\n *\t\t\t.elementToElement( {\n *\t\t\t\tmodel: 'nested',\n *\t\t\t\tview: ( modelItem, { writer } ) => {\n *\t\t\t\t\tconst div = writer.createEditableElement( 'div', { class: 'nested' } );\n *\n *\t\t\t\t\treturn toWidgetEditable( nested, writer );\n *\t\t\t\t}\n *\t\t\t} );\n *\n *\t\teditor.conversion.for( 'dataDowncast' )\n *\t\t\t.elementToElement( {\n *\t\t\t\tmodel: 'nested',\n *\t\t\t\tview: ( modelItem, { writer } ) => {\n *\t\t\t\t\treturn writer.createContainerElement( 'div', { class: 'nested' } );\n *\t\t\t\t}\n *\t\t\t} );\n *\n * See the full source code of the widget (with nested editable) schema definition and converters in\n * [this sample](https://github.com/ckeditor/ckeditor5-widget/blob/master/tests/manual/widget-with-nestededitable.js).\n *\n * @param {module:engine/view/editableelement~EditableElement} editable\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @returns {module:engine/view/editableelement~EditableElement} Returns the same element that was provided in the `editable` parameter\n */\nexport function toWidgetEditable( editable, writer ) {\n\twriter.addClass( [ 'ck-editor__editable', 'ck-editor__nested-editable' ], editable );\n\n\t// Set initial contenteditable value.\n\twriter.setAttribute( 'contenteditable', editable.isReadOnly ? 'false' : 'true', editable );\n\n\t// Bind the contenteditable property to element#isReadOnly.\n\teditable.on( 'change:isReadOnly', ( evt, property, is ) => {\n\t\twriter.setAttribute( 'contenteditable', is ? 'false' : 'true', editable );\n\t} );\n\n\teditable.on( 'change:isFocused', ( evt, property, is ) => {\n\t\tif ( is ) {\n\t\t\twriter.addClass( 'ck-editor__nested-editable_focused', editable );\n\t\t} else {\n\t\t\twriter.removeClass( 'ck-editor__nested-editable_focused', editable );\n\t\t}\n\t} );\n\n\treturn editable;\n}\n\n/**\n * Returns a model position which is optimal (in terms of UX) for inserting a widget block.\n *\n * For instance, if a selection is in the middle of a paragraph, the position before this paragraph\n * will be returned so that it is not split. If the selection is at the end of a paragraph,\n * the position after this paragraph will be returned.\n *\n * Note: If the selection is placed in an empty block, that block will be returned. If that position\n * is then passed to {@link module:engine/model/model~Model#insertContent},\n * the block will be fully replaced by the image.\n *\n * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n * The selection based on which the insertion position should be calculated.\n * @param {module:engine/model/model~Model} model Model instance.\n * @returns {module:engine/model/position~Position} The optimal position.\n */\nexport function findOptimalInsertionPosition( selection, model ) {\n\tconst selectedElement = selection.getSelectedElement();\n\n\tif ( selectedElement ) {\n\t\tconst typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition( selection );\n\n\t\t// If the WidgetTypeAround \"fake caret\" is displayed, use its position for the insertion\n\t\t// to provide the most predictable UX (https://github.com/ckeditor/ckeditor5/issues/7438).\n\t\tif ( typeAroundFakeCaretPosition ) {\n\t\t\treturn model.createPositionAt( selectedElement, typeAroundFakeCaretPosition );\n\t\t}\n\n\t\tif ( model.schema.isBlock( selectedElement ) ) {\n\t\t\treturn model.createPositionAfter( selectedElement );\n\t\t}\n\t}\n\n\tconst firstBlock = selection.getSelectedBlocks().next().value;\n\n\tif ( firstBlock ) {\n\t\t// If inserting into an empty block – return position in that block. It will get\n\t\t// replaced with the image by insertContent(). #42.\n\t\tif ( firstBlock.isEmpty ) {\n\t\t\treturn model.createPositionAt( firstBlock, 0 );\n\t\t}\n\n\t\tconst positionAfter = model.createPositionAfter( firstBlock );\n\n\t\t// If selection is at the end of the block - return position after the block.\n\t\tif ( selection.focus.isTouching( positionAfter ) ) {\n\t\t\treturn positionAfter;\n\t\t}\n\n\t\t// Otherwise return position before the block.\n\t\treturn model.createPositionBefore( firstBlock );\n\t}\n\n\treturn selection.focus;\n}\n\n/**\n * A util to be used in order to map view positions to correct model positions when implementing a widget\n * which renders non-empty view element for an empty model element.\n *\n * For example:\n *\n *\t\t// Model:\n *\t\t<placeholder type=\"name\"></placeholder>\n *\n *\t\t// View:\n *\t\t<span class=\"placeholder\">name</span>\n *\n * In such case, view positions inside `<span>` cannot be correct mapped to the model (because the model element is empty).\n * To handle mapping positions inside `<span class=\"placeholder\">` to the model use this util as follows:\n *\n *\t\teditor.editing.mapper.on(\n *\t\t\t'viewToModelPosition',\n *\t\t\tviewToModelPositionOutsideModelElement( model, viewElement => viewElement.hasClass( 'placeholder' ) )\n *\t\t);\n *\n * The callback will try to map the view offset of selection to an expected model position.\n *\n * 1. When the position is at the end (or in the middle) of the inline widget:\n *\n *\t\t// View:\n *\t\t<p>foo <span class=\"placeholder\">name|</span> bar</p>\n *\n *\t\t// Model:\n *\t\t<paragraph>foo <placeholder type=\"name\"></placeholder>| bar</paragraph>\n *\n * 2. When the position is at the beginning of the inline widget:\n *\n *\t\t// View:\n *\t\t<p>foo <span class=\"placeholder\">|name</span> bar</p>\n *\n *\t\t// Model:\n *\t\t<paragraph>foo |<placeholder type=\"name\"></placeholder> bar</paragraph>\n *\n * @param {module:engine/model/model~Model} model Model instance on which the callback operates.\n * @param {Function} viewElementMatcher Function that is passed a view element and should return `true` if the custom mapping\n * should be applied to the given view element.\n * @return {Function}\n */\nexport function viewToModelPositionOutsideModelElement( model, viewElementMatcher ) {\n\treturn ( evt, data ) => {\n\t\tconst { mapper, viewPosition } = data;\n\n\t\tconst viewParent = mapper.findMappedViewAncestor( viewPosition );\n\n\t\tif ( !viewElementMatcher( viewParent ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst modelParent = mapper.toModelElement( viewParent );\n\n\t\tdata.modelPosition = model.createPositionAt( modelParent, viewPosition.isAtStart ? 'before' : 'after' );\n\t};\n}\n\n/**\n * A positioning function passed to the {@link module:utils/dom/position~getOptimalPosition} helper as a last resort\n * when attaching {@link  module:ui/panel/balloon/balloonpanelview~BalloonPanelView balloon UI} to widgets.\n * It comes in handy when a widget is longer than the visual viewport of the web browser and/or upper/lower boundaries\n * of a widget are off screen because of the web page scroll.\n *\n *\t                                       ┌─┄┄┄┄┄┄┄┄┄Widget┄┄┄┄┄┄┄┄┄┐\n *\t                                       ┊                         ┊\n *\t┌────────────Viewport───────────┐   ┌──╁─────────Viewport────────╁──┐\n *\t│  ┏━━━━━━━━━━Widget━━━━━━━━━┓  │   │  ┃            ^            ┃  │\n *\t│  ┃            ^            ┃  │   │  ┃   ╭───────/ \\───────╮   ┃  │\n *\t│  ┃   ╭───────/ \\───────╮   ┃  │   │  ┃   │     Balloon     │   ┃  │\n *\t│  ┃   │     Balloon     │   ┃  │   │  ┃   ╰─────────────────╯   ┃  │\n *\t│  ┃   ╰─────────────────╯   ┃  │   │  ┃                         ┃  │\n *\t│  ┃                         ┃  │   │  ┃                         ┃  │\n *\t│  ┃                         ┃  │   │  ┃                         ┃  │\n *\t│  ┃                         ┃  │   │  ┃                         ┃  │\n *\t│  ┃                         ┃  │   │  ┃                         ┃  │\n *\t│  ┃                         ┃  │   │  ┃                         ┃  │\n *\t│  ┃                         ┃  │   │  ┃                         ┃  │\n *\t└──╀─────────────────────────╀──┘   └──╀─────────────────────────╀──┘\n *\t   ┊                         ┊         ┊                         ┊\n *\t   ┊                         ┊         └┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘\n *\t   ┊                         ┊\n *\t   └┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘\n *\n * **Note**: Works best if used together with\n * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions default `BalloonPanelView` positions}\n * like `northArrowSouth` and `southArrowNorth`; the transition between these two and this position is smooth.\n *\n * @param {module:utils/dom/rect~Rect} widgetRect A rect of the widget.\n * @param {module:utils/dom/rect~Rect} balloonRect A rect of the balloon.\n * @returns {module:utils/dom/position~Position|null}\n */\nexport function centeredBalloonPositionForLongWidgets( widgetRect, balloonRect ) {\n\tconst viewportRect = new Rect( global.window );\n\tconst viewportWidgetInsersectionRect = viewportRect.getIntersection( widgetRect );\n\n\tconst balloonTotalHeight = balloonRect.height + BalloonPanelView.arrowVerticalOffset;\n\n\t// If there is enough space above or below the widget then this position should not be used.\n\tif ( widgetRect.top - balloonTotalHeight > viewportRect.top || widgetRect.bottom + balloonTotalHeight < viewportRect.bottom ) {\n\t\treturn null;\n\t}\n\n\t// Because this is a last resort positioning, to keep things simple we're not playing with positions of the arrow\n\t// like, for instance, \"south west\" or whatever. Just try to keep the balloon in the middle of the visible area of\n\t// the widget for as long as it is possible. If the widgets becomes invisible (because cropped by the viewport),\n\t// just... place the balloon in the middle of it (because why not?).\n\tconst targetRect = viewportWidgetInsersectionRect || widgetRect;\n\tconst left = targetRect.left + targetRect.width / 2 - balloonRect.width / 2;\n\n\treturn {\n\t\ttop: Math.max( widgetRect.top, 0 ) + BalloonPanelView.arrowVerticalOffset,\n\t\tleft,\n\t\tname: 'arrow_n'\n\t};\n}\n\n// Default filler offset function applied to all widget elements.\n//\n// @returns {null}\nfunction getFillerOffset() {\n\treturn null;\n}\n\n// Adds a drag handle to the widget.\n//\n// @param {module:engine/view/containerelement~ContainerElement}\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\nfunction addSelectionHandle( widgetElement, writer ) {\n\tconst selectionHandle = writer.createUIElement( 'div', { class: 'ck ck-widget__selection-handle' }, function( domDocument ) {\n\t\tconst domElement = this.toDomElement( domDocument );\n\n\t\t// Use the IconView from the ui library.\n\t\tconst icon = new IconView();\n\t\ticon.set( 'content', dragHandleIcon );\n\n\t\t// Render the icon view right away to append its #element to the selectionHandle DOM element.\n\t\ticon.render();\n\n\t\tdomElement.appendChild( icon.element );\n\n\t\treturn domElement;\n\t} );\n\n\t// Append the selection handle into the widget wrapper.\n\twriter.insert( writer.createPositionAt( widgetElement, 0 ), selectionHandle );\n\twriter.addClass( [ 'ck-widget_with-selection-handle' ], widgetElement );\n}\n","export default \"<svg viewBox=\\\"0 0 16 16\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M4 0v1H1v3H0V.5A.5.5 0 0 1 .5 0H4zm8 0h3.5a.5.5 0 0 1 .5.5V4h-1V1h-3V0zM4 16H.5a.5.5 0 0 1-.5-.5V12h1v3h3v1zm8 0v-1h3v-3h1v3.5a.5.5 0 0 1-.5.5H12z\\\"/><path fill-opacity=\\\".256\\\" d=\\\"M1 1h14v14H1z\\\"/><g class=\\\"ck-icon__selected-indicator\\\"><path d=\\\"M7 0h2v1H7V0zM0 7h1v2H0V7zm15 0h1v2h-1V7zm-8 8h2v1H7v-1z\\\"/><path fill-opacity=\\\".254\\\" d=\\\"M1 1h14v14H1z\\\"/></g></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/image/utils\n */\n\nimport { findOptimalInsertionPosition, isWidget, toWidget } from '@ckeditor/ckeditor5-widget/src/utils';\n\n/**\n * Converts a given {@link module:engine/view/element~Element} to an image widget:\n * * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to recognize the image widget element.\n * * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator.\n *\n * @param {module:engine/view/element~Element} viewElement\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer An instance of the view writer.\n * @param {String} label The element's label. It will be concatenated with the image `alt` attribute if one is present.\n * @returns {module:engine/view/element~Element}\n */\nexport function toImageWidget( viewElement, writer, label ) {\n\twriter.setCustomProperty( 'image', true, viewElement );\n\n\treturn toWidget( viewElement, writer, { label: labelCreator } );\n\n\tfunction labelCreator() {\n\t\tconst imgElement = getViewImgFromWidget( viewElement );\n\t\tconst altText = imgElement.getAttribute( 'alt' );\n\n\t\treturn altText ? `${ altText } ${ label }` : label;\n\t}\n}\n\n/**\n * Checks if a given view element is an image widget.\n *\n * @param {module:engine/view/element~Element} viewElement\n * @returns {Boolean}\n */\nexport function isImageWidget( viewElement ) {\n\treturn !!viewElement.getCustomProperty( 'image' ) && isWidget( viewElement );\n}\n\n/**\n * Returns an image widget editing view element if one is selected.\n *\n * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} selection\n * @returns {module:engine/view/element~Element|null}\n */\nexport function getSelectedImageWidget( selection ) {\n\tconst viewElement = selection.getSelectedElement();\n\n\tif ( viewElement && isImageWidget( viewElement ) ) {\n\t\treturn viewElement;\n\t}\n\n\treturn null;\n}\n\n/**\n * Checks if the provided model element is an `image`.\n *\n * @param {module:engine/model/element~Element} modelElement\n * @returns {Boolean}\n */\nexport function isImage( modelElement ) {\n\treturn !!modelElement && modelElement.is( 'element', 'image' );\n}\n\n/**\n * Handles inserting single file. This method unifies image insertion using {@link module:widget/utils~findOptimalInsertionPosition} method.\n *\n *\t\tinsertImage( model, { src: 'path/to/image.jpg' } );\n *\n * @param {module:engine/model/model~Model} model\n * @param {Object} [attributes={}] Attributes of inserted image\n * @param {module:engine/model/position~Position} [insertPosition] Position to insert the image. If not specified,\n * the {@link module:widget/utils~findOptimalInsertionPosition} logic will be applied.\n */\nexport function insertImage( model, attributes = {}, insertPosition = null ) {\n\tmodel.change( writer => {\n\t\tconst imageElement = writer.createElement( 'image', attributes );\n\n\t\tconst insertAtSelection = insertPosition || findOptimalInsertionPosition( model.document.selection, model );\n\n\t\tmodel.insertContent( imageElement, insertAtSelection );\n\n\t\t// Inserting an image might've failed due to schema regulations.\n\t\tif ( imageElement.parent ) {\n\t\t\twriter.setSelection( imageElement, 'on' );\n\t\t}\n\t} );\n}\n\n/**\n * Checks if image can be inserted at current model selection.\n *\n * @param {module:engine/model/model~Model} model\n * @returns {Boolean}\n */\nexport function isImageAllowed( model ) {\n\tconst schema = model.schema;\n\tconst selection = model.document.selection;\n\n\treturn isImageAllowedInParent( selection, schema, model ) &&\n\t\t!checkSelectionOnObject( selection, schema ) &&\n\t\tisInOtherImage( selection );\n}\n\n/**\n * Get view `<img>` element from the view widget (`<figure>`).\n *\n * Assuming that image is always a first child of a widget (ie. `figureView.getChild( 0 )`) is unsafe as other features might\n * inject their own elements to the widget.\n *\n * The `<img>` can be wrapped to other elements, e.g. `<a>`. Nested check required.\n *\n * @param {module:engine/view/element~Element} figureView\n * @returns {module:engine/view/element~Element}\n */\nexport function getViewImgFromWidget( figureView ) {\n\tconst figureChildren = [];\n\n\tfor ( const figureChild of figureView.getChildren() ) {\n\t\tfigureChildren.push( figureChild );\n\n\t\tif ( figureChild.is( 'element' ) ) {\n\t\t\tfigureChildren.push( ...figureChild.getChildren() );\n\t\t}\n\t}\n\n\treturn figureChildren.find( viewChild => viewChild.is( 'element', 'img' ) );\n}\n\n// Checks if image is allowed by schema in optimal insertion parent.\n//\n// @returns {Boolean}\nfunction isImageAllowedInParent( selection, schema, model ) {\n\tconst parent = getInsertImageParent( selection, model );\n\n\treturn schema.checkChild( parent, 'image' );\n}\n\n// Check if selection is on object.\n//\n// @returns {Boolean}\nfunction checkSelectionOnObject( selection, schema ) {\n\tconst selectedElement = selection.getSelectedElement();\n\n\treturn selectedElement && schema.isObject( selectedElement );\n}\n\n// Checks if selection is placed in other image (ie. in caption).\nfunction isInOtherImage( selection ) {\n\treturn [ ...selection.focus.getAncestors() ].every( ancestor => !ancestor.is( 'element', 'image' ) );\n}\n\n// Returns a node that will be used to insert image with `model.insertContent` to check if image can be placed there.\nfunction getInsertImageParent( selection, model ) {\n\tconst insertAt = findOptimalInsertionPosition( selection, model );\n\n\tconst parent = insertAt.parent;\n\n\tif ( parent.isEmpty && !parent.is( 'element', '$root' ) ) {\n\t\treturn parent.parent;\n\t}\n\n\treturn parent;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/image/converters\n */\n\nimport first from '@ckeditor/ckeditor5-utils/src/first';\nimport { getViewImgFromWidget } from './utils';\n\n/**\n * Returns a function that converts the image view representation:\n *\n *\t\t<figure class=\"image\"><img src=\"...\" alt=\"...\"></img></figure>\n *\n * to the model representation:\n *\n *\t\t<image src=\"...\" alt=\"...\"></image>\n *\n * The entire content of the `<figure>` element except the first `<img>` is being converted as children\n * of the `<image>` model element.\n *\n * @returns {Function}\n */\nexport function viewFigureToModel() {\n\treturn dispatcher => {\n\t\tdispatcher.on( 'element:figure', converter );\n\t};\n\n\tfunction converter( evt, data, conversionApi ) {\n\t\t// Do not convert if this is not an \"image figure\".\n\t\tif ( !conversionApi.consumable.test( data.viewItem, { name: true, classes: 'image' } ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Find an image element inside the figure element.\n\t\tconst viewImage = getViewImgFromWidget( data.viewItem );\n\n\t\t// Do not convert if image element is absent, is missing src attribute or was already converted.\n\t\tif ( !viewImage || !viewImage.hasAttribute( 'src' ) || !conversionApi.consumable.test( viewImage, { name: true } ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Convert view image to model image.\n\t\tconst conversionResult = conversionApi.convertItem( viewImage, data.modelCursor );\n\n\t\t// Get image element from conversion result.\n\t\tconst modelImage = first( conversionResult.modelRange.getItems() );\n\n\t\t// When image wasn't successfully converted then finish conversion.\n\t\tif ( !modelImage ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Convert rest of the figure element's children as an image children.\n\t\tconversionApi.convertChildren( data.viewItem, modelImage );\n\n\t\tconversionApi.updateConversionResult( modelImage, data );\n\t}\n}\n\n/**\n * Converter used to convert the `srcset` model image attribute to the `srcset`, `sizes` and `width` attributes in the view.\n *\n * @returns {Function}\n */\nexport function srcsetAttributeConverter() {\n\treturn dispatcher => {\n\t\tdispatcher.on( 'attribute:srcset:image', converter );\n\t};\n\n\tfunction converter( evt, data, conversionApi ) {\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst writer = conversionApi.writer;\n\t\tconst figure = conversionApi.mapper.toViewElement( data.item );\n\t\tconst img = getViewImgFromWidget( figure );\n\n\t\tif ( data.attributeNewValue === null ) {\n\t\t\tconst srcset = data.attributeOldValue;\n\n\t\t\tif ( srcset.data ) {\n\t\t\t\twriter.removeAttribute( 'srcset', img );\n\t\t\t\twriter.removeAttribute( 'sizes', img );\n\n\t\t\t\tif ( srcset.width ) {\n\t\t\t\t\twriter.removeAttribute( 'width', img );\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tconst srcset = data.attributeNewValue;\n\n\t\t\tif ( srcset.data ) {\n\t\t\t\twriter.setAttribute( 'srcset', srcset.data, img );\n\t\t\t\t// Always outputting `100vw`. See https://github.com/ckeditor/ckeditor5-image/issues/2.\n\t\t\t\twriter.setAttribute( 'sizes', '100vw', img );\n\n\t\t\t\tif ( srcset.width ) {\n\t\t\t\t\twriter.setAttribute( 'width', srcset.width, img );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport function modelToViewAttributeConverter( attributeKey ) {\n\treturn dispatcher => {\n\t\tdispatcher.on( `attribute:${ attributeKey }:image`, converter );\n\t};\n\n\tfunction converter( evt, data, conversionApi ) {\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst figure = conversionApi.mapper.toViewElement( data.item );\n\t\tconst img = getViewImgFromWidget( figure );\n\n\t\tviewWriter.setAttribute( data.attributeKey, data.attributeNewValue || '', img );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { insertImage, isImageAllowed } from './utils';\nimport toArray from '@ckeditor/ckeditor5-utils/src/toarray';\n\n/**\n * @module image/image/imageinsertcommand\n */\n\n/**\n * Insert image command.\n *\n * The command is registered by the {@link module:image/image/imageediting~ImageEditing} plugin as `'imageInsert'`.\n *\n * In order to insert an image at the current selection position\n * (according to the {@link module:widget/utils~findOptimalInsertionPosition} algorithm),\n * execute the command and specify the image source:\n *\n *\t\teditor.execute( 'imageInsert', { source: 'http://url.to.the/image' } );\n *\n * It is also possible to insert multiple images at once:\n *\n *\t\teditor.execute( 'imageInsert', {\n *\t\t\tsource:  [\n *\t\t\t\t'path/to/image.jpg',\n *\t\t\t\t'path/to/other-image.jpg'\n *\t\t\t]\n *\t\t} );\n *\n * @extends module:core/command~Command\n */\nexport default class ImageInsertCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.isEnabled = isImageAllowed( this.editor.model );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @fires execute\n\t * @param {Object} options Options for the executed command.\n\t * @param {String|Array.<String>} options.source The image source or an array of image sources to insert.\n\t */\n\texecute( options ) {\n\t\tconst model = this.editor.model;\n\n\t\tfor ( const src of toArray( options.source ) ) {\n\t\t\tinsertImage( model, { src } );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/image/imageediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ImageLoadObserver from './imageloadobserver';\n\nimport {\n\tviewFigureToModel,\n\tmodelToViewAttributeConverter,\n\tsrcsetAttributeConverter\n} from './converters';\n\nimport { toImageWidget } from './utils';\n\nimport ImageInsertCommand from './imageinsertcommand';\n\n/**\n * The image engine plugin.\n *\n * It registers:\n *\n * * `<image>` as a block element in the document schema, and allows `alt`, `src` and `srcset` attributes.\n * * converters for editing and data pipelines.\n * * `'imageInsert'` command.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\t\tconst t = editor.t;\n\t\tconst conversion = editor.conversion;\n\n\t\t// See https://github.com/ckeditor/ckeditor5-image/issues/142.\n\t\teditor.editing.view.addObserver( ImageLoadObserver );\n\n\t\t// Configure schema.\n\t\tschema.register( 'image', {\n\t\t\tisObject: true,\n\t\t\tisBlock: true,\n\t\t\tallowWhere: '$block',\n\t\t\tallowAttributes: [ 'alt', 'src', 'srcset' ]\n\t\t} );\n\n\t\tconversion.for( 'dataDowncast' ).elementToElement( {\n\t\t\tmodel: 'image',\n\t\t\tview: ( modelElement, { writer } ) => createImageViewElement( writer )\n\t\t} );\n\n\t\tconversion.for( 'editingDowncast' ).elementToElement( {\n\t\t\tmodel: 'image',\n\t\t\tview: ( modelElement, { writer } ) => toImageWidget( createImageViewElement( writer ), writer, t( 'image widget' ) )\n\t\t} );\n\n\t\tconversion.for( 'downcast' )\n\t\t\t.add( modelToViewAttributeConverter( 'src' ) )\n\t\t\t.add( modelToViewAttributeConverter( 'alt' ) )\n\t\t\t.add( srcsetAttributeConverter() );\n\n\t\tconversion.for( 'upcast' )\n\t\t\t.elementToElement( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'img',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tsrc: true\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tmodel: ( viewImage, { writer } ) => writer.createElement( 'image', { src: viewImage.getAttribute( 'src' ) } )\n\t\t\t} )\n\t\t\t.attributeToAttribute( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'img',\n\t\t\t\t\tkey: 'alt'\n\t\t\t\t},\n\t\t\t\tmodel: 'alt'\n\t\t\t} )\n\t\t\t.attributeToAttribute( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'img',\n\t\t\t\t\tkey: 'srcset'\n\t\t\t\t},\n\t\t\t\tmodel: {\n\t\t\t\t\tkey: 'srcset',\n\t\t\t\t\tvalue: viewImage => {\n\t\t\t\t\t\tconst value = {\n\t\t\t\t\t\t\tdata: viewImage.getAttribute( 'srcset' )\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif ( viewImage.hasAttribute( 'width' ) ) {\n\t\t\t\t\t\t\tvalue.width = viewImage.getAttribute( 'width' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn value;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.add( viewFigureToModel() );\n\n\t\teditor.commands.add( 'imageInsert', new ImageInsertCommand( editor ) );\n\t}\n}\n\n// Creates a view element representing the image.\n//\n//\t\t<figure class=\"image\"><img></img></figure>\n//\n// Note that `alt` and `src` attributes are converted separately, so they are not included.\n//\n// @private\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @returns {module:engine/view/containerelement~ContainerElement}\nexport function createImageViewElement( writer ) {\n\tconst emptyElement = writer.createEmptyElement( 'img' );\n\tconst figure = writer.createContainerElement( 'figure', { class: 'image' } );\n\n\twriter.insert( writer.createPositionAt( figure, 0 ), emptyElement );\n\n\treturn figure;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/observer/mouseobserver\n */\n\nimport DomEventObserver from './domeventobserver';\n\n/**\n * Mouse events observer.\n *\n * Note that this observer is not available by default. To make it available it needs to be added to\n * {@link module:engine/view/view~View} by {@link module:engine/view/view~View#addObserver} method.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class MouseObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = 'mousedown';\n\t}\n\n\tonDomEvent( domEvent ) {\n\t\tthis.fire( domEvent.type, domEvent );\n\t}\n}\n\n/**\n * Fired when mouse button is pressed down on one of the editables.\n *\n * Introduced by {@link module:engine/view/observer/mouseobserver~MouseObserver}.\n *\n * Note that this event is not available by default. To make it available {@link module:engine/view/observer/mouseobserver~MouseObserver}\n * needs to be added to {@link module:engine/view/view~View} by a {@link module:engine/view/view~View#addObserver} method.\n *\n * @see module:engine/view/observer/mouseobserver~MouseObserver\n * @event module:engine/view/document~Document#event:mousedown\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/twostepcaretmovement\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport priorities from '@ckeditor/ckeditor5-utils/src/priorities';\n\n/**\n * This plugin enables the two-step caret (phantom) movement behavior for\n * {@link module:typing/twostepcaretmovement~TwoStepCaretMovement#registerAttribute registered attributes}\n * on arrow right (<kbd>→</kbd>) and left (<kbd>←</kbd>) key press.\n *\n * Thanks to this (phantom) caret movement the user is able to type before/after as well as at the\n * beginning/end of an attribute.\n *\n * **Note:** This plugin support right–to–left (Arabic, Hebrew, etc.) content by mirroring its behavior\n * but for the sake of simplicity examples showcase only left–to–right use–cases.\n *\n * # Forward movement\n *\n * ## \"Entering\" an attribute:\n *\n * When this plugin is enabled and registered for the `a` attribute and the selection is right before it\n * (at the attribute boundary), pressing the right arrow key will not move the selection but update its\n * attributes accordingly:\n *\n * * When enabled:\n *\n *   \t\tfoo{}<$text a=\"true\">bar</$text>\n *\n *    <kbd>→</kbd>\n *\n *   \t\tfoo<$text a=\"true\">{}bar</$text>\n *\n * * When disabled:\n *\n *   \t\tfoo{}<$text a=\"true\">bar</$text>\n *\n *   <kbd>→</kbd>\n *\n *   \t\tfoo<$text a=\"true\">b{}ar</$text>\n *\n *\n * ## \"Leaving\" an attribute:\n *\n * * When enabled:\n *\n *   \t\t<$text a=\"true\">bar{}</$text>baz\n *\n *    <kbd>→</kbd>\n *\n *   \t\t<$text a=\"true\">bar</$text>{}baz\n *\n * * When disabled:\n *\n *   \t\t<$text a=\"true\">bar{}</$text>baz\n *\n *   <kbd>→</kbd>\n *\n *   \t\t<$text a=\"true\">bar</$text>b{}az\n *\n * # Backward movement\n *\n * * When enabled:\n *\n *   \t\t<$text a=\"true\">bar</$text>{}baz\n *\n *    <kbd>←</kbd>\n *\n *   \t\t<$text a=\"true\">bar{}</$text>baz\n *\n * * When disabled:\n *\n *   \t\t<$text a=\"true\">bar</$text>{}baz\n *\n *   <kbd>←</kbd>\n *\n *   \t\t<$text a=\"true\">ba{}r</$text>b{}az\n *\n * # Multiple attributes\n *\n * * When enabled and many attributes starts or ends at the same position:\n *\n *   \t\t<$text a=\"true\" b=\"true\">bar</$text>{}baz\n *\n *    <kbd>←</kbd>\n *\n *   \t\t<$text a=\"true\" b=\"true\">bar{}</$text>baz\n *\n * * When enabled and one procedes another:\n *\n *   \t\t<$text a=\"true\">bar</$text><$text b=\"true\">{}bar</$text>\n *\n *    <kbd>←</kbd>\n *\n *   \t\t<$text a=\"true\">bar{}</$text><$text b=\"true\">bar</$text>\n *\n */\nexport default class TwoStepCaretMovement extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TwoStepCaretMovement';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * A set of attributes to handle.\n\t\t *\n\t\t * @protected\n\t\t * @property {module:typing/twostepcaretmovement~TwoStepCaretMovement}\n\t\t */\n\t\tthis.attributes = new Set();\n\n\t\t/**\n\t\t * The current UID of the overridden gravity, as returned by\n\t\t * {@link module:engine/model/writer~Writer#overrideSelectionGravity}.\n\t\t *\n\t\t * @private\n\t\t * @member {String}\n\t\t */\n\t\tthis._overrideUid = null;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst view = editor.editing.view;\n\t\tconst locale = editor.locale;\n\n\t\tconst modelSelection = model.document.selection;\n\n\t\t// Listen to keyboard events and handle the caret movement according to the 2-step caret logic.\n\t\t//\n\t\t// Note: This listener has the \"high+1\" priority:\n\t\t// * \"high\" because of the filler logic implemented in the renderer which also engages on #keydown.\n\t\t// When the gravity is overridden the attributes of the (model) selection attributes are reset.\n\t\t// It may end up with the filler kicking in and breaking the selection.\n\t\t// * \"+1\" because we would like to avoid collisions with other features (like Widgets), which\n\t\t// take over the keydown events with the \"high\" priority. Two-step caret movement takes precedence\n\t\t// over Widgets in that matter.\n\t\t//\n\t\t// Find out more in https://github.com/ckeditor/ckeditor5-engine/issues/1301.\n\t\tthis.listenTo( view.document, 'keydown', ( evt, data ) => {\n\t\t\t// This implementation works only for collapsed selection.\n\t\t\tif ( !modelSelection.isCollapsed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// When user tries to expand the selection or jump over the whole word or to the beginning/end then\n\t\t\t// two-steps movement is not necessary.\n\t\t\tif ( data.shiftKey || data.altKey || data.ctrlKey ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst arrowRightPressed = data.keyCode == keyCodes.arrowright;\n\t\t\tconst arrowLeftPressed = data.keyCode == keyCodes.arrowleft;\n\n\t\t\t// When neither left or right arrow has been pressed then do noting.\n\t\t\tif ( !arrowRightPressed && !arrowLeftPressed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst contentDirection = locale.contentLanguageDirection;\n\t\t\tlet isMovementHandled = false;\n\n\t\t\tif ( ( contentDirection === 'ltr' && arrowRightPressed ) || ( contentDirection === 'rtl' && arrowLeftPressed ) ) {\n\t\t\t\tisMovementHandled = this._handleForwardMovement( data );\n\t\t\t} else {\n\t\t\t\tisMovementHandled = this._handleBackwardMovement( data );\n\t\t\t}\n\n\t\t\t// Stop the keydown event if the two-step caret movement handled it. Avoid collisions\n\t\t\t// with other features which may also take over the caret movement (e.g. Widget).\n\t\t\tif ( isMovementHandled === true ) {\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: priorities.get( 'high' ) + 1 } );\n\n\t\t/**\n\t\t * A flag indicating that the automatic gravity restoration should not happen upon the next\n\t\t * gravity restoration.\n\t\t * {@link module:engine/model/selection~Selection#event:change:range} event.\n\t\t *\n\t\t * @private\n\t\t * @member {String}\n\t\t */\n\t\tthis._isNextGravityRestorationSkipped = false;\n\n\t\t// The automatic gravity restoration logic.\n\t\tthis.listenTo( modelSelection, 'change:range', ( evt, data ) => {\n\t\t\t// Skipping the automatic restoration is needed if the selection should change\n\t\t\t// but the gravity must remain overridden afterwards. See the #handleBackwardMovement\n\t\t\t// to learn more.\n\t\t\tif ( this._isNextGravityRestorationSkipped ) {\n\t\t\t\tthis._isNextGravityRestorationSkipped = false;\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Skip automatic restore when the gravity is not overridden — simply, there's nothing to restore\n\t\t\t// at this moment.\n\t\t\tif ( !this._isGravityOverridden ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Skip automatic restore when the change is indirect AND the selection is at the attribute boundary.\n\t\t\t// It means that e.g. if the change was external (collaboration) and the user had their\n\t\t\t// selection around the link, its gravity should remain intact in this change:range event.\n\t\t\tif ( !data.directChange && isBetweenDifferentAttributes( modelSelection.getFirstPosition(), this.attributes ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._restoreGravity();\n\t\t} );\n\t}\n\n\t/**\n\t * Registers a given attribute for the two-step caret movement.\n\t *\n\t * @param {String} attribute Name of the attribute to handle.\n\t */\n\tregisterAttribute( attribute ) {\n\t\tthis.attributes.add( attribute );\n\t}\n\n\t/**\n\t * Updates the document selection and the view according to the two–step caret movement state\n\t * when moving **forwards**. Executed upon `keypress` in the {@link module:engine/view/view~View}.\n\t *\n\t * @private\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} data Data of the key press.\n\t * @returns {Boolean} `true` when the handler prevented caret movement\n\t */\n\t_handleForwardMovement( data ) {\n\t\tconst attributes = this.attributes;\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst position = selection.getFirstPosition();\n\t\t// DON'T ENGAGE 2-SCM if gravity is already overridden. It means that we just entered\n\t\t//\n\t\t// \t\t<paragraph>foo<$text attribute>{}bar</$text>baz</paragraph>\n\t\t//\n\t\t// or left the attribute\n\t\t//\n\t\t// \t\t<paragraph>foo<$text attribute>bar</$text>{}baz</paragraph>\n\t\t//\n\t\t// and the gravity will be restored automatically.\n\t\tif ( this._isGravityOverridden ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// DON'T ENGAGE 2-SCM when the selection is at the beginning of the block AND already has the\n\t\t// attribute:\n\t\t// * when the selection was initially set there using the mouse,\n\t\t// * when the editor has just started\n\t\t//\n\t\t//\t\t<paragraph><$text attribute>{}bar</$text>baz</paragraph>\n\t\t//\n\t\tif ( position.isAtStart && hasAnyAttribute( selection, attributes ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// ENGAGE 2-SCM When at least one of the observed attributes changes its value (incl. starts, ends).\n\t\t//\n\t\t//\t\t<paragraph>foo<$text attribute>bar{}</$text>baz</paragraph>\n\t\t//\t\t<paragraph>foo<$text attribute>bar{}</$text><$text otherAttribute>baz</$text></paragraph>\n\t\t//\t\t<paragraph>foo<$text attribute=1>bar{}</$text><$text attribute=2>baz</$text></paragraph>\n\t\t//\t\t<paragraph>foo{}<$text attribute>bar</$text>baz</paragraph>\n\t\t//\n\t\tif ( isBetweenDifferentAttributes( position, attributes ) ) {\n\t\t\tpreventCaretMovement( data );\n\t\t\tthis._overrideGravity();\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t/**\n\t * Updates the document selection and the view according to the two–step caret movement state\n\t * when moving **backwards**. Executed upon `keypress` in the {@link module:engine/view/view~View}.\n\t *\n\t * @private\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} data Data of the key press.\n\t * @returns {Boolean} `true` when the handler prevented caret movement\n\t */\n\t_handleBackwardMovement( data ) {\n\t\tconst attributes = this.attributes;\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst position = selection.getFirstPosition();\n\n\t\t// When the gravity is already overridden (by this plugin), it means we are on the two-step position.\n\t\t// Prevent the movement, restore the gravity and update selection attributes.\n\t\t//\n\t\t//\t\t<paragraph>foo<$text attribute=1>bar</$text><$text attribute=2>{}baz</$text></paragraph>\n\t\t//\t\t<paragraph>foo<$text attribute>bar</$text><$text otherAttribute>{}baz</$text></paragraph>\n\t\t//\t\t<paragraph>foo<$text attribute>{}bar</$text>baz</paragraph>\n\t\t//\t\t<paragraph>foo<$text attribute>bar</$text>{}baz</paragraph>\n\t\t//\n\t\tif ( this._isGravityOverridden ) {\n\t\t\tpreventCaretMovement( data );\n\t\t\tthis._restoreGravity();\n\t\t\tsetSelectionAttributesFromTheNodeBefore( model, attributes, position );\n\n\t\t\treturn true;\n\t\t} else {\n\t\t\t// REMOVE SELECTION ATTRIBUTE when restoring gravity towards a non-existent content at the\n\t\t\t// beginning of the block.\n\t\t\t//\n\t\t\t// \t\t<paragraph>{}<$text attribute>bar</$text></paragraph>\n\t\t\t//\n\t\t\tif ( position.isAtStart ) {\n\t\t\t\tif ( hasAnyAttribute( selection, attributes ) ) {\n\t\t\t\t\tpreventCaretMovement( data );\n\t\t\t\t\tsetSelectionAttributesFromTheNodeBefore( model, attributes, position );\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// When we are moving from natural gravity, to the position of the 2SCM, we need to override the gravity,\n\t\t\t// and make sure it won't be restored. Unless it's at the end of the block and an observed attribute.\n\t\t\t// We need to check if the caret is a one position before the attribute boundary:\n\t\t\t//\n\t\t\t//\t\t<paragraph>foo<$text attribute=1>bar</$text><$text attribute=2>b{}az</$text></paragraph>\n\t\t\t//\t\t<paragraph>foo<$text attribute>bar</$text><$text otherAttribute>b{}az</$text></paragraph>\n\t\t\t//\t\t<paragraph>foo<$text attribute>b{}ar</$text>baz</paragraph>\n\t\t\t//\t\t<paragraph>foo<$text attribute>bar</$text>b{}az</paragraph>\n\t\t\t//\n\t\t\tif ( isStepAfterAnyAttributeBoundary( position, attributes ) ) {\n\t\t\t\t// ENGAGE 2-SCM if the selection has no attribute. This may happen when the user\n\t\t\t\t// left the attribute using a FORWARD 2-SCM.\n\t\t\t\t//\n\t\t\t\t// \t\t<paragraph><$text attribute>bar</$text>{}</paragraph>\n\t\t\t\t//\n\t\t\t\tif (\n\t\t\t\t\tposition.isAtEnd &&\n\t\t\t\t\t!hasAnyAttribute( selection, attributes ) &&\n\t\t\t\t\tisBetweenDifferentAttributes( position, attributes )\n\t\t\t\t) {\n\t\t\t\t\tpreventCaretMovement( data );\n\t\t\t\t\tsetSelectionAttributesFromTheNodeBefore( model, attributes, position );\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\t// Skip the automatic gravity restore upon the next selection#change:range event.\n\t\t\t\t// If not skipped, it would automatically restore the gravity, which should remain\n\t\t\t\t// overridden.\n\t\t\t\tthis._isNextGravityRestorationSkipped = true;\n\t\t\t\tthis._overrideGravity();\n\n\t\t\t\t// Don't return \"true\" here because we didn't call _preventCaretMovement.\n\t\t\t\t// Returning here will destabilize the filler logic, which also listens to\n\t\t\t\t// keydown (and the event would be stopped).\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * `true` when the gravity is overridden for the plugin.\n\t *\n\t * @readonly\n\t * @private\n\t * @type {Boolean}\n\t */\n\tget _isGravityOverridden() {\n\t\treturn !!this._overrideUid;\n\t}\n\n\t/**\n\t * Overrides the gravity using the {@link module:engine/model/writer~Writer model writer}\n\t * and stores the information about this fact in the {@link #_overrideUid}.\n\t *\n\t * A shorthand for {@link module:engine/model/writer~Writer#overrideSelectionGravity}.\n\t *\n\t * @private\n\t */\n\t_overrideGravity() {\n\t\tthis._overrideUid = this.editor.model.change( writer => {\n\t\t\treturn writer.overrideSelectionGravity();\n\t\t} );\n\t}\n\n\t/**\n\t * Restores the gravity using the {@link module:engine/model/writer~Writer model writer}.\n\t *\n\t * A shorthand for {@link module:engine/model/writer~Writer#restoreSelectionGravity}.\n\t *\n\t * @private\n\t */\n\t_restoreGravity() {\n\t\tthis.editor.model.change( writer => {\n\t\t\twriter.restoreSelectionGravity( this._overrideUid );\n\t\t\tthis._overrideUid = null;\n\t\t} );\n\t}\n}\n\n// Checks whether the selection has any of given attributes.\n//\n// @param {module:engine/model/documentselection~DocumentSelection} selection\n// @param {Iterable.<String>} attributes\nfunction hasAnyAttribute( selection, attributes ) {\n\tfor ( const observedAttribute of attributes ) {\n\t\tif ( selection.hasAttribute( observedAttribute ) ) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n// Applies the given attributes to the current selection using using the\n// values from the node before the current position. Uses\n// the {@link module:engine/model/writer~Writer model writer}.\n//\n// @param {module:engine/model/model~Model}\n// @param {Iterable.<String>} attributess\n// @param {module:engine/model/position~Position} position\nfunction setSelectionAttributesFromTheNodeBefore( model, attributes, position ) {\n\tconst nodeBefore = position.nodeBefore;\n\tmodel.change( writer => {\n\t\tif ( nodeBefore ) {\n\t\t\twriter.setSelectionAttribute( nodeBefore.getAttributes() );\n\t\t} else {\n\t\t\twriter.removeSelectionAttribute( attributes );\n\t\t}\n\t} );\n}\n\n// Prevents the caret movement in the view by calling `preventDefault` on the event data.\n//\n// @alias data.preventDefault\nfunction preventCaretMovement( data ) {\n\tdata.preventDefault();\n}\n\n// Checks whether the step before `isBetweenDifferentAttributes()`.\n//\n// @param {module:engine/model/position~Position} position\n// @param {String} attribute\nfunction isStepAfterAnyAttributeBoundary( position, attributes ) {\n\tconst positionBefore = position.getShiftedBy( -1 );\n\treturn isBetweenDifferentAttributes( positionBefore, attributes );\n}\n\n// Checks whether the given position is between different values of given attributes.\n//\n// @param {module:engine/model/position~Position} position\n// @param {Iterable.<String>} attributes\nfunction isBetweenDifferentAttributes( position, attributes ) {\n\tconst { nodeBefore, nodeAfter } = position;\n\tfor ( const observedAttribute of attributes ) {\n\t\tconst attrBefore = nodeBefore ? nodeBefore.getAttribute( observedAttribute ) : undefined;\n\t\tconst attrAfter = nodeAfter ? nodeAfter.getAttribute( observedAttribute ) : undefined;\n\n\t\tif ( attrAfter !== attrBefore ) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/utils/findattributerange\n */\n\n/**\n * Returns a model range that covers all consecutive nodes with the same `attributeName` and its `value`\n * that intersect the given `position`.\n *\n * It can be used e.g. to get the entire range on which the `linkHref` attribute needs to be changed when having a\n * selection inside a link.\n *\n * @param {module:engine/model/position~Position} position The start position.\n * @param {String} attributeName The attribute name.\n * @param {String} value The attribute value.\n * @param {module:engine/model/model~Model} model The model instance.\n * @returns {module:engine/model/range~Range} The link range.\n */\nexport default function findAttributeRange( position, attributeName, value, model ) {\n\treturn model.createRange(\n\t\t_findBound( position, attributeName, value, true, model ),\n\t\t_findBound( position, attributeName, value, false, model )\n\t);\n}\n\n// Walks forward or backward (depends on the `lookBack` flag), node by node, as long as they have the same attribute value\n// and returns a position just before or after (depends on the `lookBack` flag) the last matched node.\n//\n// @param {module:engine/model/position~Position} position The start position.\n// @param {String} attributeName The attribute name.\n// @param {String} value The attribute value.\n// @param {Boolean} lookBack Whether the walk direction is forward (`false`) or backward (`true`).\n// @returns {module:engine/model/position~Position} The position just before the last matched node.\nfunction _findBound( position, attributeName, value, lookBack, model ) {\n\t// Get node before or after position (depends on `lookBack` flag).\n\t// When position is inside text node then start searching from text node.\n\tlet node = position.textNode || ( lookBack ? position.nodeBefore : position.nodeAfter );\n\n\tlet lastNode = null;\n\n\twhile ( node && node.getAttribute( attributeName ) == value ) {\n\t\tlastNode = node;\n\t\tnode = lookBack ? node.previousSibling : node.nextSibling;\n\t}\n\n\treturn lastNode ? model.createPositionAt( lastNode, lookBack ? 'before' : 'after' ) : position;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module link/utils\n */\n\nimport toMap from '@ckeditor/ckeditor5-utils/src/tomap';\n\n/**\n * Helper class that ties together all {@link module:link/link~LinkDecoratorAutomaticDefinition} and provides\n * the {@link module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToElement downcast dispatchers} for them.\n */\nexport default class AutomaticDecorators {\n\tconstructor() {\n\t\t/**\n\t\t * Stores the definition of {@link module:link/link~LinkDecoratorAutomaticDefinition automatic decorators}.\n\t\t * This data is used as a source for a downcast dispatcher to create a proper conversion to output data.\n\t\t *\n\t\t * @private\n\t\t * @type {Set}\n\t\t */\n\t\tthis._definitions = new Set();\n\t}\n\n\t/**\n\t * Gives information about the number of decorators stored in the {@link module:link/utils~AutomaticDecorators} instance.\n\t *\n\t * @readonly\n\t * @protected\n\t * @type {Number}\n\t */\n\tget length() {\n\t\treturn this._definitions.size;\n\t}\n\n\t/**\n\t * Adds automatic decorator objects or an array with them to be used during downcasting.\n\t *\n\t * @param {module:link/link~LinkDecoratorAutomaticDefinition|Array.<module:link/link~LinkDecoratorAutomaticDefinition>} item\n\t * A configuration object of automatic rules for decorating links. It might also be an array of such objects.\n\t */\n\tadd( item ) {\n\t\tif ( Array.isArray( item ) ) {\n\t\t\titem.forEach( item => this._definitions.add( item ) );\n\t\t} else {\n\t\t\tthis._definitions.add( item );\n\t\t}\n\t}\n\n\t/**\n\t * Provides the conversion helper used in the {@link module:engine/conversion/downcasthelpers~DowncastHelpers#add} method.\n\t *\n\t * @returns {Function} A dispatcher function used as conversion helper\n\t * in {@link module:engine/conversion/downcasthelpers~DowncastHelpers#add}.\n\t */\n\tgetDispatcher() {\n\t\treturn dispatcher => {\n\t\t\tdispatcher.on( 'attribute:linkHref', ( evt, data, conversionApi ) => {\n\t\t\t\t// There is only test as this behavior decorates links and\n\t\t\t\t// it is run before dispatcher which actually consumes this node.\n\t\t\t\t// This allows on writing own dispatcher with highest priority,\n\t\t\t\t// which blocks both native converter and this additional decoration.\n\t\t\t\tif ( !conversionApi.consumable.test( data.item, 'attribute:linkHref' ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst viewWriter = conversionApi.writer;\n\t\t\t\tconst viewSelection = viewWriter.document.selection;\n\n\t\t\t\tfor ( const item of this._definitions ) {\n\t\t\t\t\tconst viewElement = viewWriter.createAttributeElement( 'a', item.attributes, {\n\t\t\t\t\t\tpriority: 5\n\t\t\t\t\t} );\n\t\t\t\t\tviewWriter.setCustomProperty( 'link', true, viewElement );\n\t\t\t\t\tif ( item.callback( data.attributeNewValue ) ) {\n\t\t\t\t\t\tif ( data.item.is( 'selection' ) ) {\n\t\t\t\t\t\t\tviewWriter.wrap( viewSelection.getFirstRange(), viewElement );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tviewWriter.wrap( conversionApi.mapper.toViewRange( data.range ), viewElement );\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tviewWriter.unwrap( conversionApi.mapper.toViewRange( data.range ), viewElement );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, { priority: 'high' } );\n\t\t};\n\t}\n\n\t/**\n\t * Provides the conversion helper used in the {@link module:engine/conversion/downcasthelpers~DowncastHelpers#add} method\n\t * when linking images.\n\t *\n\t * @returns {Function} A dispatcher function used as conversion helper\n\t * in {@link module:engine/conversion/downcasthelpers~DowncastHelpers#add}.\n\t */\n\tgetDispatcherForLinkedImage() {\n\t\treturn dispatcher => {\n\t\t\tdispatcher.on( 'attribute:linkHref:image', ( evt, data, conversionApi ) => {\n\t\t\t\tconst viewFigure = conversionApi.mapper.toViewElement( data.item );\n\t\t\t\tconst linkInImage = Array.from( viewFigure.getChildren() ).find( child => child.name === 'a' );\n\n\t\t\t\tfor ( const item of this._definitions ) {\n\t\t\t\t\tconst attributes = toMap( item.attributes );\n\n\t\t\t\t\tif ( item.callback( data.attributeNewValue ) ) {\n\t\t\t\t\t\tfor ( const [ key, val ] of attributes ) {\n\t\t\t\t\t\t\tif ( key === 'class' ) {\n\t\t\t\t\t\t\t\tconversionApi.writer.addClass( val, linkInImage );\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tconversionApi.writer.setAttribute( key, val, linkInImage );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfor ( const [ key, val ] of attributes ) {\n\t\t\t\t\t\t\tif ( key === 'class' ) {\n\t\t\t\t\t\t\t\tconversionApi.writer.removeClass( val, linkInImage );\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tconversionApi.writer.removeAttribute( key, linkInImage );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t};\n\t}\n}\n","import baseSlice from './_baseSlice.js';\n\n/**\n * Casts `array` to a slice if it's needed.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {number} start The start position.\n * @param {number} [end=array.length] The end position.\n * @returns {Array} Returns the cast slice.\n */\nfunction castSlice(array, start, end) {\n  var length = array.length;\n  end = end === undefined ? length : end;\n  return (!start && end >= length) ? array : baseSlice(array, start, end);\n}\n\nexport default castSlice;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n    rsComboMarksRange = '\\\\u0300-\\\\u036f',\n    reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n    rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n    rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n    rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsZWJ = '\\\\u200d';\n\n/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */\nvar reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange  + rsComboRange + rsVarRange + ']');\n\n/**\n * Checks if `string` contains Unicode symbols.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {boolean} Returns `true` if a symbol is found, else `false`.\n */\nfunction hasUnicode(string) {\n  return reHasUnicode.test(string);\n}\n\nexport default hasUnicode;\n","/**\n * Converts an ASCII `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction asciiToArray(string) {\n  return string.split('');\n}\n\nexport default asciiToArray;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n    rsComboMarksRange = '\\\\u0300-\\\\u036f',\n    reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n    rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n    rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n    rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsAstral = '[' + rsAstralRange + ']',\n    rsCombo = '[' + rsComboRange + ']',\n    rsFitz = '\\\\ud83c[\\\\udffb-\\\\udfff]',\n    rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',\n    rsNonAstral = '[^' + rsAstralRange + ']',\n    rsRegional = '(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}',\n    rsSurrPair = '[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]',\n    rsZWJ = '\\\\u200d';\n\n/** Used to compose unicode regexes. */\nvar reOptMod = rsModifier + '?',\n    rsOptVar = '[' + rsVarRange + ']?',\n    rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',\n    rsSeq = rsOptVar + reOptMod + rsOptJoin,\n    rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';\n\n/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */\nvar reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');\n\n/**\n * Converts a Unicode `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction unicodeToArray(string) {\n  return string.match(reUnicode) || [];\n}\n\nexport default unicodeToArray;\n","import asciiToArray from './_asciiToArray.js';\nimport hasUnicode from './_hasUnicode.js';\nimport unicodeToArray from './_unicodeToArray.js';\n\n/**\n * Converts `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction stringToArray(string) {\n  return hasUnicode(string)\n    ? unicodeToArray(string)\n    : asciiToArray(string);\n}\n\nexport default stringToArray;\n","import castSlice from './_castSlice.js';\nimport hasUnicode from './_hasUnicode.js';\nimport stringToArray from './_stringToArray.js';\nimport toString from './toString.js';\n\n/**\n * Creates a function like `_.lowerFirst`.\n *\n * @private\n * @param {string} methodName The name of the `String` case method to use.\n * @returns {Function} Returns the new case function.\n */\nfunction createCaseFirst(methodName) {\n  return function(string) {\n    string = toString(string);\n\n    var strSymbols = hasUnicode(string)\n      ? stringToArray(string)\n      : undefined;\n\n    var chr = strSymbols\n      ? strSymbols[0]\n      : string.charAt(0);\n\n    var trailing = strSymbols\n      ? castSlice(strSymbols, 1).join('')\n      : string.slice(1);\n\n    return chr[methodName]() + trailing;\n  };\n}\n\nexport default createCaseFirst;\n","import createCaseFirst from './_createCaseFirst.js';\n\n/**\n * Converts the first character of `string` to upper case.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category String\n * @param {string} [string=''] The string to convert.\n * @returns {string} Returns the converted string.\n * @example\n *\n * _.upperFirst('fred');\n * // => 'Fred'\n *\n * _.upperFirst('FRED');\n * // => 'FRED'\n */\nvar upperFirst = createCaseFirst('toUpperCase');\n\nexport default upperFirst;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module link/utils\n */\n\nimport { upperFirst } from 'lodash-es';\n\nconst ATTRIBUTE_WHITESPACES = /[\\u0000-\\u0020\\u00A0\\u1680\\u180E\\u2000-\\u2029\\u205f\\u3000]/g; // eslint-disable-line no-control-regex\nconst SAFE_URL = /^(?:(?:https?|ftps?|mailto):|[^a-z]|[a-z+.-]+(?:[^a-z+.:-]|$))/i;\n\n// Simplified email test - should be run over previously found URL.\nconst EMAIL_REG_EXP = /^[\\S]+@((?![-_])(?:[-\\w\\u00a1-\\uffff]{0,63}[^-_]\\.))+(?:[a-z\\u00a1-\\uffff]{2,})$/i;\n\n// The regex checks for the protocol syntax ('xxxx://' or 'xxxx:')\n// or non-word characters at the beginning of the link ('/', '#' etc.).\nconst PROTOCOL_REG_EXP = /^((\\w+:(\\/{2,})?)|(\\W))/i;\n\n/**\n * A keystroke used by the {@link module:link/linkui~LinkUI link UI feature}.\n */\nexport const LINK_KEYSTROKE = 'Ctrl+K';\n\n/**\n * Returns `true` if a given view node is the link element.\n *\n * @param {module:engine/view/node~Node} node\n * @returns {Boolean}\n */\nexport function isLinkElement( node ) {\n\treturn node.is( 'attributeElement' ) && !!node.getCustomProperty( 'link' );\n}\n\n/**\n * Creates a link {@link module:engine/view/attributeelement~AttributeElement} with the provided `href` attribute.\n *\n * @param {String} href\n * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n * @returns {module:engine/view/attributeelement~AttributeElement}\n */\nexport function createLinkElement( href, { writer } ) {\n\t// Priority 5 - https://github.com/ckeditor/ckeditor5-link/issues/121.\n\tconst linkElement = writer.createAttributeElement( 'a', { href }, { priority: 5 } );\n\twriter.setCustomProperty( 'link', true, linkElement );\n\n\treturn linkElement;\n}\n\n/**\n * Returns a safe URL based on a given value.\n *\n * A URL is considered safe if it is safe for the user (does not contain any malicious code).\n *\n * If a URL is considered unsafe, a simple `\"#\"` is returned.\n *\n * @protected\n * @param {*} url\n * @returns {String} Safe URL.\n */\nexport function ensureSafeUrl( url ) {\n\turl = String( url );\n\n\treturn isSafeUrl( url ) ? url : '#';\n}\n\n// Checks whether the given URL is safe for the user (does not contain any malicious code).\n//\n// @param {String} url URL to check.\nfunction isSafeUrl( url ) {\n\tconst normalizedUrl = url.replace( ATTRIBUTE_WHITESPACES, '' );\n\n\treturn normalizedUrl.match( SAFE_URL );\n}\n\n/**\n * Returns the {@link module:link/link~LinkConfig#decorators `config.link.decorators`} configuration processed\n * to respect the locale of the editor, i.e. to display the {@link module:link/link~LinkDecoratorManualDefinition label}\n * in the correct language.\n *\n * **Note**: Only the few most commonly used labels are translated automatically. Other labels should be manually\n * translated in the {@link module:link/link~LinkConfig#decorators `config.link.decorators`} configuration.\n *\n * @param {module:utils/locale~Locale#t} t shorthand for {@link module:utils/locale~Locale#t Locale#t}\n * @param {Array.<module:link/link~LinkDecoratorDefinition>} The decorator reference\n * where the label values should be localized.\n * @returns {Array.<module:link/link~LinkDecoratorDefinition>}\n */\nexport function getLocalizedDecorators( t, decorators ) {\n\tconst localizedDecoratorsLabels = {\n\t\t'Open in a new tab': t( 'Open in a new tab' ),\n\t\t'Downloadable': t( 'Downloadable' )\n\t};\n\n\tdecorators.forEach( decorator => {\n\t\tif ( decorator.label && localizedDecoratorsLabels[ decorator.label ] ) {\n\t\t\tdecorator.label = localizedDecoratorsLabels[ decorator.label ];\n\t\t}\n\t\treturn decorator;\n\t} );\n\n\treturn decorators;\n}\n\n/**\n * Converts an object with defined decorators to a normalized array of decorators. The `id` key is added for each decorator and\n * is used as the attribute's name in the model.\n *\n * @param {Object.<String, module:link/link~LinkDecoratorDefinition>} decorators\n * @returns {Array.<module:link/link~LinkDecoratorDefinition>}\n */\nexport function normalizeDecorators( decorators ) {\n\tconst retArray = [];\n\n\tif ( decorators ) {\n\t\tfor ( const [ key, value ] of Object.entries( decorators ) ) {\n\t\t\tconst decorator = Object.assign(\n\t\t\t\t{},\n\t\t\t\tvalue,\n\t\t\t\t{ id: `link${ upperFirst( key ) }` }\n\t\t\t);\n\t\t\tretArray.push( decorator );\n\t\t}\n\t}\n\n\treturn retArray;\n}\n\n/**\n * Returns `true` if the specified `element` is an image and it can be linked (the element allows having the `linkHref` attribute).\n *\n * @params {module:engine/model/element~Element|null} element\n * @params {module:engine/model/schema~Schema} schema\n * @returns {Boolean}\n */\nexport function isImageAllowed( element, schema ) {\n\tif ( !element ) {\n\t\treturn false;\n\t}\n\n\treturn element.is( 'element', 'image' ) && schema.checkAttribute( 'image', 'linkHref' );\n}\n\n/**\n * Returns `true` if the specified `value` is an email.\n *\n * @params {String} value\n * @returns {Boolean}\n */\nexport function isEmail( value ) {\n\treturn EMAIL_REG_EXP.test( value );\n}\n\n/**\n * Adds the protocol prefix to the specified `link` when:\n *\n * * it does not contain it already, and there is a {@link module:link/link~LinkConfig#defaultProtocol `defaultProtocol` }\n * configuration value provided,\n * * or the link is an email address.\n *\n *\n * @params {String} link\n * @params {String} defaultProtocol\n * @returns {Boolean}\n */\nexport function addLinkProtocolIfApplicable( link, defaultProtocol ) {\n\tconst protocol = isEmail( link ) ? 'mailto:' : defaultProtocol;\n\tconst isProtocolNeeded = !!protocol && !PROTOCOL_REG_EXP.test( link );\n\n\treturn link && isProtocolNeeded ? protocol + link : link;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module link/linkcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport findAttributeRange from '@ckeditor/ckeditor5-typing/src/utils/findattributerange';\nimport toMap from '@ckeditor/ckeditor5-utils/src/tomap';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport first from '@ckeditor/ckeditor5-utils/src/first';\nimport AutomaticDecorators from './utils/automaticdecorators';\nimport { isImageAllowed } from './utils';\n\n/**\n * The link command. It is used by the {@link module:link/link~Link link feature}.\n *\n * @extends module:core/command~Command\n */\nexport default class LinkCommand extends Command {\n\t/**\n\t * The value of the `'linkHref'` attribute if the start of the selection is located in a node with this attribute.\n\t *\n\t * @observable\n\t * @readonly\n\t * @member {Object|undefined} #value\n\t */\n\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * A collection of {@link module:link/utils~ManualDecorator manual decorators}\n\t\t * corresponding to the {@link module:link/link~LinkConfig#decorators decorator configuration}.\n\t\t *\n\t\t * You can consider it a model with states of manual decorators added to the currently selected link.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:utils/collection~Collection}\n\t\t */\n\t\tthis.manualDecorators = new Collection();\n\n\t\t/**\n\t\t * An instance of the helper that ties together all {@link module:link/link~LinkDecoratorAutomaticDefinition}\n\t\t * that are used by the {@glink features/link link} and the {@glink features/image#linking-images linking images} features.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:link/utils~AutomaticDecorators}\n\t\t */\n\t\tthis.automaticDecorators = new AutomaticDecorators();\n\t}\n\n\t/**\n\t * Synchronizes the state of {@link #manualDecorators} with the currently present elements in the model.\n\t */\n\trestoreManualDecoratorStates() {\n\t\tfor ( const manualDecorator of this.manualDecorators ) {\n\t\t\tmanualDecorator.value = this._getDecoratorStateFromModel( manualDecorator.id );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tconst selectedElement = first( doc.selection.getSelectedBlocks() );\n\n\t\t// A check for the `LinkImage` plugin. If the selection contains an element, get values from the element.\n\t\t// Currently the selection reads attributes from text nodes only. See #7429 and #7465.\n\t\tif ( isImageAllowed( selectedElement, model.schema ) ) {\n\t\t\tthis.value = selectedElement.getAttribute( 'linkHref' );\n\t\t\tthis.isEnabled = model.schema.checkAttribute( selectedElement, 'linkHref' );\n\t\t} else {\n\t\t\tthis.value = doc.selection.getAttribute( 'linkHref' );\n\t\t\tthis.isEnabled = model.schema.checkAttributeInSelection( doc.selection, 'linkHref' );\n\t\t}\n\n\t\tfor ( const manualDecorator of this.manualDecorators ) {\n\t\t\tmanualDecorator.value = this._getDecoratorStateFromModel( manualDecorator.id );\n\t\t}\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * When the selection is non-collapsed, the `linkHref` attribute will be applied to nodes inside the selection, but only to\n\t * those nodes where the `linkHref` attribute is allowed (disallowed nodes will be omitted).\n\t *\n\t * When the selection is collapsed and is not inside the text with the `linkHref` attribute, a\n\t * new {@link module:engine/model/text~Text text node} with the `linkHref` attribute will be inserted in place of the caret, but\n\t * only if such element is allowed in this place. The `_data` of the inserted text will equal the `href` parameter.\n\t * The selection will be updated to wrap the just inserted text node.\n\t *\n\t * When the selection is collapsed and inside the text with the `linkHref` attribute, the attribute value will be updated.\n\t *\n\t * # Decorators and model attribute management\n\t *\n\t * There is an optional argument to this command that applies or removes model\n\t * {@glink framework/guides/architecture/editing-engine#text-attributes text attributes} brought by\n\t * {@link module:link/utils~ManualDecorator manual link decorators}.\n\t *\n\t * Text attribute names in the model correspond to the entries in the {@link module:link/link~LinkConfig#decorators configuration}.\n\t * For every decorator configured, a model text attribute exists with the \"link\" prefix. For example, a `'linkMyDecorator'` attribute\n\t * corresponds to `'myDecorator'` in the configuration.\n\t *\n\t * To learn more about link decorators, check out the {@link module:link/link~LinkConfig#decorators `config.link.decorators`}\n\t * documentation.\n\t *\n\t * Here is how to manage decorator attributes with the link command:\n\t *\n\t *\t\tconst linkCommand = editor.commands.get( 'link' );\n\t *\n\t *\t\t// Adding a new decorator attribute.\n\t *\t\tlinkCommand.execute( 'http://example.com', {\n\t *\t\t\tlinkIsExternal: true\n\t *\t\t} );\n\t *\n\t *\t\t// Removing a decorator attribute from the selection.\n\t *\t\tlinkCommand.execute( 'http://example.com', {\n\t *\t\t\tlinkIsExternal: false\n\t *\t\t} );\n\t *\n\t *\t\t// Adding multiple decorator attributes at the same time.\n\t *\t\tlinkCommand.execute( 'http://example.com', {\n\t *\t\t\tlinkIsExternal: true,\n\t *\t\t\tlinkIsDownloadable: true,\n\t *\t\t} );\n\t *\n\t *\t\t// Removing and adding decorator attributes at the same time.\n\t *\t\tlinkCommand.execute( 'http://example.com', {\n\t *\t\t\tlinkIsExternal: false,\n\t *\t\t\tlinkFoo: true,\n\t *\t\t\tlinkIsDownloadable: false,\n\t *\t\t} );\n\t *\n\t * **Note**: If the decorator attribute name is not specified, its state remains untouched.\n\t *\n\t * **Note**: {@link module:link/unlinkcommand~UnlinkCommand#execute `UnlinkCommand#execute()`} removes all\n\t * decorator attributes.\n\t *\n\t * @fires execute\n\t * @param {String} href Link destination.\n\t * @param {Object} [manualDecoratorIds={}] The information about manual decorator attributes to be applied or removed upon execution.\n\t */\n\texecute( href, manualDecoratorIds = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\t// Stores information about manual decorators to turn them on/off when command is applied.\n\t\tconst truthyManualDecorators = [];\n\t\tconst falsyManualDecorators = [];\n\n\t\tfor ( const name in manualDecoratorIds ) {\n\t\t\tif ( manualDecoratorIds[ name ] ) {\n\t\t\t\ttruthyManualDecorators.push( name );\n\t\t\t} else {\n\t\t\t\tfalsyManualDecorators.push( name );\n\t\t\t}\n\t\t}\n\n\t\tmodel.change( writer => {\n\t\t\t// If selection is collapsed then update selected link or insert new one at the place of caret.\n\t\t\tif ( selection.isCollapsed ) {\n\t\t\t\tconst position = selection.getFirstPosition();\n\n\t\t\t\t// When selection is inside text with `linkHref` attribute.\n\t\t\t\tif ( selection.hasAttribute( 'linkHref' ) ) {\n\t\t\t\t\t// Then update `linkHref` value.\n\t\t\t\t\tconst linkRange = findAttributeRange( position, 'linkHref', selection.getAttribute( 'linkHref' ), model );\n\n\t\t\t\t\twriter.setAttribute( 'linkHref', href, linkRange );\n\n\t\t\t\t\ttruthyManualDecorators.forEach( item => {\n\t\t\t\t\t\twriter.setAttribute( item, true, linkRange );\n\t\t\t\t\t} );\n\n\t\t\t\t\tfalsyManualDecorators.forEach( item => {\n\t\t\t\t\t\twriter.removeAttribute( item, linkRange );\n\t\t\t\t\t} );\n\n\t\t\t\t\t// Put the selection at the end of the updated link.\n\t\t\t\t\twriter.setSelection( writer.createPositionAfter( linkRange.end.nodeBefore ) );\n\t\t\t\t}\n\t\t\t\t// If not then insert text node with `linkHref` attribute in place of caret.\n\t\t\t\t// However, since selection in collapsed, attribute value will be used as data for text node.\n\t\t\t\t// So, if `href` is empty, do not create text node.\n\t\t\t\telse if ( href !== '' ) {\n\t\t\t\t\tconst attributes = toMap( selection.getAttributes() );\n\n\t\t\t\t\tattributes.set( 'linkHref', href );\n\n\t\t\t\t\ttruthyManualDecorators.forEach( item => {\n\t\t\t\t\t\tattributes.set( item, true );\n\t\t\t\t\t} );\n\n\t\t\t\t\tconst { end: positionAfter } = model.insertContent( writer.createText( href, attributes ), position );\n\n\t\t\t\t\t// Put the selection at the end of the inserted link.\n\t\t\t\t\t// Using end of range returned from insertContent in case nodes with the same attributes got merged.\n\t\t\t\t\twriter.setSelection( positionAfter );\n\t\t\t\t}\n\n\t\t\t\t// Remove the `linkHref` attribute and all link decorators from the selection.\n\t\t\t\t// It stops adding a new content into the link element.\n\t\t\t\t[ 'linkHref', ...truthyManualDecorators, ...falsyManualDecorators ].forEach( item => {\n\t\t\t\t\twriter.removeSelectionAttribute( item );\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\t// If selection has non-collapsed ranges, we change attribute on nodes inside those ranges\n\t\t\t\t// omitting nodes where the `linkHref` attribute is disallowed.\n\t\t\t\tconst ranges = model.schema.getValidRanges( selection.getRanges(), 'linkHref' );\n\n\t\t\t\t// But for the first, check whether the `linkHref` attribute is allowed on selected blocks (e.g. the \"image\" element).\n\t\t\t\tconst allowedRanges = [];\n\n\t\t\t\tfor ( const element of selection.getSelectedBlocks() ) {\n\t\t\t\t\tif ( model.schema.checkAttribute( element, 'linkHref' ) ) {\n\t\t\t\t\t\tallowedRanges.push( writer.createRangeOn( element ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Ranges that accept the `linkHref` attribute. Since we will iterate over `allowedRanges`, let's clone it.\n\t\t\t\tconst rangesToUpdate = allowedRanges.slice();\n\n\t\t\t\t// For all selection ranges we want to check whether given range is inside an element that accepts the `linkHref` attribute.\n\t\t\t\t// If so, we don't want to propagate applying the attribute to its children.\n\t\t\t\tfor ( const range of ranges ) {\n\t\t\t\t\tif ( this._isRangeToUpdate( range, allowedRanges ) ) {\n\t\t\t\t\t\trangesToUpdate.push( range );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor ( const range of rangesToUpdate ) {\n\t\t\t\t\twriter.setAttribute( 'linkHref', href, range );\n\n\t\t\t\t\ttruthyManualDecorators.forEach( item => {\n\t\t\t\t\t\twriter.setAttribute( item, true, range );\n\t\t\t\t\t} );\n\n\t\t\t\t\tfalsyManualDecorators.forEach( item => {\n\t\t\t\t\t\twriter.removeAttribute( item, range );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Provides information whether a decorator with a given name is present in the currently processed selection.\n\t *\n\t * @private\n\t * @param {String} decoratorName The name of the manual decorator used in the model\n\t * @returns {Boolean} The information whether a given decorator is currently present in the selection.\n\t */\n\t_getDecoratorStateFromModel( decoratorName ) {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tconst selectedElement = first( doc.selection.getSelectedBlocks() );\n\n\t\t// A check for the `LinkImage` plugin. If the selection contains an element, get values from the element.\n\t\t// Currently the selection reads attributes from text nodes only. See #7429 and #7465.\n\t\tif ( isImageAllowed( selectedElement, model.schema ) ) {\n\t\t\treturn selectedElement.getAttribute( decoratorName );\n\t\t}\n\n\t\treturn doc.selection.getAttribute( decoratorName );\n\t}\n\n\t/**\n\t * Checks whether specified `range` is inside an element that accepts the `linkHref` attribute.\n\t *\n\t * @private\n\t * @param {module:engine/view/range~Range} range A range to check.\n\t * @param {Array.<module:engine/view/range~Range>} allowedRanges An array of ranges created on elements where the attribute is accepted.\n\t * @returns {Boolean}\n\t */\n\t_isRangeToUpdate( range, allowedRanges ) {\n\t\tfor ( const allowedRange of allowedRanges ) {\n\t\t\t// A range is inside an element that will have the `linkHref` attribute. Do not modify its nodes.\n\t\t\tif ( allowedRange.containsRange( range ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module link/unlinkcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport findAttributeRange from '@ckeditor/ckeditor5-typing/src/utils/findattributerange';\nimport first from '@ckeditor/ckeditor5-utils/src/first';\nimport { isImageAllowed } from './utils';\n\n/**\n * The unlink command. It is used by the {@link module:link/link~Link link plugin}.\n *\n * @extends module:core/command~Command\n */\nexport default class UnlinkCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tconst selectedElement = first( doc.selection.getSelectedBlocks() );\n\n\t\t// A check for the `LinkImage` plugin. If the selection contains an image element, get values from the element.\n\t\t// Currently the selection reads attributes from text nodes only. See #7429 and #7465.\n\t\tif ( isImageAllowed( selectedElement, model.schema ) ) {\n\t\t\tthis.isEnabled = model.schema.checkAttribute( selectedElement, 'linkHref' );\n\t\t} else {\n\t\t\tthis.isEnabled = model.schema.checkAttributeInSelection( doc.selection, 'linkHref' );\n\t\t}\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * When the selection is collapsed, it removes the `linkHref` attribute from each node with the same `linkHref` attribute value.\n\t * When the selection is non-collapsed, it removes the `linkHref` attribute from each node in selected ranges.\n\t *\n\t * # Decorators\n\t *\n\t * If {@link module:link/link~LinkConfig#decorators `config.link.decorators`} is specified,\n\t * all configured decorators are removed together with the `linkHref` attribute.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst editor = this.editor;\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst linkCommand = editor.commands.get( 'link' );\n\n\t\tmodel.change( writer => {\n\t\t\t// Get ranges to unlink.\n\t\t\tconst rangesToUnlink = selection.isCollapsed ?\n\t\t\t\t[ findAttributeRange(\n\t\t\t\t\tselection.getFirstPosition(),\n\t\t\t\t\t'linkHref',\n\t\t\t\t\tselection.getAttribute( 'linkHref' ),\n\t\t\t\t\tmodel\n\t\t\t\t) ] :\n\t\t\t\tmodel.schema.getValidRanges( selection.getRanges(), 'linkHref' );\n\n\t\t\t// Remove `linkHref` attribute from specified ranges.\n\t\t\tfor ( const range of rangesToUnlink ) {\n\t\t\t\twriter.removeAttribute( 'linkHref', range );\n\t\t\t\t// If there are registered custom attributes, then remove them during unlink.\n\t\t\t\tif ( linkCommand ) {\n\t\t\t\t\tfor ( const manualDecorator of linkCommand.manualDecorators ) {\n\t\t\t\t\t\twriter.removeAttribute( manualDecorator.id, range );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module link/utils\n */\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Helper class that stores manual decorators with observable {@link module:link/utils~ManualDecorator#value}\n * to support integration with the UI state. An instance of this class is a model with the state of individual manual decorators.\n * These decorators are kept as collections in {@link module:link/linkcommand~LinkCommand#manualDecorators}.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class ManualDecorator {\n\t/**\n\t * Creates a new instance of {@link module:link/utils~ManualDecorator}.\n\t *\n\t * @param {Object} config\n\t * @param {String} config.id The name of the attribute used in the model that represents a given manual decorator.\n\t * For example: `'linkIsExternal'`.\n\t * @param {String} config.label The label used in the user interface to toggle the manual decorator.\n\t * @param {Object} config.attributes A set of attributes added to output data when the decorator is active for a specific link.\n\t * Attributes should keep the format of attributes defined in {@link module:engine/view/elementdefinition~ElementDefinition}.\n\t * @param {Boolean} [config.defaultValue] Controls whether the decorator is \"on\" by default.\n\t */\n\tconstructor( { id, label, attributes, defaultValue } ) {\n\t\t/**\n\t\t * An ID of a manual decorator which is the name of the attribute in the model, for example: 'linkManualDecorator0'.\n\t\t *\n\t\t * @type {String}\n\t\t */\n\t\tthis.id = id;\n\n\t\t/**\n\t\t * The value of the current manual decorator. It reflects its state from the UI.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} module:link/utils~ManualDecorator#value\n\t\t */\n\t\tthis.set( 'value' );\n\n\t\t/**\n\t\t * The default value of manual decorator.\n\t\t *\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis.defaultValue = defaultValue;\n\n\t\t/**\n\t\t * The label used in the user interface to toggle the manual decorator.\n\t\t *\n\t\t * @type {String}\n\t\t */\n\t\tthis.label = label;\n\n\t\t/**\n\t\t * A set of attributes added to downcasted data when the decorator is activated for a specific link.\n\t\t * Attributes should be added in a form of attributes defined in {@link module:engine/view/elementdefinition~ElementDefinition}.\n\t\t *\n\t\t * @type {Object}\n\t\t */\n\t\tthis.attributes = attributes;\n\t}\n}\n\nmix( ManualDecorator, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module link/linkediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport MouseObserver from '@ckeditor/ckeditor5-engine/src/view/observer/mouseobserver';\nimport TwoStepCaretMovement from '@ckeditor/ckeditor5-typing/src/twostepcaretmovement';\nimport inlineHighlight from '@ckeditor/ckeditor5-typing/src/utils/inlinehighlight';\nimport Input from '@ckeditor/ckeditor5-typing/src/input';\nimport Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';\nimport LinkCommand from './linkcommand';\nimport UnlinkCommand from './unlinkcommand';\nimport ManualDecorator from './utils/manualdecorator';\nimport findAttributeRange from '@ckeditor/ckeditor5-typing/src/utils/findattributerange';\nimport { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport { createLinkElement, ensureSafeUrl, getLocalizedDecorators, normalizeDecorators } from './utils';\n\nimport '../theme/link.css';\n\nconst HIGHLIGHT_CLASS = 'ck-link_selected';\nconst DECORATOR_AUTOMATIC = 'automatic';\nconst DECORATOR_MANUAL = 'manual';\nconst EXTERNAL_LINKS_REGEXP = /^(https?:)?\\/\\//;\n\n/**\n * The link engine feature.\n *\n * It introduces the `linkHref=\"url\"` attribute in the model which renders to the view as a `<a href=\"url\">` element\n * as well as `'link'` and `'unlink'` commands.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class LinkEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'LinkEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\t// Clipboard is required for handling cut and paste events while typing over the link.\n\t\treturn [ TwoStepCaretMovement, Input, Clipboard ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( 'link', {\n\t\t\taddTargetToExternalLinks: false\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Allow link attribute on all inline nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: 'linkHref' } );\n\n\t\teditor.conversion.for( 'dataDowncast' )\n\t\t\t.attributeToElement( { model: 'linkHref', view: createLinkElement } );\n\n\t\teditor.conversion.for( 'editingDowncast' )\n\t\t\t.attributeToElement( { model: 'linkHref', view: ( href, conversionApi ) => {\n\t\t\t\treturn createLinkElement( ensureSafeUrl( href ), conversionApi );\n\t\t\t} } );\n\n\t\teditor.conversion.for( 'upcast' )\n\t\t\t.elementToAttribute( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'a',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\thref: true\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tmodel: {\n\t\t\t\t\tkey: 'linkHref',\n\t\t\t\t\tvalue: viewElement => viewElement.getAttribute( 'href' )\n\t\t\t\t}\n\t\t\t} );\n\n\t\t// Create linking commands.\n\t\teditor.commands.add( 'link', new LinkCommand( editor ) );\n\t\teditor.commands.add( 'unlink', new UnlinkCommand( editor ) );\n\n\t\tconst linkDecorators = getLocalizedDecorators( editor.t, normalizeDecorators( editor.config.get( 'link.decorators' ) ) );\n\n\t\tthis._enableAutomaticDecorators( linkDecorators.filter( item => item.mode === DECORATOR_AUTOMATIC ) );\n\t\tthis._enableManualDecorators( linkDecorators.filter( item => item.mode === DECORATOR_MANUAL ) );\n\n\t\t// Enable two-step caret movement for `linkHref` attribute.\n\t\tconst twoStepCaretMovementPlugin = editor.plugins.get( TwoStepCaretMovement );\n\t\ttwoStepCaretMovementPlugin.registerAttribute( 'linkHref' );\n\n\t\t// Setup highlight over selected link.\n\t\tinlineHighlight( editor, 'linkHref', 'a', HIGHLIGHT_CLASS );\n\n\t\t// Change the attributes of the selection in certain situations after the link was inserted into the document.\n\t\tthis._enableInsertContentSelectionAttributesFixer();\n\n\t\t// Handle a click at the beginning/end of a link element.\n\t\tthis._enableClickingAfterLink();\n\n\t\t// Handle typing over the link.\n\t\tthis._enableTypingOverLink();\n\n\t\t// Handle removing the content after the link element.\n\t\tthis._handleDeleteContentAfterLink();\n\t}\n\n\t/**\n\t * Processes an array of configured {@link module:link/link~LinkDecoratorAutomaticDefinition automatic decorators}\n\t * and registers a {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher downcast dispatcher}\n\t * for each one of them. Downcast dispatchers are obtained using the\n\t * {@link module:link/utils~AutomaticDecorators#getDispatcher} method.\n\t *\n\t * **Note**: This method also activates the automatic external link decorator if enabled with\n\t * {@link module:link/link~LinkConfig#addTargetToExternalLinks `config.link.addTargetToExternalLinks`}.\n\t *\n\t * @private\n\t * @param {Array.<module:link/link~LinkDecoratorAutomaticDefinition>} automaticDecoratorDefinitions\n\t */\n\t_enableAutomaticDecorators( automaticDecoratorDefinitions ) {\n\t\tconst editor = this.editor;\n\t\t// Store automatic decorators in the command instance as we do the same with manual decorators.\n\t\t// Thanks to that, `LinkImageEditing` plugin can re-use the same definitions.\n\t\tconst command = editor.commands.get( 'link' );\n\t\tconst automaticDecorators = command.automaticDecorators;\n\n\t\t// Adds a default decorator for external links.\n\t\tif ( editor.config.get( 'link.addTargetToExternalLinks' ) ) {\n\t\t\tautomaticDecorators.add( {\n\t\t\t\tid: 'linkIsExternal',\n\t\t\t\tmode: DECORATOR_AUTOMATIC,\n\t\t\t\tcallback: url => EXTERNAL_LINKS_REGEXP.test( url ),\n\t\t\t\tattributes: {\n\t\t\t\t\ttarget: '_blank',\n\t\t\t\t\trel: 'noopener noreferrer'\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\tautomaticDecorators.add( automaticDecoratorDefinitions );\n\n\t\tif ( automaticDecorators.length ) {\n\t\t\teditor.conversion.for( 'downcast' ).add( automaticDecorators.getDispatcher() );\n\t\t}\n\t}\n\n\t/**\n\t * Processes an array of configured {@link module:link/link~LinkDecoratorManualDefinition manual decorators},\n\t * transforms them into {@link module:link/utils~ManualDecorator} instances and stores them in the\n\t * {@link module:link/linkcommand~LinkCommand#manualDecorators} collection (a model for manual decorators state).\n\t *\n\t * Also registers an {@link module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToElement attribute-to-element}\n\t * converter for each manual decorator and extends the {@link module:engine/model/schema~Schema model's schema}\n\t * with adequate model attributes.\n\t *\n\t * @private\n\t * @param {Array.<module:link/link~LinkDecoratorManualDefinition>} manualDecoratorDefinitions\n\t */\n\t_enableManualDecorators( manualDecoratorDefinitions ) {\n\t\tif ( !manualDecoratorDefinitions.length ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst editor = this.editor;\n\t\tconst command = editor.commands.get( 'link' );\n\t\tconst manualDecorators = command.manualDecorators;\n\n\t\tmanualDecoratorDefinitions.forEach( decorator => {\n\t\t\teditor.model.schema.extend( '$text', { allowAttributes: decorator.id } );\n\n\t\t\t// Keeps reference to manual decorator to decode its name to attributes during downcast.\n\t\t\tmanualDecorators.add( new ManualDecorator( decorator ) );\n\n\t\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t\t\t\tmodel: decorator.id,\n\t\t\t\tview: ( manualDecoratorName, { writer } ) => {\n\t\t\t\t\tif ( manualDecoratorName ) {\n\t\t\t\t\t\tconst attributes = manualDecorators.get( decorator.id ).attributes;\n\t\t\t\t\t\tconst element = writer.createAttributeElement( 'a', attributes, { priority: 5 } );\n\t\t\t\t\t\twriter.setCustomProperty( 'link', true, element );\n\n\t\t\t\t\t\treturn element;\n\t\t\t\t\t}\n\t\t\t\t} } );\n\n\t\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'a',\n\t\t\t\t\tattributes: manualDecorators.get( decorator.id ).attributes\n\t\t\t\t},\n\t\t\t\tmodel: {\n\t\t\t\t\tkey: decorator.id\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n\n\t/**\n\t * Starts listening to {@link module:engine/model/model~Model#event:insertContent} and corrects the model\n\t * selection attributes if the selection is at the end of a link after inserting the content.\n\t *\n\t * The purpose of this action is to improve the overall UX because the user is no longer \"trapped\" by the\n\t * `linkHref` attribute of the selection and they can type a \"clean\" (`linkHref`–less) text right away.\n\t *\n\t * See https://github.com/ckeditor/ckeditor5/issues/6053.\n\t *\n\t * @private\n\t */\n\t_enableInsertContentSelectionAttributesFixer() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst linkCommand = editor.commands.get( 'link' );\n\n\t\tthis.listenTo( model, 'insertContent', () => {\n\t\t\tconst nodeBefore = selection.anchor.nodeBefore;\n\t\t\tconst nodeAfter = selection.anchor.nodeAfter;\n\n\t\t\t// NOTE: ↰ and ↱ represent the gravity of the selection.\n\n\t\t\t// The only truly valid case is:\n\t\t\t//\n\t\t\t//\t\t                                 ↰\n\t\t\t//\t\t...<$text linkHref=\"foo\">INSERTED[]</$text>\n\t\t\t//\n\t\t\t// If the selection is not \"trapped\" by the `linkHref` attribute after inserting, there's nothing\n\t\t\t// to fix there.\n\t\t\tif ( !selection.hasAttribute( 'linkHref' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Filter out the following case where a link with the same href (e.g. <a href=\"foo\">INSERTED</a>) is inserted\n\t\t\t// in the middle of an existing link:\n\t\t\t//\n\t\t\t// Before insertion:\n\t\t\t//\t\t                       ↰\n\t\t\t//\t\t<$text linkHref=\"foo\">l[]ink</$text>\n\t\t\t//\n\t\t\t// Expected after insertion:\n\t\t\t//\t\t                               ↰\n\t\t\t//\t\t<$text linkHref=\"foo\">lINSERTED[]ink</$text>\n\t\t\t//\n\t\t\tif ( !nodeBefore ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Filter out the following case where the selection has the \"linkHref\" attribute because the\n\t\t\t// gravity is overridden and some text with another attribute (e.g. <b>INSERTED</b>) is inserted:\n\t\t\t//\n\t\t\t// Before insertion:\n\t\t\t//\n\t\t\t//\t\t                       ↱\n\t\t\t//\t\t<$text linkHref=\"foo\">[]link</$text>\n\t\t\t//\n\t\t\t// Expected after insertion:\n\t\t\t//\n\t\t\t//\t\t                                                          ↱\n\t\t\t//\t\t<$text bold=\"true\">INSERTED</$text><$text linkHref=\"foo\">[]link</$text>\n\t\t\t//\n\t\t\tif ( !nodeBefore.hasAttribute( 'linkHref' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Filter out the following case where a link is a inserted in the middle (or before) another link\n\t\t\t// (different URLs, so they will not merge). In this (let's say weird) case, we can leave the selection\n\t\t\t// attributes as they are because the user will end up writing in one link or another anyway.\n\t\t\t//\n\t\t\t// Before insertion:\n\t\t\t//\n\t\t\t//\t\t                       ↰\n\t\t\t//\t\t<$text linkHref=\"foo\">l[]ink</$text>\n\t\t\t//\n\t\t\t// Expected after insertion:\n\t\t\t//\n\t\t\t//\t\t                                                             ↰\n\t\t\t//\t\t<$text linkHref=\"foo\">l</$text><$text linkHref=\"bar\">INSERTED[]</$text><$text linkHref=\"foo\">ink</$text>\n\t\t\t//\n\t\t\tif ( nodeAfter && nodeAfter.hasAttribute( 'linkHref' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmodel.change( writer => {\n\t\t\t\tremoveLinkAttributesFromSelection( writer, linkCommand.manualDecorators );\n\t\t\t} );\n\t\t}, { priority: 'low' } );\n\t}\n\n\t/**\n\t * Starts listening to {@link module:engine/view/document~Document#event:mousedown} and\n\t * {@link module:engine/view/document~Document#event:selectionChange} and puts the selection before/after a link node\n\t * if clicked at the beginning/ending of the link.\n\t *\n\t * The purpose of this action is to allow typing around the link node directly after a click.\n\t *\n\t * See https://github.com/ckeditor/ckeditor5/issues/1016.\n\t *\n\t * @private\n\t */\n\t_enableClickingAfterLink() {\n\t\tconst editor = this.editor;\n\t\tconst linkCommand = editor.commands.get( 'link' );\n\n\t\teditor.editing.view.addObserver( MouseObserver );\n\n\t\tlet clicked = false;\n\n\t\t// Detect the click.\n\t\tthis.listenTo( editor.editing.view.document, 'mousedown', () => {\n\t\t\tclicked = true;\n\t\t} );\n\n\t\t// When the selection has changed...\n\t\tthis.listenTo( editor.editing.view.document, 'selectionChange', () => {\n\t\t\tif ( !clicked ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// ...and it was caused by the click...\n\t\t\tclicked = false;\n\n\t\t\tconst selection = editor.model.document.selection;\n\n\t\t\t// ...and no text is selected...\n\t\t\tif ( !selection.isCollapsed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// ...and clicked text is the link...\n\t\t\tif ( !selection.hasAttribute( 'linkHref' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst position = selection.getFirstPosition();\n\t\t\tconst linkRange = findAttributeRange( position, 'linkHref', selection.getAttribute( 'linkHref' ), editor.model );\n\n\t\t\t// ...check whether clicked start/end boundary of the link.\n\t\t\t// If so, remove the `linkHref` attribute.\n\t\t\tif ( position.isTouching( linkRange.start ) || position.isTouching( linkRange.end ) ) {\n\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\tremoveLinkAttributesFromSelection( writer, linkCommand.manualDecorators );\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Starts listening to {@link module:engine/model/model~Model#deleteContent} and {@link module:engine/model/model~Model#insertContent}\n\t * and checks whether typing over the link. If so, attributes of removed text are preserved and applied to the inserted text.\n\t *\n\t * The purpose of this action is to allow modifying a text without loosing the `linkHref` attribute (and other).\n\t *\n\t * See https://github.com/ckeditor/ckeditor5/issues/4762.\n\t *\n\t * @private\n\t */\n\t_enableTypingOverLink() {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\n\t\t// Selection attributes when started typing over the link.\n\t\tlet selectionAttributes;\n\n\t\t// Whether pressed `Backspace` or `Delete`. If so, attributes should not be preserved.\n\t\tlet deletedContent;\n\n\t\t// Detect pressing `Backspace` / `Delete`.\n\t\tthis.listenTo( view.document, 'delete', () => {\n\t\t\tdeletedContent = true;\n\t\t}, { priority: 'high' } );\n\n\t\t// Listening to `model#deleteContent` allows detecting whether selected content was a link.\n\t\t// If so, before removing the element, we will copy its attributes.\n\t\tthis.listenTo( editor.model, 'deleteContent', () => {\n\t\t\tconst selection = editor.model.document.selection;\n\n\t\t\t// Copy attributes only if anything is selected.\n\t\t\tif ( selection.isCollapsed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// When the content was deleted, do not preserve attributes.\n\t\t\tif ( deletedContent ) {\n\t\t\t\tdeletedContent = false;\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Enabled only when typing.\n\t\t\tif ( !isTyping( editor ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( shouldCopyAttributes( editor.model ) ) {\n\t\t\t\tselectionAttributes = selection.getAttributes();\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\n\t\t// Listening to `model#insertContent` allows detecting the content insertion.\n\t\t// We want to apply attributes that were removed while typing over the link.\n\t\tthis.listenTo( editor.model, 'insertContent', ( evt, [ element ] ) => {\n\t\t\tdeletedContent = false;\n\n\t\t\t// Enabled only when typing.\n\t\t\tif ( !isTyping( editor ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( !selectionAttributes ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\teditor.model.change( writer => {\n\t\t\t\tfor ( const [ attribute, value ] of selectionAttributes ) {\n\t\t\t\t\twriter.setAttribute( attribute, value, element );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tselectionAttributes = null;\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * Starts listening to {@link module:engine/model/model~Model#deleteContent} and checks whether\n\t * removing a content right after the \"linkHref\" attribute.\n\t *\n\t * If so, the selection should not preserve the `linkHref` attribute. However, if\n\t * the {@link module:typing/twostepcaretmovement~TwoStepCaretMovement} plugin is active and\n\t * the selection has the \"linkHref\" attribute due to overriden gravity (at the end), the `linkHref` attribute should stay untouched.\n\t *\n\t * The purpose of this action is to allow removing the link text and keep the selection outside the link.\n\t *\n\t * See https://github.com/ckeditor/ckeditor5/issues/7521.\n\t *\n\t * @private\n\t */\n\t_handleDeleteContentAfterLink() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst view = editor.editing.view;\n\t\tconst linkCommand = editor.commands.get( 'link' );\n\n\t\t// A flag whether attributes `linkHref` attribute should be preserved.\n\t\tlet shouldPreserveAttributes = false;\n\n\t\t// A flag whether the `Backspace` key was pressed.\n\t\tlet hasBackspacePressed = false;\n\n\t\t// Detect pressing `Backspace`.\n\t\tthis.listenTo( view.document, 'delete', ( evt, data ) => {\n\t\t\thasBackspacePressed = data.domEvent.keyCode === keyCodes.backspace;\n\t\t}, { priority: 'high' } );\n\n\t\t// Before removing the content, check whether the selection is inside a link or at the end of link but with 2-SCM enabled.\n\t\t// If so, we want to preserve link attributes.\n\t\tthis.listenTo( model, 'deleteContent', () => {\n\t\t\t// Reset the state.\n\t\t\tshouldPreserveAttributes = false;\n\n\t\t\tconst position = selection.getFirstPosition();\n\t\t\tconst linkHref = selection.getAttribute( 'linkHref' );\n\n\t\t\tif ( !linkHref ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst linkRange = findAttributeRange( position, 'linkHref', linkHref, model );\n\n\t\t\t// Preserve `linkHref` attribute if the selection is in the middle of the link or\n\t\t\t// the selection is at the end of the link and 2-SCM is activated.\n\t\t\tshouldPreserveAttributes = linkRange.containsPosition( position ) || linkRange.end.isEqual( position );\n\t\t}, { priority: 'high' } );\n\n\t\t// After removing the content, check whether the current selection should preserve the `linkHref` attribute.\n\t\tthis.listenTo( model, 'deleteContent', () => {\n\t\t\t// If didn't press `Backspace`.\n\t\t\tif ( !hasBackspacePressed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\thasBackspacePressed = false;\n\n\t\t\t// Disable the mechanism if inside a link (`<$text url=\"foo\">F[]oo</$text>` or <$text url=\"foo\">Foo[]</$text>`).\n\t\t\tif ( shouldPreserveAttributes ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Use `model.enqueueChange()` in order to execute the callback at the end of the changes process.\n\t\t\teditor.model.enqueueChange( writer => {\n\t\t\t\tremoveLinkAttributesFromSelection( writer, linkCommand.manualDecorators );\n\t\t\t} );\n\t\t}, { priority: 'low' } );\n\t}\n}\n\n// Make the selection free of link-related model attributes.\n// All link-related model attributes start with \"link\". That includes not only \"linkHref\"\n// but also all decorator attributes (they have dynamic names).\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:utils/collection~Collection} manualDecorators\nfunction removeLinkAttributesFromSelection( writer, manualDecorators ) {\n\twriter.removeSelectionAttribute( 'linkHref' );\n\n\tfor ( const decorator of manualDecorators ) {\n\t\twriter.removeSelectionAttribute( decorator.id );\n\t}\n}\n\n// Checks whether selection's attributes should be copied to the new inserted text.\n//\n// @param {module:engine/model/model~Model} model\n// @returns {Boolean}\nfunction shouldCopyAttributes( model ) {\n\tconst selection = model.document.selection;\n\tconst firstPosition = selection.getFirstPosition();\n\tconst lastPosition = selection.getLastPosition();\n\tconst nodeAtFirstPosition = firstPosition.nodeAfter;\n\n\t// The text link node does not exist...\n\tif ( !nodeAtFirstPosition ) {\n\t\treturn false;\n\t}\n\n\t// ...or it isn't the text node...\n\tif ( !nodeAtFirstPosition.is( '$text' ) ) {\n\t\treturn false;\n\t}\n\n\t// ...or isn't the link.\n\tif ( !nodeAtFirstPosition.hasAttribute( 'linkHref' ) ) {\n\t\treturn false;\n\t}\n\n\t// `textNode` = the position is inside the link element.\n\t// `nodeBefore` = the position is at the end of the link element.\n\tconst nodeAtLastPosition = lastPosition.textNode || lastPosition.nodeBefore;\n\n\t// If both references the same node selection contains a single text node.\n\tif ( nodeAtFirstPosition === nodeAtLastPosition ) {\n\t\treturn true;\n\t}\n\n\t// If nodes are not equal, maybe the link nodes has defined additional attributes inside.\n\t// First, we need to find the entire link range.\n\tconst linkRange = findAttributeRange( firstPosition, 'linkHref', nodeAtFirstPosition.getAttribute( 'linkHref' ), model );\n\n\t// Then we can check whether selected range is inside the found link range. If so, attributes should be preserved.\n\treturn linkRange.containsRange( model.createRange( firstPosition, lastPosition ), true );\n}\n\n// Checks whether provided changes were caused by typing.\n//\n// @params {module:core/editor/editor~Editor} editor\n// @returns {Boolean}\nfunction isTyping( editor ) {\n\tconst input = editor.plugins.get( 'Input' );\n\n\treturn input.isInput( editor.model.change( writer => writer.batch ) );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport findAttributeRange from './findattributerange';\n\n/**\n * @module typing/utils/inlinehighlight\n */\n\n/**\n * Adds a visual highlight style to an attribute element in which the selection is anchored.\n * Together with two-step caret movement, they indicate that the user is typing inside the element.\n *\n * Highlight is turned on by adding the given class to the attribute element in the view:\n *\n * * The class is removed before the conversion has started, as callbacks added with the `'highest'` priority\n * to {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher} events.\n * * The class is added in the view post fixer, after other changes in the model tree were converted to the view.\n *\n * This way, adding and removing the highlight does not interfere with conversion.\n *\n * Usage:\n *\n *\t\timport inlineHighlight from '@ckeditor/ckeditor5-typing/src/utils/inlinehighlight';\n *\n *\t\t// Make `ck-link_selected` class be applied on an `a` element\n *\t\t// whenever the corresponding `linkHref` attribute element is selected.\n *\t\tinlineHighlight( editor, 'linkHref', 'a', 'ck-link_selected' );\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n * @param {String} attributeName The attribute name to check.\n * @param {String} tagName The tagName of a view item.\n * @param {String} className The class name to apply in the view.\n */\nexport default function inlineHighlight( editor, attributeName, tagName, className ) {\n\tconst view = editor.editing.view;\n\tconst highlightedElements = new Set();\n\n\t// Adding the class.\n\tview.document.registerPostFixer( writer => {\n\t\tconst selection = editor.model.document.selection;\n\t\tlet changed = false;\n\n\t\tif ( selection.hasAttribute( attributeName ) ) {\n\t\t\tconst modelRange = findAttributeRange(\n\t\t\t\tselection.getFirstPosition(),\n\t\t\t\tattributeName,\n\t\t\t\tselection.getAttribute( attributeName ),\n\t\t\t\teditor.model\n\t\t\t);\n\t\t\tconst viewRange = editor.editing.mapper.toViewRange( modelRange );\n\n\t\t\t// There might be multiple view elements in the `viewRange`, for example, when the `a` element is\n\t\t\t// broken by a UIElement.\n\t\t\tfor ( const item of viewRange.getItems() ) {\n\t\t\t\tif ( item.is( 'element', tagName ) && !item.hasClass( className ) ) {\n\t\t\t\t\twriter.addClass( className, item );\n\t\t\t\t\thighlightedElements.add( item );\n\t\t\t\t\tchanged = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn changed;\n\t} );\n\n\t// Removing the class.\n\teditor.conversion.for( 'editingDowncast' ).add( dispatcher => {\n\t\t// Make sure the highlight is removed on every possible event, before conversion is started.\n\t\tdispatcher.on( 'insert', removeHighlight, { priority: 'highest' } );\n\t\tdispatcher.on( 'remove', removeHighlight, { priority: 'highest' } );\n\t\tdispatcher.on( 'attribute', removeHighlight, { priority: 'highest' } );\n\t\tdispatcher.on( 'selection', removeHighlight, { priority: 'highest' } );\n\n\t\tfunction removeHighlight() {\n\t\t\tview.change( writer => {\n\t\t\t\tfor ( const item of highlightedElements.values() ) {\n\t\t\t\t\twriter.removeClass( className, item );\n\t\t\t\t\thighlightedElements.delete( item );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/notification/notification\n */\n\n/* globals window */\n\nimport ContextPlugin from '@ckeditor/ckeditor5-core/src/contextplugin';\n\n/**\n * The Notification plugin.\n *\n * This plugin sends a few types of notifications: `success`, `info` and `warning`. The notifications need to be\n * handled and displayed by a plugin responsible for showing the UI of the notifications. Using this plugin for dispatching\n * notifications makes it possible to switch the notifications UI.\n *\n * Note that every unhandled and not stopped `warning` notification will be displayed as a system alert.\n * See {@link module:ui/notification/notification~Notification#showWarning}.\n *\n * @extends module:core/contextplugin~ContextPlugin\n */\nexport default class Notification extends ContextPlugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Notification';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\t// Each unhandled and not stopped `show:warning` event is displayed as a system alert.\n\t\tthis.on( 'show:warning', ( evt, data ) => {\n\t\t\twindow.alert( data.message ); // eslint-disable-line no-alert\n\t\t}, { priority: 'lowest' } );\n\t}\n\n\t/**\n\t * Shows a success notification.\n\t *\n\t * By default, it fires the {@link #event:show:success `show:success` event} with the given `data`. The event namespace can be extended\n\t * using the `data.namespace` option. For example:\n\t *\n\t * \t\tshowSuccess( 'Image is uploaded.', {\n\t * \t\t\tnamespace: 'upload:image'\n\t * \t\t} );\n\t *\n\t * will fire the `show:success:upload:image` event.\n\t *\n\t * You can provide the title of the notification:\n\t *\n\t *\t\tshowSuccess( 'Image is uploaded.', {\n\t *\t\t\ttitle: 'Image upload success'\n\t *\t\t} );\n\t *\n\t * @param {String} message The content of the notification.\n\t * @param {Object} [data={}] Additional data.\n\t * @param {String} [data.namespace] Additional event namespace.\n\t * @param {String} [data.title] The title of the notification.\n\t */\n\tshowSuccess( message, data = {} ) {\n\t\tthis._showNotification( {\n\t\t\tmessage,\n\t\t\ttype: 'success',\n\t\t\tnamespace: data.namespace,\n\t\t\ttitle: data.title\n\t\t} );\n\t}\n\n\t/**\n\t * Shows an information notification.\n\t *\n\t * By default, it fires the {@link #event:show:info `show:info` event} with the given `data`. The event namespace can be extended\n\t * using the `data.namespace` option. For example:\n\t *\n\t * \t\tshowInfo( 'Editor is offline.', {\n\t * \t\t\tnamespace: 'editor:status'\n\t * \t\t} );\n\t *\n\t * will fire the `show:info:editor:status` event.\n\t *\n\t * You can provide the title of the notification:\n\t *\n\t *\t\tshowInfo( 'Editor is offline.', {\n\t *\t\t\ttitle: 'Network information'\n\t *\t\t} );\n\t *\n\t * @param {String} message The content of the notification.\n\t * @param {Object} [data={}] Additional data.\n\t * @param {String} [data.namespace] Additional event namespace.\n\t * @param {String} [data.title] The title of the notification.\n\t */\n\tshowInfo( message, data = {} ) {\n\t\tthis._showNotification( {\n\t\t\tmessage,\n\t\t\ttype: 'info',\n\t\t\tnamespace: data.namespace,\n\t\t\ttitle: data.title\n\t\t} );\n\t}\n\n\t/**\n\t * Shows a warning notification.\n\t *\n\t * By default, it fires the {@link #event:show:warning `show:warning` event}\n\t * with the given `data`. The event namespace can be extended using the `data.namespace` option. For example:\n\t *\n\t * \t\tshowWarning( 'Image upload error.', {\n\t * \t\t\tnamespace: 'upload:image'\n\t * \t\t} );\n\t *\n\t * will fire the `show:warning:upload:image` event.\n\t *\n\t * You can provide the title of the notification:\n\t *\n\t *\t\tshowWarning( 'Image upload error.', {\n\t *\t\t\ttitle: 'Upload failed'\n\t *\t\t} );\n\t *\n\t * Note that each unhandled and not stopped `warning` notification will be displayed as a system alert.\n\t * The plugin responsible for displaying warnings should `stop()` the event to prevent displaying it as an alert:\n\t *\n\t * \t\tnotifications.on( 'show:warning', ( evt, data ) => {\n\t * \t\t\t// Do something with the data.\n\t *\n\t * \t\t\t// Stop this event to prevent displaying it as an alert.\n\t * \t\t\tevt.stop();\n\t * \t\t} );\n\t *\n\t * You can attach many listeners to the same event and `stop()` this event in a listener with a low priority:\n\t *\n\t * \t\tnotifications.on( 'show:warning', ( evt, data ) => {\n\t * \t\t\t// Show the warning in the UI, but do not stop it.\n\t * \t\t} );\n\t *\n\t * \t\tnotifications.on( 'show:warning', ( evt, data ) => {\n\t * \t\t\t// Log the warning to some error tracker.\n\t *\n\t * \t\t\t// Stop this event to prevent displaying it as an alert.\n\t * \t\t\tevt.stop();\n\t * \t\t}, { priority: 'low' } );\n\t *\n\t * @param {String} message The content of the notification.\n\t * @param {Object} [data={}] Additional data.\n\t * @param {String} [data.namespace] Additional event namespace.\n\t * @param {String} [data.title] The title of the notification.\n\t */\n\tshowWarning( message, data = {} ) {\n\t\tthis._showNotification( {\n\t\t\tmessage,\n\t\t\ttype: 'warning',\n\t\t\tnamespace: data.namespace,\n\t\t\ttitle: data.title\n\t\t} );\n\t}\n\n\t/**\n\t * Fires the `show` event with the specified type, namespace and message.\n\t *\n\t * @private\n\t * @param {Object} data The message data.\n\t * @param {String} data.message The content of the notification.\n\t * @param {'success'|'info'|'warning'} data.type The type of the message.\n\t * @param {String} [data.namespace] Additional event namespace.\n\t * @param {String} [data.title=''] The title of the notification.\n\t */\n\t_showNotification( data ) {\n\t\tconst event = `show:${ data.type }` + ( data.namespace ? `:${ data.namespace }` : '' );\n\n\t\tthis.fire( event, {\n\t\t\tmessage: data.message,\n\t\t\ttype: data.type,\n\t\t\ttitle: data.title || ''\n\t\t} );\n\t}\n\n\t/**\n\t * Fired when one of the `showSuccess()`, `showInfo()`, `showWarning()` methods is called.\n\t *\n\t * @event show\n\t * @param {Object} data The notification data.\n\t * @param {String} data.message The content of the notification.\n\t * @param {String} data.title The title of the notification.\n\t * @param {'success'|'info'|'warning'} data.type The type of the notification.\n\t */\n\n\t/**\n\t * Fired when the `showSuccess()` method is called.\n\t *\n\t * @event show:success\n\t * @param {Object} data The notification data.\n\t * @param {String} data.message The content of the notification.\n\t * @param {String} data.title The title of the notification.\n\t * @param {'success'} data.type The type of the notification.\n\t */\n\n\t/**\n\t * Fired when the `showInfo()` method is called.\n\t *\n\t * @event show:info\n\t * @param {Object} data The notification data.\n\t * @param {String} data.message The content of the notification.\n\t * @param {String} data.title The title of the notification.\n\t * @param {'info'} data.type The type of the notification.\n\t */\n\n\t/**\n\t * Fired when the `showWarning()` method is called.\n\t *\n\t * When this event is not handled or stopped by `event.stop()`, the `data.message` of this event will\n\t * be automatically displayed as a system alert.\n\t *\n\t * @event show:warning\n\t * @param {Object} data The notification data.\n\t * @param {String} data.message The content of the notification.\n\t * @param {String} data.title The title of the notification.\n\t * @param {'warning'} data.type The type of the notification.\n\t */\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* global window */\n\n/**\n * @module ckfinder/ckfindercommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * The CKFinder command. It is used by the {@link module:ckfinder/ckfinderediting~CKFinderEditing CKFinder editing feature}\n * to open the CKFinder file manager to insert an image or a link to a file into the editor content.\n *\n *\t\teditor.execute( 'ckfinder' );\n *\n * **Note:** This command uses other features to perform tasks:\n * - To insert images the {@link module:image/image/imageinsertcommand~ImageInsertCommand 'imageInsert'} command\n * from the {@link module:image/image~Image Image feature}.\n * - To insert links to files the {@link module:link/linkcommand~LinkCommand 'link'} command\n * from the {@link module:link/link~Link Link feature}.\n *\n * @extends module:core/command~Command\n */\nexport default class CKFinderCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t// Remove default document listener to lower its priority.\n\t\tthis.stopListening( this.editor.model.document, 'change' );\n\n\t\t// Lower this command listener priority to be sure that refresh() will be called after link & image refresh.\n\t\tthis.listenTo( this.editor.model.document, 'change', () => this.refresh(), { priority: 'low' } );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst imageCommand = this.editor.commands.get( 'imageInsert' );\n\t\tconst linkCommand = this.editor.commands.get( 'link' );\n\n\t\t// The CKFinder command is enabled when one of image or link command is enabled.\n\t\tthis.isEnabled = imageCommand.isEnabled || linkCommand.isEnabled;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst editor = this.editor;\n\n\t\tconst openerMethod = this.editor.config.get( 'ckfinder.openerMethod' ) || 'modal';\n\n\t\tif ( openerMethod != 'popup' && openerMethod != 'modal' ) {\n\t\t\t/**\n\t\t\t * The `ckfinder.openerMethod` must be one of: \"popup\" or \"modal\".\n\t\t\t *\n\t\t\t * @error ckfinder-unknown-openermethod\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'ckfinder-unknown-openermethod', editor );\n\t\t}\n\n\t\tconst options = this.editor.config.get( 'ckfinder.options' ) || {};\n\n\t\toptions.chooseFiles = true;\n\n\t\t// Cache the user-defined onInit method\n\t\tconst originalOnInit = options.onInit;\n\n\t\t// Pass the lang code to the CKFinder if not defined by user.\n\t\tif ( !options.language ) {\n\t\t\toptions.language = editor.locale.uiLanguage;\n\t\t}\n\n\t\t// The onInit method allows to extend CKFinder's behavior. It is used to attach event listeners to file choosing related events.\n\t\toptions.onInit = finder => {\n\t\t\t// Call original options.onInit if it was defined by user.\n\t\t\tif ( originalOnInit ) {\n\t\t\t\toriginalOnInit( finder );\n\t\t\t}\n\n\t\t\tfinder.on( 'files:choose', evt => {\n\t\t\t\tconst files = evt.data.files.toArray();\n\n\t\t\t\t// Insert links\n\t\t\t\tconst links = files.filter( file => !file.isImage() );\n\t\t\t\tconst images = files.filter( file => file.isImage() );\n\n\t\t\t\tfor ( const linkFile of links ) {\n\t\t\t\t\teditor.execute( 'link', linkFile.getUrl() );\n\t\t\t\t}\n\n\t\t\t\tconst imagesUrls = [];\n\n\t\t\t\tfor ( const image of images ) {\n\t\t\t\t\tconst url = image.getUrl();\n\n\t\t\t\t\timagesUrls.push( url ? url : finder.request( 'file:getProxyUrl', { file: image } ) );\n\t\t\t\t}\n\n\t\t\t\tif ( imagesUrls.length ) {\n\t\t\t\t\tinsertImages( editor, imagesUrls );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tfinder.on( 'file:choose:resizedImage', evt => {\n\t\t\t\tconst resizedUrl = evt.data.resizedUrl;\n\n\t\t\t\tif ( !resizedUrl ) {\n\t\t\t\t\tconst notification = editor.plugins.get( 'Notification' );\n\t\t\t\t\tconst t = editor.locale.t;\n\n\t\t\t\t\tnotification.showWarning( t( 'Could not obtain resized image URL.' ), {\n\t\t\t\t\t\ttitle: t( 'Selecting resized image failed' ),\n\t\t\t\t\t\tnamespace: 'ckfinder'\n\t\t\t\t\t} );\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tinsertImages( editor, [ resizedUrl ] );\n\t\t\t} );\n\t\t};\n\n\t\twindow.CKFinder[ openerMethod ]( options );\n\t}\n}\n\nfunction insertImages( editor, urls ) {\n\tconst imageCommand = editor.commands.get( 'imageInsert' );\n\n\t// Check if inserting an image is actually possible - it might be possible to only insert a link.\n\tif ( !imageCommand.isEnabled ) {\n\t\tconst notification = editor.plugins.get( 'Notification' );\n\t\tconst t = editor.locale.t;\n\n\t\tnotification.showWarning( t( 'Could not insert image at the current position.' ), {\n\t\t\ttitle: t( 'Inserting image failed' ),\n\t\t\tnamespace: 'ckfinder'\n\t\t} );\n\n\t\treturn;\n\t}\n\n\teditor.execute( 'imageInsert', { source: urls } );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ckfinder/ckfinderediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ImageEditing from '@ckeditor/ckeditor5-image/src/image/imageediting';\nimport LinkEditing from '@ckeditor/ckeditor5-link/src/linkediting';\nimport Notification from '@ckeditor/ckeditor5-ui/src/notification/notification';\n\nimport CKFinderCommand from './ckfindercommand';\n\n/**\n * The CKFinder editing feature. It introduces the {@link module:ckfinder/ckfindercommand~CKFinderCommand CKFinder command}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class CKFinderEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'CKFinderEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ Notification, ImageEditing, LinkEditing ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\teditor.commands.add( 'ckfinder', new CKFinderCommand( editor ) );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module cloud-services-core/uploadgateway/fileuploader\n */\n\n/* globals XMLHttpRequest, FormData, Blob, atob */\n\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\nconst BASE64_HEADER_REG_EXP = /^data:(\\S*?);base64,/;\n\n/**\n * FileUploader class used to upload single file.\n */\nexport default class FileUploader {\n\t/**\n\t * Creates `FileUploader` instance.\n\t *\n\t * @param {Blob|String} fileOrData A blob object or a data string encoded with Base64.\n\t * @param {module:cloud-services-core/token~Token} token Token used for authentication.\n\t * @param {String} apiAddress API address.\n\t */\n\tconstructor( fileOrData, token, apiAddress ) {\n\t\tif ( !fileOrData ) {\n\t\t\t/**\n\t\t\t * File must be provided as the first argument.\n\t\t\t *\n\t\t\t * @error fileuploader-missing-file\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'fileuploader-missing-file', null );\n\t\t}\n\n\t\tif ( !token ) {\n\t\t\t/**\n\t\t\t * Token must be provided as the second argument.\n\t\t\t *\n\t\t\t * @error fileuploader-missing-token\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'fileuploader-missing-token', null );\n\t\t}\n\n\t\tif ( !apiAddress ) {\n\t\t\t/**\n\t\t\t * Api address must be provided as the third argument.\n\t\t\t *\n\t\t\t * @error fileuploader-missing-api-address\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'fileuploader-missing-api-address', null );\n\t\t}\n\n\t\t/**\n\t\t * A file that is being uploaded.\n\t\t *\n\t\t * @type {Blob}\n\t\t */\n\t\tthis.file = _isBase64( fileOrData ) ? _base64ToBlob( fileOrData ) : fileOrData;\n\n\t\t/**\n\t\t * CKEditor Cloud Services access token.\n\t\t *\n\t\t * @type {module:cloud-services-core/token~Token}\n\t\t * @private\n\t\t */\n\t\tthis._token = token;\n\n\t\t/**\n\t\t * CKEditor Cloud Services API address.\n\t\t *\n\t\t * @type {String}\n\t\t * @private\n\t\t */\n\t\tthis._apiAddress = apiAddress;\n\t}\n\n\t/**\n\t * Registers callback on `progress` event.\n\t *\n\t * @chainable\n\t * @param {Function} callback\n\t * @returns {module:cloud-services-core/uploadgateway/fileuploader~FileUploader}\n\t */\n\tonProgress( callback ) {\n\t\tthis.on( 'progress', ( event, data ) => callback( data ) );\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Registers callback on `error` event. Event is called once when error occurs.\n\t *\n\t * @chainable\n\t * @param {Function} callback\n\t * @returns {module:cloud-services-core/uploadgateway/fileuploader~FileUploader}\n\t */\n\tonError( callback ) {\n\t\tthis.once( 'error', ( event, data ) => callback( data ) );\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Aborts upload process.\n\t */\n\tabort() {\n\t\tthis.xhr.abort();\n\t}\n\n\t/**\n\t * Sends XHR request to API.\n\t *\n\t * @chainable\n\t * @returns {Promise.<Object>}\n\t */\n\tsend() {\n\t\tthis._prepareRequest();\n\t\tthis._attachXHRListeners();\n\n\t\treturn this._sendRequest();\n\t}\n\n\t/**\n\t * Prepares XHR request.\n\t *\n\t * @private\n\t */\n\t_prepareRequest() {\n\t\tconst xhr = new XMLHttpRequest();\n\n\t\txhr.open( 'POST', this._apiAddress );\n\t\txhr.setRequestHeader( 'Authorization', this._token.value );\n\t\txhr.responseType = 'json';\n\n\t\tthis.xhr = xhr;\n\t}\n\n\t/**\n\t * Attaches listeners to the XHR.\n\t *\n\t * @private\n\t */\n\t_attachXHRListeners() {\n\t\tconst that = this;\n\t\tconst xhr = this.xhr;\n\n\t\txhr.addEventListener( 'error', onError( 'Network Error' ) );\n\t\txhr.addEventListener( 'abort', onError( 'Abort' ) );\n\n\t\t/* istanbul ignore else */\n\t\tif ( xhr.upload ) {\n\t\t\txhr.upload.addEventListener( 'progress', event => {\n\t\t\t\tif ( event.lengthComputable ) {\n\t\t\t\t\tthis.fire( 'progress', {\n\t\t\t\t\t\ttotal: event.total,\n\t\t\t\t\t\tuploaded: event.loaded\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\txhr.addEventListener( 'load', () => {\n\t\t\tconst statusCode = xhr.status;\n\t\t\tconst xhrResponse = xhr.response;\n\n\t\t\tif ( statusCode < 200 || statusCode > 299 ) {\n\t\t\t\treturn this.fire( 'error', xhrResponse.message || xhrResponse.error );\n\t\t\t}\n\t\t} );\n\n\t\tfunction onError( message ) {\n\t\t\treturn () => that.fire( 'error', message );\n\t\t}\n\t}\n\n\t/**\n\t * Sends XHR request.\n\t *\n\t * @private\n\t */\n\t_sendRequest() {\n\t\tconst formData = new FormData();\n\t\tconst xhr = this.xhr;\n\n\t\tformData.append( 'file', this.file );\n\n\t\treturn new Promise( ( resolve, reject ) => {\n\t\t\txhr.addEventListener( 'load', () => {\n\t\t\t\tconst statusCode = xhr.status;\n\t\t\t\tconst xhrResponse = xhr.response;\n\n\t\t\t\tif ( statusCode < 200 || statusCode > 299 ) {\n\t\t\t\t\tif ( xhrResponse.message ) {\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * Uploading file failed.\n\t\t\t\t\t\t *\n\t\t\t\t\t\t * @error fileuploader-uploading-data-failed\n\t\t\t\t\t\t */\n\t\t\t\t\t\treturn reject( new CKEditorError(\n\t\t\t\t\t\t\t'fileuploader-uploading-data-failed',\n\t\t\t\t\t\t\tthis,\n\t\t\t\t\t\t\t{ message: xhrResponse.message }\n\t\t\t\t\t\t) );\n\t\t\t\t\t}\n\n\t\t\t\t\treturn reject( xhrResponse.error );\n\t\t\t\t}\n\n\t\t\t\treturn resolve( xhrResponse );\n\t\t\t} );\n\n\t\t\txhr.addEventListener( 'error', () => reject( new Error( 'Network Error' ) ) );\n\t\t\txhr.addEventListener( 'abort', () => reject( new Error( 'Abort' ) ) );\n\n\t\t\txhr.send( formData );\n\t\t} );\n\t}\n\n\t/**\n\t * Fired when error occurs.\n\t *\n\t * @event error\n\t * @param {String} error Error message\n\t */\n\n\t/**\n\t * Fired on upload progress.\n\t *\n\t * @event progress\n\t * @param {Object} status Total and uploaded status\n\t */\n}\n\nmix( FileUploader, EmitterMixin );\n\n/**\n * Transforms Base64 string data into file.\n *\n * @param {String} base64 String data.\n * @param {Number} [sliceSize=512]\n * @returns {Blob}\n * @private\n */\nfunction _base64ToBlob( base64, sliceSize = 512 ) {\n\ttry {\n\t\tconst contentType = base64.match( BASE64_HEADER_REG_EXP )[ 1 ];\n\t\tconst base64Data = atob( base64.replace( BASE64_HEADER_REG_EXP, '' ) );\n\n\t\tconst byteArrays = [];\n\n\t\tfor ( let offset = 0; offset < base64Data.length; offset += sliceSize ) {\n\t\t\tconst slice = base64Data.slice( offset, offset + sliceSize );\n\t\t\tconst byteNumbers = new Array( slice.length );\n\n\t\t\tfor ( let i = 0; i < slice.length; i++ ) {\n\t\t\t\tbyteNumbers[ i ] = slice.charCodeAt( i );\n\t\t\t}\n\n\t\t\tbyteArrays.push( new Uint8Array( byteNumbers ) );\n\t\t}\n\n\t\treturn new Blob( byteArrays, { type: contentType } );\n\t} catch ( error ) {\n\t\t/**\n\t\t * Problem with decoding Base64 image data.\n\t\t *\n\t\t * @error fileuploader-decoding-image-data-error\n\t\t */\n\t\tthrow new CKEditorError( 'fileuploader-decoding-image-data-error', null );\n\t}\n}\n\n/**\n * Checks that string is Base64.\n *\n * @param {String} string\n * @returns {Boolean}\n * @private\n */\nfunction _isBase64( string ) {\n\tif ( typeof string !== 'string' ) {\n\t\treturn false;\n\t}\n\n\tconst match = string.match( BASE64_HEADER_REG_EXP );\n\treturn !!( match && match.length );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module cloud-services-core/token\n */\n\n/* globals XMLHttpRequest, setTimeout, clearTimeout, atob */\n\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\nconst DEFAULT_OPTIONS = { autoRefresh: true };\nconst DEFAULT_TOKEN_REFRESH_TIMEOUT_TIME = 3600000;\n\n/**\n * Class representing the token used for communication with CKEditor Cloud Services.\n * Value of the token is retrieving from the specified URL and is refreshed every 1 hour by default.\n *\n * @mixes ObservableMixin\n */\nclass Token {\n\t/**\n\t * Creates `Token` instance.\n\t * Method `init` should be called after using the constructor or use `create` method instead.\n\t *\n\t * @param {String|Function} tokenUrlOrRefreshToken Endpoint address to download the token or a callback that provides the token. If the\n\t * value is a function it has to match the {@link module:cloud-services-core/token~refreshToken} interface.\n\t * @param {Object} options\n\t * @param {String} [options.initValue] Initial value of the token.\n\t * @param {Boolean} [options.autoRefresh=true] Specifies whether to start the refresh automatically.\n\t */\n\tconstructor( tokenUrlOrRefreshToken, options = DEFAULT_OPTIONS ) {\n\t\tif ( !tokenUrlOrRefreshToken ) {\n\t\t\t/**\n\t\t\t * A `tokenUrl` must be provided as the first constructor argument.\n\t\t\t *\n\t\t\t * @error token-missing-token-url\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'token-missing-token-url',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tif ( options.initValue ) {\n\t\t\tthis._validateTokenValue( options.initValue );\n\t\t}\n\n\t\t/**\n\t\t * Value of the token.\n\t\t * The value of the token is null if `initValue` is not provided or `init` method was not called.\n\t\t * `create` method creates token with initialized value from url.\n\t\t *\n\t\t * @name value\n\t\t * @member {String} #value\n\t\t * @observable\n\t\t * @readonly\n\t\t */\n\t\tthis.set( 'value', options.initValue );\n\n\t\t/**\n\t\t * Base refreshing function.\n\t\t *\n\t\t * @private\n\t\t * @member {String|Function} #_refresh\n\t\t */\n\t\tif ( typeof tokenUrlOrRefreshToken === 'function' ) {\n\t\t\tthis._refresh = tokenUrlOrRefreshToken;\n\t\t} else {\n\t\t\tthis._refresh = () => defaultRefreshToken( tokenUrlOrRefreshToken );\n\t\t}\n\n\t\t/**\n\t\t * @type {Object}\n\t\t * @private\n\t\t */\n\t\tthis._options = Object.assign( {}, DEFAULT_OPTIONS, options );\n\t}\n\n\t/**\n\t * Initializes the token.\n\t *\n\t * @returns {Promise.<module:cloud-services-core/token~Token>}\n\t */\n\tinit() {\n\t\treturn new Promise( ( resolve, reject ) => {\n\t\t\tif ( !this.value ) {\n\t\t\t\tthis.refreshToken()\n\t\t\t\t\t.then( resolve )\n\t\t\t\t\t.catch( reject );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( this._options.autoRefresh ) {\n\t\t\t\tthis._registerRefreshTokenTimeout();\n\t\t\t}\n\n\t\t\tresolve( this );\n\t\t} );\n\t}\n\n\t/**\n\t * Refresh token method. Useful in a method form as it can be override in tests.\n\t * @returns {Promise.<String>}\n\t */\n\trefreshToken() {\n\t\treturn this._refresh()\n\t\t\t.then( value => {\n\t\t\t\tthis._validateTokenValue( value );\n\t\t\t\tthis.set( 'value', value );\n\n\t\t\t\tif ( this._options.autoRefresh ) {\n\t\t\t\t\tthis._registerRefreshTokenTimeout();\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.then( () => this );\n\t}\n\n\t/**\n\t * Destroys token instance. Stops refreshing.\n\t */\n\tdestroy() {\n\t\tclearTimeout( this._tokenRefreshTimeout );\n\t}\n\n\t/**\n\t * Checks whether the provided token follows the JSON Web Tokens (JWT) format.\n\t *\n\t * @protected\n\t * @param {String} tokenValue The token to validate.\n\t */\n\t_validateTokenValue( tokenValue ) {\n\t\t// The token must be a string.\n\t\tconst isString = typeof tokenValue === 'string';\n\n\t\t// The token must be a plain string without quotes (\"\").\n\t\tconst isPlainString = !/^\".*\"$/.test( tokenValue );\n\n\t\t// JWT token contains 3 parts: header, payload, and signature.\n\t\t// Each part is separated by a dot.\n\t\tconst isJWTFormat = isString && tokenValue.split( '.' ).length === 3;\n\n\t\tif ( !( isPlainString && isJWTFormat ) ) {\n\t\t\t/**\n\t\t\t * The provided token must follow the [JSON Web Tokens](https://jwt.io/introduction/) format.\n\t\t\t *\n\t\t\t * @error token-not-in-jwt-format\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'token-not-in-jwt-format', this );\n\t\t}\n\t}\n\n\t/**\n\t * Registers a refresh token timeout for the time taken from token.\n\t *\n\t * @protected\n\t */\n\t_registerRefreshTokenTimeout() {\n\t\tconst tokenRefreshTimeoutTime = this._getTokenRefreshTimeoutTime();\n\n\t\tclearTimeout( this._tokenRefreshTimeout );\n\n\t\tthis._tokenRefreshTimeout = setTimeout( () => {\n\t\t\tthis.refreshToken();\n\t\t}, tokenRefreshTimeoutTime );\n\t}\n\n\t/**\n\t * Returns token refresh timeout time calculated from expire time in the token payload.\n\t *\n\t * If the token parse fails or the token payload doesn't contain, the default DEFAULT_TOKEN_REFRESH_TIMEOUT_TIME is returned.\n\t *\n\t * @protected\n\t * @returns {Number}\n\t */\n\t_getTokenRefreshTimeoutTime() {\n\t\ttry {\n\t\t\tconst [ , binaryTokenPayload ] = this.value.split( '.' );\n\t\t\tconst { exp: tokenExpireTime } = JSON.parse( atob( binaryTokenPayload ) );\n\n\t\t\tif ( !tokenExpireTime ) {\n\t\t\t\treturn DEFAULT_TOKEN_REFRESH_TIMEOUT_TIME;\n\t\t\t}\n\n\t\t\tconst tokenRefreshTimeoutTime = Math.floor( ( ( tokenExpireTime * 1000 ) - Date.now() ) / 2 );\n\n\t\t\treturn tokenRefreshTimeoutTime;\n\t\t} catch ( err ) {\n\t\t\treturn DEFAULT_TOKEN_REFRESH_TIMEOUT_TIME;\n\t\t}\n\t}\n\n\t/**\n\t * Creates a initialized {@link module:cloud-services-core/token~Token} instance.\n\t *\n\t * @param {String|Function} tokenUrlOrRefreshToken Endpoint address to download the token or a callback that provides the token. If the\n\t * value is a function it has to match the {@link module:cloud-services-core/token~refreshToken} interface.\n\t * @param {Object} options\n\t * @param {String} [options.initValue] Initial value of the token.\n\t * @param {Boolean} [options.autoRefresh=true] Specifies whether to start the refresh automatically.\n\t * @returns {Promise.<module:cloud-services-core/token~Token>}\n\t */\n\tstatic create( tokenUrlOrRefreshToken, options = DEFAULT_OPTIONS ) {\n\t\tconst token = new Token( tokenUrlOrRefreshToken, options );\n\n\t\treturn token.init();\n\t}\n}\n\nmix( Token, ObservableMixin );\n\n/**\n * This function is called in a defined interval by the {@link ~Token} class. It also can be invoked manually.\n * It should return a promise, which resolves with the new token value.\n * If any error occurs it should return a rejected promise with an error message.\n *\n * @function refreshToken\n * @returns {Promise.<String>}\n */\n\n/**\n * @private\n * @param {String} tokenUrl\n */\nfunction defaultRefreshToken( tokenUrl ) {\n\treturn new Promise( ( resolve, reject ) => {\n\t\tconst xhr = new XMLHttpRequest();\n\n\t\txhr.open( 'GET', tokenUrl );\n\n\t\txhr.addEventListener( 'load', () => {\n\t\t\tconst statusCode = xhr.status;\n\t\t\tconst xhrResponse = xhr.response;\n\n\t\t\tif ( statusCode < 200 || statusCode > 299 ) {\n\t\t\t\t/**\n\t\t\t\t * Cannot download new token from the provided url.\n\t\t\t\t *\n\t\t\t\t * @error token-cannot-download-new-token\n\t\t\t\t */\n\t\t\t\treturn reject(\n\t\t\t\t\tnew CKEditorError( 'token-cannot-download-new-token', null )\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn resolve( xhrResponse );\n\t\t} );\n\n\t\txhr.addEventListener( 'error', () => reject( new Error( 'Network Error' ) ) );\n\t\txhr.addEventListener( 'abort', () => reject( new Error( 'Abort' ) ) );\n\n\t\txhr.send();\n\t} );\n}\n\nexport default Token;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module cloud-services/cloudservices\n */\n\nimport ContextPlugin from '@ckeditor/ckeditor5-core/src/contextplugin';\nimport Token from '@ckeditor/ckeditor-cloud-services-core/src/token/token';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Plugin introducing integration between CKEditor 5 and CKEditor Cloud Services .\n *\n * It initializes the token provider based on\n * the {@link module:cloud-services/cloudservices~CloudServicesConfig `config.cloudService`}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class CloudServices extends ContextPlugin {\n\t/**\n\t * @inheritdoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'CloudServices';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst config = this.context.config;\n\n\t\tconst options = config.get( 'cloudServices' ) || {};\n\n\t\tfor ( const optionName in options ) {\n\t\t\tthis[ optionName ] = options[ optionName ];\n\t\t}\n\n\t\t/**\n\t\t * Map of `Token` object instances keyed by `tokenUrl`s.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.<String, module:cloud-services-core/token~Token>}\n\t\t */\n\t\tthis._tokens = new Map();\n\n\t\t/**\n\t\t * The authentication token URL for CKEditor Cloud Services or a callback to the token value promise. See the\n\t\t * {@link module:cloud-services/cloudservices~CloudServicesConfig#tokenUrl} for more details.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String|Function|undefined} #tokenUrl\n\t\t */\n\n\t\t/**\n\t\t * The URL to which the files should be uploaded.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} #uploadUrl\n\t\t */\n\n\t\t/**\n\t\t * Other plugins use this token for the authorization process. It handles token requesting and refreshing.\n\t\t * Its value is `null` when {@link module:cloud-services/cloudservices~CloudServicesConfig#tokenUrl} is not provided.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:cloud-services-core/token~Token|null} #token\n\t\t */\n\n\t\tif ( !this.tokenUrl ) {\n\t\t\tthis.token = null;\n\n\t\t\treturn;\n\t\t}\n\n\t\tthis.token = new CloudServices.Token( this.tokenUrl );\n\n\t\tthis._tokens.set( this.tokenUrl, this.token );\n\n\t\treturn this.token.init();\n\t}\n\n\t/**\n\t * Registers an additional authentication token URL for CKEditor Cloud Services or a callback to the token value promise. See the\n\t * {@link module:cloud-services/cloudservices~CloudServicesConfig#tokenUrl} for more details.\n\t *\n\t * @param {String|Function} tokenUrl The authentication token URL for CKEditor Cloud Services or a callback to the token value promise.\n\t * @returns {Promise.<module:cloud-services-core/token~Token>}\n\t */\n\tregisterTokenUrl( tokenUrl ) {\n\t\t// Reuse Token instance in case of multiple features using the same tokenUrl.\n\t\tif ( this._tokens.has( tokenUrl ) ) {\n\t\t\treturn Promise.resolve( this.getTokenFor( tokenUrl ) );\n\t\t}\n\n\t\tconst token = new CloudServices.Token( tokenUrl );\n\n\t\tthis._tokens.set( tokenUrl, token );\n\n\t\treturn token.init();\n\t}\n\n\t/**\n\t * Returns authentication token provider previously registered by {@link #registerTokenUrl}.\n\t *\n\t * @param {String|Function} tokenUrl The authentication token URL for CKEditor Cloud Services or a callback to the token value promise.\n\t * @returns {module:cloud-services-core/token~Token}\n\t */\n\tgetTokenFor( tokenUrl ) {\n\t\tconst token = this._tokens.get( tokenUrl );\n\n\t\tif ( !token ) {\n\t\t\t/**\n\t\t\t * Provided `tokenUrl` was not registered by {@link module:cloud-services/cloudservices~CloudServices#registerTokenUrl}.\n\t\t\t *\n\t\t\t * @error cloudservices-token-not-registered\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'cloudservices-token-not-registered', this );\n\t\t}\n\n\t\treturn token;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tfor ( const token of this._tokens.values() ) {\n\t\t\ttoken.destroy();\n\t\t}\n\t}\n}\n\nCloudServices.Token = Token;\n\n/**\n * The configuration of CKEditor Cloud Services. Introduced by the {@link module:cloud-services/cloudservices~CloudServices} plugin.\n *\n * Read more in {@link module:cloud-services/cloudservices~CloudServicesConfig}.\n *\n * @member {module:cloud-services/cloudservices~CloudServicesConfig} module:core/editor/editorconfig~EditorConfig#cloudServices\n */\n\n/**\n * The configuration for all plugins using CKEditor Cloud Services.\n *\n *\t\tClassicEditor\n *\t\t\t.create( document.querySelector( '#editor' ), {\n *\t\t\t\tcloudServices: {\n *\t\t\t\t\ttokenUrl: 'https://example.com/cs-token-endpoint',\n *\t\t\t\t\tuploadUrl: 'https://your-organization-id.cke-cs.com/easyimage/upload/'\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface CloudServicesConfig\n */\n\n/**\n * A token URL or a token request function.\n *\n * As a string, it should be a URL to the security token endpoint in your application. The role of this endpoint is to securely authorize\n * the end users of your application to use [CKEditor Cloud Services](https://ckeditor.com/ckeditor-cloud-services) only\n * if they should have access e.g. to upload files with {@glink @cs guides/easy-image/quick-start Easy Image} or to use the\n * {@glink @cs guides/collaboration/quick-start Collaboration} service.\n *\n *\t\tClassicEditor\n *\t\t\t.create( document.querySelector( '#editor' ), {\n *\t\t\t\tcloudServices: {\n *\t\t\t\t\ttokenUrl: 'https://example.com/cs-token-endpoint',\n *\t\t\t\t\t...\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * As a function, it should provide a promise to the token value, so you can highly customize the token and provide your token URL endpoint.\n * By using this approach you can set your own headers for the request.\n *\n * \t\tClassicEditor\n *\t\t\t.create( document.querySelector( '#editor' ), {\n *\t\t\t\tcloudServices: {\n *\t\t\t\t\ttokenUrl: () => new Promise( ( resolve, reject ) => {\n *\t\t\t\t\t\tconst xhr = new XMLHttpRequest();\n *\n *\t\t\t\t\t\txhr.open( 'GET', 'https://example.com/cs-token-endpoint' );\n *\n *\t\t\t\t\t\txhr.addEventListener( 'load', () => {\n *\t\t\t\t\t\t\tconst statusCode = xhr.status;\n *\t\t\t\t\t\t\tconst xhrResponse = xhr.response;\n *\n *\t\t\t\t\t\t\tif ( statusCode < 200 || statusCode > 299 ) {\n *\t\t\t\t\t\t\t\treturn reject( new Error( 'Cannot download new token!' ) );\n *\t\t\t\t\t\t\t}\n *\n *\t\t\t\t\t\t\treturn resolve( xhrResponse );\n *\t\t\t\t\t\t} );\n *\n *\t\t\t\t\t\txhr.addEventListener( 'error', () => reject( new Error( 'Network Error' ) ) );\n *\t\t\t\t\t\txhr.addEventListener( 'abort', () => reject( new Error( 'Abort' ) ) );\n *\n *\t\t\t\t\t\txhr.setRequestHeader( customHeader, customValue );\n *\n *\t\t\t\t\t\txhr.send();\n *\t\t\t\t\t} ),\n *\t\t\t\t\t...\n *\t\t\t\t}\n *\t\t\t} )\n *\n * You can find more information about token endpoints in the\n * {@glink @cs guides/easy-image/quick-start#create-token-endpoint Cloud Services - Quick start}\n * and {@glink @cs guides/security/token-endpoint Cloud Services - Token endpoint} documentation.\n *\n * Without a properly working token endpoint (token URL) CKEditor plugins will not be able to connect to CKEditor Cloud Services.\n *\n * @member {String|Function} module:cloud-services/cloudservices~CloudServicesConfig#tokenUrl\n */\n\n/**\n * The endpoint URL for [CKEditor Cloud Services](https://ckeditor.com/ckeditor-cloud-services) uploads.\n * This option must be set for Easy Image to work correctly.\n *\n * The upload URL is unique for each customer and can be found in the\n * [CKEditor Ecosystem customer dashboard](https://dashboard.ckeditor.com) after subscribing to the Easy Image service.\n * To learn how to start using Easy Image, check the {@glink @cs guides/easy-image/quick-start Easy Image - Quick start} documentation.\n *\n * Note: Make sure to also set the {@link module:cloud-services/cloudservices~CloudServicesConfig#tokenUrl} configuration option.\n *\n * @member {String} module:cloud-services/cloudservices~CloudServicesConfig#uploadUrl\n */\n\n/**\n * The URL for web socket communication, used by the `RealTimeCollaborativeEditing` plugin. Every customer (organization in the CKEditor\n * Ecosystem dashboard) has their own, unique URLs to communicate with CKEditor Cloud Services. The URL can be found in the\n * CKEditor Ecosystem customer dashboard.\n *\n * Note: Unlike most plugins, `RealTimeCollaborativeEditing` is not included in any CKEditor 5 build and needs to be installed manually.\n * Check [Collaboration overview](https://ckeditor.com/docs/ckeditor5/latest/features/collaboration/overview.html) for more details.\n *\n * @member {String} module:cloud-services/cloudservices~CloudServicesConfig#webSocketUrl\n */\n\n/**\n * An optional parameter used for integration with CKEditor Cloud Services when uploading the editor build to cloud services.\n *\n * Whenever the editor build or the configuration changes, this parameter should be set to a new, unique value to differentiate\n * the new bundle (build + configuration) from the old ones.\n *\n * @member {String} module:cloud-services/cloudservices~CloudServicesConfig#bundleVersion\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n* @module easy-image/cloudservicesuploadadapter\n*/\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport FileRepository from '@ckeditor/ckeditor5-upload/src/filerepository';\nimport UploadGateway from '@ckeditor/ckeditor-cloud-services-core/src/uploadgateway/uploadgateway';\nimport CloudServices from '@ckeditor/ckeditor5-cloud-services/src/cloudservices';\n\n/**\n * A plugin that enables upload to [CKEditor Cloud Services](https://ckeditor.com/ckeditor-cloud-services/).\n *\n * It is mainly used by the {@link module:easy-image/easyimage~EasyImage} feature.\n *\n * After enabling this adapter you need to configure the CKEditor Cloud Services integration through\n * {@link module:cloud-services/cloudservices~CloudServicesConfig `config.cloudServices`}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class CloudServicesUploadAdapter extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ FileRepository, CloudServices ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\tconst cloudServices = editor.plugins.get( CloudServices );\n\n\t\tconst token = cloudServices.token;\n\t\tconst uploadUrl = cloudServices.uploadUrl;\n\n\t\tif ( !token ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._uploadGateway = new CloudServicesUploadAdapter._UploadGateway( token, uploadUrl );\n\n\t\teditor.plugins.get( FileRepository ).createUploadAdapter = loader => {\n\t\t\treturn new Adapter( this._uploadGateway, loader );\n\t\t};\n\t}\n}\n\n/**\n * @private\n */\nclass Adapter {\n\tconstructor( uploadGateway, loader ) {\n\t\tthis.uploadGateway = uploadGateway;\n\n\t\tthis.loader = loader;\n\t}\n\n\tupload() {\n\t\treturn this.loader.file.then( file => {\n\t\t\tthis.fileUploader = this.uploadGateway.upload( file );\n\n\t\t\tthis.fileUploader.on( 'progress', ( evt, data ) => {\n\t\t\t\tthis.loader.uploadTotal = data.total;\n\t\t\t\tthis.loader.uploaded = data.uploaded;\n\t\t\t} );\n\n\t\t\treturn this.fileUploader.send();\n\t\t} );\n\t}\n\n\tabort() {\n\t\tthis.fileUploader.abort();\n\t}\n}\n\n// Store the API in static property to easily overwrite it in tests.\n// Too bad dependency injection does not work in Webpack + ES 6 (const) + Babel.\nCloudServicesUploadAdapter._UploadGateway = UploadGateway;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module cloud-services-core/uploadgateway/uploadgateway\n */\n\nimport FileUploader from './fileuploader';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * UploadGateway abstracts file uploads to CKEditor Cloud Services.\n */\nexport default class UploadGateway {\n\t/**\n\t * Creates `UploadGateway` instance.\n\t *\n\t * @param {module:cloud-services-core/token~Token} token Token used for authentication.\n\t * @param {String} apiAddress API address.\n\t */\n\tconstructor( token, apiAddress ) {\n\t\tif ( !token ) {\n\t\t\t/**\n\t\t\t * Token must be provided.\n\t\t\t *\n\t\t\t * @error uploadgateway-missing-token\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'uploadgateway-missing-token', null );\n\t\t}\n\n\t\tif ( !apiAddress ) {\n\t\t\t/**\n\t\t\t * Api address must be provided.\n\t\t\t *\n\t\t\t * @error uploadgateway-missing-api-address\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'uploadgateway-missing-api-address', null );\n\t\t}\n\n\t\t/**\n\t\t * CKEditor Cloud Services access token.\n\t\t *\n\t\t * @type {module:cloud-services-core/token~Token}\n\t\t * @private\n\t\t */\n\t\tthis._token = token;\n\n\t\t/**\n\t\t * CKEditor Cloud Services API address.\n\t\t *\n\t\t * @type {String}\n\t\t * @private\n\t\t */\n\t\tthis._apiAddress = apiAddress;\n\t}\n\n\t/**\n\t * Creates a {@link module:cloud-services-core/uploadgateway/fileuploader~FileUploader} instance that wraps\n\t * file upload process. The file is being sent at a time when the\n\t * {@link module:cloud-services-core/uploadgateway/fileuploader~FileUploader#send} method is called.\n\t *\n\t *     const token = await Token.create( 'https://token-endpoint' );\n\t *     new UploadGateway( token, 'https://example.org' )\n\t *        .upload( 'FILE' )\n\t *        .onProgress( ( data ) => console.log( data ) )\n\t *        .send()\n\t *        .then( ( response ) => console.log( response ) );\n\t *\n\t * @param {Blob|String} fileOrData A blob object or a data string encoded with Base64.\n\t * @returns {module:cloud-services-core/uploadgateway/fileuploader~FileUploader} Returns `FileUploader` instance.\n\t */\n\tupload( fileOrData ) {\n\t\treturn new FileUploader( fileOrData, this._token, this._apiAddress );\n\t}\n}\n\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* global DOMParser */\n\n/**\n * @module widget/widgettypearound\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Template from '@ckeditor/ckeditor5-ui/src/template';\nimport {\n\tisArrowKeyCode,\n\tisForwardArrowKeyCode,\n\tkeyCodes\n} from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport priorities from '@ckeditor/ckeditor5-utils/src/priorities';\n\nimport {\n\tisTypeAroundWidget,\n\tgetClosestTypeAroundDomButton,\n\tgetTypeAroundButtonPosition,\n\tgetClosestWidgetViewElement,\n\tgetTypeAroundFakeCaretPosition,\n\tTYPE_AROUND_SELECTION_ATTRIBUTE\n} from './utils';\n\nimport {\n\tisNonTypingKeystroke\n} from '@ckeditor/ckeditor5-typing/src/utils/injectunsafekeystrokeshandling';\n\nimport returnIcon from '../../theme/icons/return-arrow.svg';\nimport '../../theme/widgettypearound.css';\n\nconst POSSIBLE_INSERTION_POSITIONS = [ 'before', 'after' ];\n\n// Do the SVG parsing once and then clone the result <svg> DOM element for each new button.\nconst RETURN_ARROW_ICON_ELEMENT = new DOMParser().parseFromString( returnIcon, 'image/svg+xml' ).firstChild;\n\nconst PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';\n\n/**\n * A plugin that allows users to type around widgets where normally it is impossible to place the caret due\n * to limitations of web browsers. These \"tight spots\" occur, for instance, before (or after) a widget being\n * the first (or last) child of its parent or between two block widgets.\n *\n * This plugin extends the {@link module:widget/widget~Widget `Widget`} plugin and injects the user interface\n * with two buttons into each widget instance in the editor. Each of the buttons can be clicked by the\n * user if the widget is next to the \"tight spot\". Once clicked, a paragraph is created with the selection anchored\n * in it so that users can type (or insert content, paste, etc.) straight away.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class WidgetTypeAround extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'WidgetTypeAround';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * A reference to the model widget element that has the fake caret active\n\t\t * on either side of it. It is later used to remove CSS classes associated with the fake caret\n\t\t * when the widget no longer needs it.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/element~Element|null}\n\t\t */\n\t\tthis._currentFakeCaretModelElement = null;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\n\t\t// Set a CSS class on the view editing root when the plugin is disabled so all the buttons\n\t\t// and lines visually disappear. All the interactions are disabled in individual plugin methods.\n\t\tthis.on( 'change:isEnabled', ( evt, data, isEnabled ) => {\n\t\t\teditingView.change( writer => {\n\t\t\t\tfor ( const root of editingView.document.roots ) {\n\t\t\t\t\tif ( isEnabled ) {\n\t\t\t\t\t\twriter.removeClass( PLUGIN_DISABLED_EDITING_ROOT_CLASS, root );\n\t\t\t\t\t} else {\n\t\t\t\t\t\twriter.addClass( PLUGIN_DISABLED_EDITING_ROOT_CLASS, root );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tif ( !isEnabled ) {\n\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\twriter.removeSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE );\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\tthis._enableTypeAroundUIInjection();\n\t\tthis._enableInsertingParagraphsOnButtonClick();\n\t\tthis._enableInsertingParagraphsOnEnterKeypress();\n\t\tthis._enableInsertingParagraphsOnTypingKeystroke();\n\t\tthis._enableTypeAroundFakeCaretActivationUsingKeyboardArrows();\n\t\tthis._enableDeleteIntegration();\n\t\tthis._enableInsertContentIntegration();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tthis._currentFakeCaretModelElement = null;\n\t}\n\n\t/**\n\t * Inserts a new paragraph next to a widget element with the selection anchored in it.\n\t *\n\t * **Note**: This method is heavily user-oriented and will both focus the editing view and scroll\n\t * the viewport to the selection in the inserted paragraph.\n\t *\n\t * @protected\n\t * @param {module:engine/model/element~Element} widgetModelElement The model widget element next to which a paragraph is inserted.\n\t * @param {'before'|'after'} position The position where the paragraph is inserted. Either `'before'` or `'after'` the widget.\n\t */\n\t_insertParagraph( widgetModelElement, position ) {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\n\t\teditor.execute( 'insertParagraph', {\n\t\t\tposition: editor.model.createPositionAt( widgetModelElement, position )\n\t\t} );\n\n\t\teditingView.focus();\n\t\teditingView.scrollToTheSelection();\n\t}\n\n\t/**\n\t * A wrapper for the {@link module:utils/emittermixin~EmitterMixin#listenTo} method that executes the callbacks only\n\t * when the plugin {@link #isEnabled is enabled}.\n\t *\n\t * @private\n\t * @param {module:utils/emittermixin~Emitter} emitter The object that fires the event.\n\t * @param {String} event The name of the event.\n\t * @param {Function} callback The function to be called on event.\n\t * @param {Object} [options={}] Additional options.\n\t * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher\n\t * the priority value the sooner the callback will be fired. Events having the same priority are called in the\n\t * order they were added.\n\t */\n\t_listenToIfEnabled( emitter, event, callback, options ) {\n\t\tthis.listenTo( emitter, event, ( ...args ) => {\n\t\t\t// Do not respond if the plugin is disabled.\n\t\t\tif ( this.isEnabled ) {\n\t\t\t\tcallback( ...args );\n\t\t\t}\n\t\t}, options );\n\t}\n\n\t/**\n\t * Similar to {@link #_insertParagraph}, this method inserts a paragraph except that it\n\t * does not expect a position. Instead, it performs the insertion next to a selected widget\n\t * according to the `widget-type-around` model selection attribute value (fake caret position).\n\t *\n\t * Because this method requires the `widget-type-around` attribute to be set,\n\t * the insertion can only happen when the widget's fake caret is active (e.g. activated\n\t * using the keyboard).\n\t *\n\t * @private\n\t * @returns {Boolean} Returns `true` when the paragraph was inserted (the attribute was present) and `false` otherwise.\n\t */\n\t_insertParagraphAccordingToFakeCaretPosition() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst modelSelection = model.document.selection;\n\t\tconst typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition( modelSelection );\n\n\t\tif ( !typeAroundFakeCaretPosition ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst selectedModelElement = modelSelection.getSelectedElement();\n\n\t\tthis._insertParagraph( selectedModelElement, typeAroundFakeCaretPosition );\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Creates a listener in the editing conversion pipeline that injects the widget type around\n\t * UI into every single widget instance created in the editor.\n\t *\n\t * The UI is delivered as a {@link module:engine/view/uielement~UIElement}\n\t * wrapper which renders DOM buttons that users can use to insert paragraphs.\n\t *\n\t * @private\n\t */\n\t_enableTypeAroundUIInjection() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\t\tconst t = editor.locale.t;\n\t\tconst buttonTitles = {\n\t\t\tbefore: t( 'Insert paragraph before block' ),\n\t\t\tafter: t( 'Insert paragraph after block' )\n\t\t};\n\n\t\teditor.editing.downcastDispatcher.on( 'insert', ( evt, data, conversionApi ) => {\n\t\t\tconst viewElement = conversionApi.mapper.toViewElement( data.item );\n\n\t\t\t// Filter out non-widgets and inline widgets.\n\t\t\tif ( isTypeAroundWidget( viewElement, data.item, schema ) ) {\n\t\t\t\tinjectUIIntoWidget( conversionApi.writer, buttonTitles, viewElement );\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\t}\n\n\t/**\n\t * Brings support for the fake caret that appears when either:\n\t *\n\t * * the selection moves to a widget from a position next to it using arrow keys,\n\t * * the arrow key is pressed when the widget is already selected.\n\t *\n\t * The fake caret lets the user know that they can start typing or just press\n\t * <kbd>Enter</kbd> to insert a paragraph at the position next to a widget as suggested by the fake caret.\n\t *\n\t * The fake caret disappears when the user changes the selection or the editor\n\t * gets blurred.\n\t *\n\t * The whole idea is as follows:\n\t *\n\t * 1. A user does one of the 2 scenarios described at the beginning.\n\t * 2. The \"keydown\" listener is executed and the decision is made whether to show or hide the fake caret.\n\t * 3. If it should show up, the `widget-type-around` model selection attribute is set indicating\n\t *    on which side of the widget it should appear.\n\t * 4. The selection dispatcher reacts to the selection attribute and sets CSS classes responsible for the\n\t *    fake caret on the view widget.\n\t * 5. If the fake caret should disappear, the selection attribute is removed and the dispatcher\n\t *    does the CSS class clean-up in the view.\n\t * 6. Additionally, `change:range` and `FocusTracker#isFocused` listeners also remove the selection\n\t *    attribute (the former also removes widget CSS classes).\n\t *\n\t * @private\n\t */\n\t_enableTypeAroundFakeCaretActivationUsingKeyboardArrows() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst modelSelection = model.document.selection;\n\t\tconst schema = model.schema;\n\t\tconst editingView = editor.editing.view;\n\n\t\t// This is the main listener responsible for the fake caret.\n\t\t// Note: The priority must precede the default Widget class keydown handler (\"high\") and the\n\t\t// TableKeyboard keydown handler (\"high-10\").\n\t\tthis._listenToIfEnabled( editingView.document, 'keydown', ( evt, domEventData ) => {\n\t\t\tif ( isArrowKeyCode( domEventData.keyCode ) ) {\n\t\t\t\tthis._handleArrowKeyPress( evt, domEventData );\n\t\t\t}\n\t\t}, { priority: priorities.get( 'high' ) + 10 } );\n\n\t\t// This listener makes sure the widget type around selection attribute will be gone from the model\n\t\t// selection as soon as the model range changes. This attribute only makes sense when a widget is selected\n\t\t// (and the \"fake horizontal caret\" is visible) so whenever the range changes (e.g. selection moved somewhere else),\n\t\t// let's get rid of the attribute so that the selection downcast dispatcher isn't even bothered.\n\t\tthis._listenToIfEnabled( modelSelection, 'change:range', ( evt, data ) => {\n\t\t\t// Do not reset the selection attribute when the change was indirect.\n\t\t\tif ( !data.directChange ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Get rid of the widget type around attribute of the selection on every change:range.\n\t\t\t// If the range changes, it means for sure, the user is no longer in the active (\"fake horizontal caret\") mode.\n\t\t\teditor.model.change( writer => {\n\t\t\t\twriter.removeSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE );\n\t\t\t} );\n\t\t} );\n\n\t\t// Get rid of the widget type around attribute of the selection on every document change\n\t\t// that makes widget not selected any more (i.e. widget was removed).\n\t\tthis._listenToIfEnabled( model.document, 'change:data', () => {\n\t\t\tconst selectedModelElement = modelSelection.getSelectedElement();\n\n\t\t\tif ( selectedModelElement ) {\n\t\t\t\tconst selectedViewElement = editor.editing.mapper.toViewElement( selectedModelElement );\n\n\t\t\t\tif ( isTypeAroundWidget( selectedViewElement, selectedModelElement, schema ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\teditor.model.change( writer => {\n\t\t\t\twriter.removeSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE );\n\t\t\t} );\n\t\t} );\n\n\t\t// React to changes of the model selection attribute made by the arrow keys listener.\n\t\t// If the block widget is selected and the attribute changes, downcast the attribute to special\n\t\t// CSS classes associated with the active (\"fake horizontal caret\") mode of the widget.\n\t\tthis._listenToIfEnabled( editor.editing.downcastDispatcher, 'selection', ( evt, data, conversionApi ) => {\n\t\t\tconst writer = conversionApi.writer;\n\n\t\t\tif ( this._currentFakeCaretModelElement ) {\n\t\t\t\tconst selectedViewElement = conversionApi.mapper.toViewElement( this._currentFakeCaretModelElement );\n\n\t\t\t\tif ( selectedViewElement ) {\n\t\t\t\t\t// Get rid of CSS classes associated with the active (\"fake horizontal caret\") mode from the view widget.\n\t\t\t\t\twriter.removeClass( POSSIBLE_INSERTION_POSITIONS.map( positionToWidgetCssClass ), selectedViewElement );\n\n\t\t\t\t\tthis._currentFakeCaretModelElement = null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst selectedModelElement = data.selection.getSelectedElement();\n\n\t\t\tif ( !selectedModelElement ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst selectedViewElement = conversionApi.mapper.toViewElement( selectedModelElement );\n\n\t\t\tif ( !isTypeAroundWidget( selectedViewElement, selectedModelElement, schema ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition( data.selection );\n\n\t\t\tif ( !typeAroundFakeCaretPosition ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\twriter.addClass( positionToWidgetCssClass( typeAroundFakeCaretPosition ), selectedViewElement );\n\n\t\t\t// Remember the view widget that got the \"fake-caret\" CSS class. This class should be removed ASAP when the\n\t\t\t// selection changes\n\t\t\tthis._currentFakeCaretModelElement = selectedModelElement;\n\t\t} );\n\n\t\tthis._listenToIfEnabled( editor.ui.focusTracker, 'change:isFocused', ( evt, name, isFocused ) => {\n\t\t\tif ( !isFocused ) {\n\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\twriter.removeSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE );\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\tfunction positionToWidgetCssClass( position ) {\n\t\t\treturn `ck-widget_type-around_show-fake-caret_${ position }`;\n\t\t}\n\t}\n\n\t/**\n\t * A listener executed on each \"keydown\" in the view document, a part of\n\t * {@link #_enableTypeAroundFakeCaretActivationUsingKeyboardArrows}.\n\t *\n\t * It decides whether the arrow keypress should activate the fake caret or not (also whether it should\n\t * be deactivated).\n\t *\n\t * The fake caret activation is done by setting the `widget-type-around` model selection attribute\n\t * in this listener, and stopping and preventing the event that would normally be handled by the widget\n\t * plugin that is responsible for the regular keyboard navigation near/across all widgets (that\n\t * includes inline widgets, which are ignored by the widget type around plugin).\n\t *\n\t * @private\n\t */\n\t_handleArrowKeyPress( evt, domEventData ) {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst modelSelection = model.document.selection;\n\t\tconst schema = model.schema;\n\t\tconst editingView = editor.editing.view;\n\n\t\tconst keyCode = domEventData.keyCode;\n\t\tconst isForward = isForwardArrowKeyCode( keyCode, editor.locale.contentLanguageDirection );\n\t\tconst selectedViewElement = editingView.document.selection.getSelectedElement();\n\t\tconst selectedModelElement = editor.editing.mapper.toModelElement( selectedViewElement );\n\t\tlet shouldStopAndPreventDefault;\n\n\t\t// Handle keyboard navigation when a type-around-compatible widget is currently selected.\n\t\tif ( isTypeAroundWidget( selectedViewElement, selectedModelElement, schema ) ) {\n\t\t\tshouldStopAndPreventDefault = this._handleArrowKeyPressOnSelectedWidget( isForward );\n\t\t}\n\t\t// Handle keyboard arrow navigation when the selection is next to a type-around-compatible widget\n\t\t// and the widget is about to be selected.\n\t\telse if ( modelSelection.isCollapsed ) {\n\t\t\tshouldStopAndPreventDefault = this._handleArrowKeyPressWhenSelectionNextToAWidget( isForward );\n\t\t}\n\n\t\tif ( shouldStopAndPreventDefault ) {\n\t\t\tdomEventData.preventDefault();\n\t\t\tevt.stop();\n\t\t}\n\t}\n\n\t/**\n\t * Handles the keyboard navigation on \"keydown\" when a widget is currently selected and activates or deactivates\n\t * the fake caret for that widget, depending on the current value of the `widget-type-around` model\n\t * selection attribute and the direction of the pressed arrow key.\n\t *\n\t * @private\n\t * @param {Boolean} isForward `true` when the pressed arrow key was responsible for the forward model selection movement\n\t * as in {@link module:utils/keyboard~isForwardArrowKeyCode}.\n\t * @returns {Boolean} Returns `true` when the keypress was handled and no other keydown listener of the editor should\n\t * process the event any further. Returns `false` otherwise.\n\t */\n\t_handleArrowKeyPressOnSelectedWidget( isForward ) {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst modelSelection = model.document.selection;\n\t\tconst typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition( modelSelection );\n\n\t\treturn model.change( writer => {\n\t\t\t// If the fake caret is displayed...\n\t\t\tif ( typeAroundFakeCaretPosition ) {\n\t\t\t\tconst isLeavingWidget = typeAroundFakeCaretPosition === ( isForward ? 'after' : 'before' );\n\n\t\t\t\t// If the keyboard arrow works against the value of the selection attribute...\n\t\t\t\t// then remove the selection attribute but prevent default DOM actions\n\t\t\t\t// and do not let the Widget plugin listener move the selection. This brings\n\t\t\t\t// the widget back to the state, for instance, like if was selected using the mouse.\n\t\t\t\t//\n\t\t\t\t// **Note**: If leaving the widget when the fake caret is active, then the default\n\t\t\t\t// Widget handler will change the selection and, in turn, this will automatically discard\n\t\t\t\t// the selection attribute.\n\t\t\t\tif ( !isLeavingWidget ) {\n\t\t\t\t\twriter.removeSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE );\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// If the fake caret wasn't displayed, let's set it now according to the direction of the arrow\n\t\t\t// key press. This also means we cannot let the Widget plugin listener move the selection.\n\t\t\telse {\n\t\t\t\twriter.setSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE, isForward ? 'after' : 'before' );\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t} );\n\t}\n\n\t/**\n\t * Handles the keyboard navigation on \"keydown\" when **no** widget is selected but the selection is **directly** next\n\t * to one and upon the fake caret should become active for this widget upon arrow keypress\n\t * (AKA entering/selecting the widget).\n\t *\n\t * **Note**: This code mirrors the implementation from the widget plugin but also adds the selection attribute.\n\t * Unfortunately, there is no safe way to let the widget plugin do the selection part first and then just set the\n\t * selection attribute here in the widget type around plugin. This is why this code must duplicate some from the widget plugin.\n\t *\n\t * @private\n\t * @param {Boolean} isForward `true` when the pressed arrow key was responsible for the forward model selection movement\n\t * as in {@link module:utils/keyboard~isForwardArrowKeyCode}.\n\t * @returns {Boolean} Returns `true` when the keypress was handled and no other keydown listener of the editor should\n\t * process the event any further. Returns `false` otherwise.\n\t */\n\t_handleArrowKeyPressWhenSelectionNextToAWidget( isForward ) {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst schema = model.schema;\n\t\tconst widgetPlugin = editor.plugins.get( 'Widget' );\n\n\t\t// This is the widget the selection is about to be set on.\n\t\tconst modelElementNextToSelection = widgetPlugin._getObjectElementNextToSelection( isForward );\n\t\tconst viewElementNextToSelection = editor.editing.mapper.toViewElement( modelElementNextToSelection );\n\n\t\tif ( isTypeAroundWidget( viewElementNextToSelection, modelElementNextToSelection, schema ) ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\twidgetPlugin._setSelectionOverElement( modelElementNextToSelection );\n\t\t\t\twriter.setSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE, isForward ? 'before' : 'after' );\n\t\t\t} );\n\n\t\t\t// The change() block above does the same job as the Widget plugin. The event can\n\t\t\t// be safely canceled.\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Registers a `mousedown` listener for the view document which intercepts events\n\t * coming from the widget type around UI, which happens when a user clicks one of the buttons\n\t * that insert a paragraph next to a widget.\n\t *\n\t * @private\n\t */\n\t_enableInsertingParagraphsOnButtonClick() {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\n\t\tthis._listenToIfEnabled( editingView.document, 'mousedown', ( evt, domEventData ) => {\n\t\t\tconst button = getClosestTypeAroundDomButton( domEventData.domTarget );\n\n\t\t\tif ( !button ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst buttonPosition = getTypeAroundButtonPosition( button );\n\t\t\tconst widgetViewElement = getClosestWidgetViewElement( button, editingView.domConverter );\n\t\t\tconst widgetModelElement = editor.editing.mapper.toModelElement( widgetViewElement );\n\n\t\t\tthis._insertParagraph( widgetModelElement, buttonPosition );\n\n\t\t\tdomEventData.preventDefault();\n\t\t\tevt.stop();\n\t\t} );\n\t}\n\n\t/**\n\t * Creates the <kbd>Enter</kbd> key listener on the view document that allows the user to insert a paragraph\n\t * near the widget when either:\n\t *\n\t * * The fake caret was first activated using the arrow keys,\n\t * * The entire widget is selected in the model.\n\t *\n\t * In the first case, the new paragraph is inserted according to the `widget-type-around` selection\n\t * attribute (see {@link #_handleArrowKeyPress}).\n\t *\n\t * In the second case, the new paragraph is inserted based on whether a soft (<kbd>Shift</kbd>+<kbd>Enter</kbd>) keystroke\n\t * was pressed or not.\n\t *\n\t * @private\n\t */\n\t_enableInsertingParagraphsOnEnterKeypress() {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\n\t\tthis._listenToIfEnabled( editingView.document, 'enter', ( evt, domEventData ) => {\n\t\t\tconst selectedViewElement = editingView.document.selection.getSelectedElement();\n\t\t\tconst selectedModelElement = editor.editing.mapper.toModelElement( selectedViewElement );\n\t\t\tconst schema = editor.model.schema;\n\t\t\tlet wasHandled;\n\n\t\t\t// First check if the widget is selected and there's a type around selection attribute associated\n\t\t\t// with the fake caret that would tell where to insert a new paragraph.\n\t\t\tif ( this._insertParagraphAccordingToFakeCaretPosition() ) {\n\t\t\t\twasHandled = true;\n\t\t\t}\n\t\t\t// Then, if there is no selection attribute associated with the fake caret, check if the widget\n\t\t\t// simply is selected and create a new paragraph according to the keystroke (Shift+)Enter.\n\t\t\telse if ( isTypeAroundWidget( selectedViewElement, selectedModelElement, schema ) ) {\n\t\t\t\tthis._insertParagraph( selectedModelElement, domEventData.isSoft ? 'before' : 'after' );\n\n\t\t\t\twasHandled = true;\n\t\t\t}\n\n\t\t\tif ( wasHandled ) {\n\t\t\t\tdomEventData.preventDefault();\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Similar to the {@link #_enableInsertingParagraphsOnEnterKeypress}, it allows the user\n\t * to insert a paragraph next to a widget when the fake caret was activated using arrow\n\t * keys but it responds to typing keystrokes instead of <kbd>Enter</kbd>.\n\t *\n\t * \"Typing keystrokes\" are keystrokes that insert new content into the document,\n\t * for instance, letters (\"a\") or numbers (\"4\"). The \"keydown\" listener enabled by this method\n\t * will insert a new paragraph according to the `widget-type-around` model selection attribute\n\t * as the user simply starts typing, which creates the impression that the fake caret\n\t * behaves like a real one rendered by the browser (AKA your text appears where the caret was).\n\t *\n\t * **Note**: At the moment this listener creates 2 undo steps: one for the `insertParagraph` command\n\t * and another one for actual typing. It is not a disaster but this may need to be fixed\n\t * sooner or later.\n\t *\n\t * Learn more in {@link module:typing/utils/injectunsafekeystrokeshandling}.\n\t *\n\t * @private\n\t */\n\t_enableInsertingParagraphsOnTypingKeystroke() {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\t\tconst keyCodesHandledSomewhereElse = [\n\t\t\tkeyCodes.enter,\n\t\t\tkeyCodes.delete,\n\t\t\tkeyCodes.backspace\n\t\t];\n\n\t\t// Note: The priority must precede the default Widget class keydown handler (\"high\") and the\n\t\t// TableKeyboard keydown handler (\"high + 1\").\n\t\tthis._listenToIfEnabled( editingView.document, 'keydown', ( evt, domEventData ) => {\n\t\t\t// Don't handle enter/backspace/delete here. They are handled in dedicated listeners.\n\t\t\tif ( !keyCodesHandledSomewhereElse.includes( domEventData.keyCode ) && !isNonTypingKeystroke( domEventData ) ) {\n\t\t\t\tthis._insertParagraphAccordingToFakeCaretPosition();\n\t\t\t}\n\t\t}, { priority: priorities.get( 'high' ) + 1 } );\n\t}\n\n\t/**\n\t * It creates a \"delete\" event listener on the view document to handle cases when the <kbd>Delete</kbd> or <kbd>Backspace</kbd>\n\t * is pressed and the fake caret is currently active.\n\t *\n\t * The fake caret should create an illusion of a real browser caret so that when it appears before or after\n\t * a widget, pressing <kbd>Delete</kbd> or <kbd>Backspace</kbd> should remove a widget or delete the content\n\t * before or after a widget (depending on the content surrounding the widget).\n\t *\n\t * @private\n\t */\n\t_enableDeleteIntegration() {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\t\tconst model = editor.model;\n\t\tconst schema = model.schema;\n\n\t\t// Note: The priority must precede the default Widget class delete handler.\n\t\tthis._listenToIfEnabled( editingView.document, 'delete', ( evt, domEventData ) => {\n\t\t\tconst typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition( model.document.selection );\n\n\t\t\t// This listener handles only these cases when the fake caret is active.\n\t\t\tif ( !typeAroundFakeCaretPosition ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst direction = domEventData.direction;\n\t\t\tconst selectedModelWidget = model.document.selection.getSelectedElement();\n\n\t\t\tconst isFakeCaretBefore = typeAroundFakeCaretPosition === 'before';\n\t\t\tconst isForwardDelete = direction == 'forward';\n\t\t\tconst shouldDeleteEntireWidget = isFakeCaretBefore === isForwardDelete;\n\n\t\t\tif ( shouldDeleteEntireWidget ) {\n\t\t\t\teditor.execute( 'delete', {\n\t\t\t\t\tselection: model.createSelection( selectedModelWidget, 'on' )\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\tconst range = schema.getNearestSelectionRange(\n\t\t\t\t\tmodel.createPositionAt( selectedModelWidget, typeAroundFakeCaretPosition ),\n\t\t\t\t\tdirection\n\t\t\t\t);\n\n\t\t\t\t// If there is somewhere to move selection to, then there will be something to delete.\n\t\t\t\tif ( range ) {\n\t\t\t\t\t// If the range is NOT collapsed, then we know that the range contains an object (see getNearestSelectionRange() docs).\n\t\t\t\t\tif ( !range.isCollapsed ) {\n\t\t\t\t\t\tmodel.change( writer => {\n\t\t\t\t\t\t\twriter.setSelection( range );\n\t\t\t\t\t\t\teditor.execute( isForwardDelete ? 'forwardDelete' : 'delete' );\n\t\t\t\t\t\t} );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst probe = model.createSelection( range.start );\n\t\t\t\t\t\tmodel.modifySelection( probe, { direction } );\n\n\t\t\t\t\t\t// If the range is collapsed, let's see if a non-collapsed range exists that can could be deleted.\n\t\t\t\t\t\t// If such range exists, use the editor command because it it safe for collaboration (it merges where it can).\n\t\t\t\t\t\tif ( !probe.focus.isEqual( range.start ) ) {\n\t\t\t\t\t\t\tmodel.change( writer => {\n\t\t\t\t\t\t\t\twriter.setSelection( range );\n\t\t\t\t\t\t\t\teditor.execute( isForwardDelete ? 'forwardDelete' : 'delete' );\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// If there is no non-collapsed range to be deleted then we are sure that there is an empty element\n\t\t\t\t\t\t// next to a widget that should be removed. \"delete\" and \"forwardDelete\" commands cannot get rid of it\n\t\t\t\t\t\t// so calling Model#deleteContent here manually.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tconst deepestEmptyRangeAncestor = getDeepestEmptyElementAncestor( schema, range.start.parent );\n\n\t\t\t\t\t\t\tmodel.deleteContent( model.createSelection( deepestEmptyRangeAncestor, 'on' ), {\n\t\t\t\t\t\t\t\tdoNotAutoparagraph: true\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If some content was deleted, don't let the handler from the Widget plugin kick in.\n\t\t\t// If nothing was deleted, then the default handler will have nothing to do anyway.\n\t\t\tdomEventData.preventDefault();\n\t\t\tevt.stop();\n\t\t}, { priority: priorities.get( 'high' ) + 1 } );\n\t}\n\n\t/**\n\t * Attaches the {@link module:engine/model/model~Model#event:insertContent} event listener that, for instance, allows the user to paste\n\t * content near a widget when the fake caret is first activated using the arrow keys.\n\t *\n\t * The content is inserted according to the `widget-type-around` selection attribute (see {@link #_handleArrowKeyPress}).\n\t *\n\t * @private\n\t */\n\t_enableInsertContentIntegration() {\n\t\tconst editor = this.editor;\n\t\tconst model = this.editor.model;\n\t\tconst documentSelection = model.document.selection;\n\n\t\tthis._listenToIfEnabled( editor.model, 'insertContent', ( evt, [ content, selectable ] ) => {\n\t\t\tif ( selectable && !selectable.is( 'documentSelection' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition( documentSelection );\n\n\t\t\tif ( !typeAroundFakeCaretPosition ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tevt.stop();\n\n\t\t\treturn model.change( writer => {\n\t\t\t\tconst selectedElement = documentSelection.getSelectedElement();\n\t\t\t\tconst position = model.createPositionAt( selectedElement, typeAroundFakeCaretPosition );\n\t\t\t\tconst selection = writer.createSelection( position );\n\n\t\t\t\tconst result = model.insertContent( content, selection );\n\n\t\t\t\twriter.setSelection( selection );\n\n\t\t\t\treturn result;\n\t\t\t} );\n\t\t}, { priority: 'high' } );\n\t}\n}\n\n// Injects the type around UI into a view widget instance.\n//\n// @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter\n// @param {Object.<String,String>} buttonTitles\n// @param {module:engine/view/element~Element} widgetViewElement\nfunction injectUIIntoWidget( viewWriter, buttonTitles, widgetViewElement ) {\n\tconst typeAroundWrapper = viewWriter.createUIElement( 'div', {\n\t\tclass: 'ck ck-reset_all ck-widget__type-around'\n\t}, function( domDocument ) {\n\t\tconst wrapperDomElement = this.toDomElement( domDocument );\n\n\t\tinjectButtons( wrapperDomElement, buttonTitles );\n\t\tinjectFakeCaret( wrapperDomElement );\n\n\t\treturn wrapperDomElement;\n\t} );\n\n\t// Inject the type around wrapper into the widget's wrapper.\n\tviewWriter.insert( viewWriter.createPositionAt( widgetViewElement, 'end' ), typeAroundWrapper );\n}\n\n// FYI: Not using the IconView class because each instance would need to be destroyed to avoid memory leaks\n// and it's pretty hard to figure out when a view (widget) is gone for good so it's cheaper to use raw\n// <svg> here.\n//\n// @param {HTMLElement} wrapperDomElement\n// @param {Object.<String,String>} buttonTitles\nfunction injectButtons( wrapperDomElement, buttonTitles ) {\n\tfor ( const position of POSSIBLE_INSERTION_POSITIONS ) {\n\t\tconst buttonTemplate = new Template( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-widget__type-around__button',\n\t\t\t\t\t`ck-widget__type-around__button_${ position }`\n\t\t\t\t],\n\t\t\t\ttitle: buttonTitles[ position ]\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\twrapperDomElement.ownerDocument.importNode( RETURN_ARROW_ICON_ELEMENT, true )\n\t\t\t]\n\t\t} );\n\n\t\twrapperDomElement.appendChild( buttonTemplate.render() );\n\t}\n}\n\n// @param {HTMLElement} wrapperDomElement\nfunction injectFakeCaret( wrapperDomElement ) {\n\tconst caretTemplate = new Template( {\n\t\ttag: 'div',\n\t\tattributes: {\n\t\t\tclass: [\n\t\t\t\t'ck',\n\t\t\t\t'ck-widget__type-around__fake-caret'\n\t\t\t]\n\t\t}\n\t} );\n\n\twrapperDomElement.appendChild( caretTemplate.render() );\n}\n\n// Returns the ancestor of an element closest to the root which is empty. For instance,\n// for `<baz>`:\n//\n//\t\t<foo>abc<bar><baz></baz></bar></foo>\n//\n// it returns `<bar>`.\n//\n// @param {module:engine/model/schema~Schema} schema\n// @param {module:engine/model/element~Element} element\n// @returns {module:engine/model/element~Element|null}\nfunction getDeepestEmptyElementAncestor( schema, element ) {\n\tlet deepestEmptyAncestor = element;\n\n\tfor ( const ancestor of element.getAncestors( { parentFirst: true } ) ) {\n\t\tif ( ancestor.childCount > 1 || schema.isLimit( ancestor ) ) {\n\t\t\tbreak;\n\t\t}\n\n\t\tdeepestEmptyAncestor = ancestor;\n\t}\n\n\treturn deepestEmptyAncestor;\n}\n","export default \"<svg viewBox=\\\"0 0 10 8\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M9.055.263v3.972h-6.77M1 4.216l2-2.038m-2 2l2 2.038\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';\n\n/**\n * @module widget/verticalnavigationhandler\n */\n\n/**\n * Returns 'keydown' handler for up/down arrow keys that modifies the caret movement if it's in a text line next to an object.\n *\n * @param {module:engine/controller/editingcontroller~EditingController} editing The editing controller.\n * @returns {Function}\n */\nexport default function verticalNavigationHandler( editing ) {\n\tconst model = editing.model;\n\n\treturn ( evt, data ) => {\n\t\tconst arrowUpPressed = data.keyCode == keyCodes.arrowup;\n\t\tconst arrowDownPressed = data.keyCode == keyCodes.arrowdown;\n\t\tconst expandSelection = data.shiftKey;\n\t\tconst selection = model.document.selection;\n\n\t\tif ( !arrowUpPressed && !arrowDownPressed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst isForward = arrowDownPressed;\n\n\t\t// Navigation is in the opposite direction than the selection direction so this is shrinking of the selection.\n\t\t// Selection for sure will not approach any object.\n\t\tif ( expandSelection && selectionWillShrink( selection, isForward ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Find a range between selection and closest limit element.\n\t\tconst range = findTextRangeFromSelection( editing, selection, isForward );\n\n\t\tif ( !range || range.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If the range is a single line (there is no word wrapping) then move the selection to the position closest to the limit element.\n\t\t//\n\t\t// We can't move the selection directly to the isObject element (eg. table cell) because of dual position at the end/beginning\n\t\t// of wrapped line (it's at the same time at the end of one line and at the start of the next line).\n\t\tif ( isSingleLineRange( editing, range, isForward ) ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\tconst newPosition = isForward ? range.end : range.start;\n\n\t\t\t\tif ( expandSelection ) {\n\t\t\t\t\tconst newSelection = model.createSelection( selection.anchor );\n\t\t\t\t\tnewSelection.setFocus( newPosition );\n\n\t\t\t\t\twriter.setSelection( newSelection );\n\t\t\t\t} else {\n\t\t\t\t\twriter.setSelection( newPosition );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tevt.stop();\n\t\t\tdata.preventDefault();\n\t\t\tdata.stopPropagation();\n\t\t}\n\t};\n}\n\n// Finds the range between selection and closest limit element (in the direction of navigation).\n// The position next to limit element is adjusted to the closest allowed `$text` position.\n//\n// Returns `null` if, according to the schema, the resulting range cannot contain a `$text` element.\n//\n// @param {module:engine/controller/editingcontroller~EditingController} editing The editing controller.\n// @param {module:engine/model/selection~Selection} selection The current selection.\n// @param {Boolean} isForward The expected navigation direction.\n// @returns {module:engine/model/range~Range|null}\n//\nfunction findTextRangeFromSelection( editing, selection, isForward ) {\n\tconst model = editing.model;\n\n\tif ( isForward ) {\n\t\tconst startPosition = selection.isCollapsed ? selection.focus : selection.getLastPosition();\n\t\tconst endPosition = getNearestNonInlineLimit( model, startPosition, 'forward' );\n\n\t\t// There is no limit element, browser should handle this.\n\t\tif ( !endPosition ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst range = model.createRange( startPosition, endPosition );\n\t\tconst lastRangePosition = getNearestTextPosition( model.schema, range, 'backward' );\n\n\t\tif ( lastRangePosition && startPosition.isBefore( lastRangePosition ) ) {\n\t\t\treturn model.createRange( startPosition, lastRangePosition );\n\t\t}\n\n\t\treturn null;\n\t} else {\n\t\tconst endPosition = selection.isCollapsed ? selection.focus : selection.getFirstPosition();\n\t\tconst startPosition = getNearestNonInlineLimit( model, endPosition, 'backward' );\n\n\t\t// There is no limit element, browser should handle this.\n\t\tif ( !startPosition ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst range = model.createRange( startPosition, endPosition );\n\t\tconst firstRangePosition = getNearestTextPosition( model.schema, range, 'forward' );\n\n\t\tif ( firstRangePosition && endPosition.isAfter( firstRangePosition ) ) {\n\t\t\treturn model.createRange( firstRangePosition, endPosition );\n\t\t}\n\n\t\treturn null;\n\t}\n}\n\n// Finds the limit element position that is closest to startPosition.\n//\n// @param {module:engine/model/model~Model} model\n// @param {<module:engine/model/position~Position>} startPosition\n// @param {'forward'|'backward'} direction Search direction.\n// @returns {<module:engine/model/position~Position>|null}\n//\nfunction getNearestNonInlineLimit( model, startPosition, direction ) {\n\tconst schema = model.schema;\n\tconst range = model.createRangeIn( startPosition.root );\n\n\tconst walkerValueType = direction == 'forward' ? 'elementStart' : 'elementEnd';\n\n\tfor ( const { previousPosition, item, type } of range.getWalker( { startPosition, direction } ) ) {\n\t\tif ( schema.isLimit( item ) && !schema.isInline( item ) ) {\n\t\t\treturn previousPosition;\n\t\t}\n\n\t\t// Stop looking for isLimit element if the next element is a block element (it is for sure not single line).\n\t\tif ( type == walkerValueType && schema.isBlock( item ) ) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n// Basing on the provided range, finds the first or last (depending on `direction`) position inside the range\n// that can contain `$text` (according to schema).\n//\n// @param {module:engine/model/schema~Schema} schema The schema.\n// @param {module:engine/model/range~Range} range The range to find the position in.\n// @param {'forward'|'backward'} direction Search direction.\n// @returns {module:engine/model/position~Position} The nearest selection range.\n//\nfunction getNearestTextPosition( schema, range, direction ) {\n\tconst position = direction == 'backward' ? range.end : range.start;\n\n\tif ( schema.checkChild( position, '$text' ) ) {\n\t\treturn position;\n\t}\n\n\tfor ( const { nextPosition } of range.getWalker( { direction } ) ) {\n\t\tif ( schema.checkChild( nextPosition, '$text' ) ) {\n\t\t\treturn nextPosition;\n\t\t}\n\t}\n}\n\n// Checks if the DOM range corresponding to the provided model range renders as a single line by analyzing DOMRects\n// (verifying if they visually wrap content to the next line).\n//\n// @param {module:engine/controller/editingcontroller~EditingController} editing The editing controller.\n// @param {module:engine/model/range~Range} modelRange The current table cell content range.\n// @param {Boolean} isForward The expected navigation direction.\n// @returns {Boolean}\n//\nfunction isSingleLineRange( editing, modelRange, isForward ) {\n\tconst model = editing.model;\n\tconst domConverter = editing.view.domConverter;\n\n\t// Wrapped lines contain exactly the same position at the end of current line\n\t// and at the beginning of next line. That position's client rect is at the end\n\t// of current line. In case of caret at first position of the last line that 'dual'\n\t// position would be detected as it's not the last line.\n\tif ( isForward ) {\n\t\tconst probe = model.createSelection( modelRange.start );\n\n\t\tmodel.modifySelection( probe );\n\n\t\t// If the new position is at the end of the container then we can't use this position\n\t\t// because it would provide incorrect result for eg caption of image and selection\n\t\t// just before end of it. Also in this case there is no \"dual\" position.\n\t\tif ( !probe.focus.isAtEnd && !modelRange.start.isEqual( probe.focus ) ) {\n\t\t\tmodelRange = model.createRange( probe.focus, modelRange.end );\n\t\t}\n\t}\n\n\tconst viewRange = editing.mapper.toViewRange( modelRange );\n\tconst domRange = domConverter.viewRangeToDom( viewRange );\n\tconst rects = Rect.getDomRangeRects( domRange );\n\n\tlet boundaryVerticalPosition;\n\n\tfor ( const rect of rects ) {\n\t\tif ( boundaryVerticalPosition === undefined ) {\n\t\t\tboundaryVerticalPosition = Math.round( rect.bottom );\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Let's check if this rect is in new line.\n\t\tif ( Math.round( rect.top ) >= boundaryVerticalPosition ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tboundaryVerticalPosition = Math.max( boundaryVerticalPosition, Math.round( rect.bottom ) );\n\t}\n\n\treturn true;\n}\n\nfunction selectionWillShrink( selection, isForward ) {\n\treturn !selection.isCollapsed && selection.isBackward == isForward;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module widget/widget\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport MouseObserver from '@ckeditor/ckeditor5-engine/src/view/observer/mouseobserver';\nimport WidgetTypeAround from './widgettypearound/widgettypearound';\nimport { getLabel, isWidget, WIDGET_SELECTED_CLASS_NAME } from './utils';\nimport {\n\tisArrowKeyCode,\n\tisForwardArrowKeyCode\n} from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\nimport '../theme/widget.css';\nimport priorities from '@ckeditor/ckeditor5-utils/src/priorities';\nimport verticalNavigationHandler from './verticalnavigation';\n\n/**\n * The widget plugin. It enables base support for widgets.\n *\n * See {@glink api/widget package page} for more details and documentation.\n *\n * This plugin enables multiple behaviors required by widgets:\n *\n * * The model to view selection converter for the editing pipeline (it handles widget custom selection rendering).\n * If a converted selection wraps around a widget element, that selection is marked as\n * {@link module:engine/view/selection~Selection#isFake fake}. Additionally, the `ck-widget_selected` CSS class\n * is added to indicate that widget has been selected.\n * * The mouse and keyboard events handling on and around widget elements.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Widget extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Widget';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ WidgetTypeAround ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst view = this.editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\t/**\n\t\t * Holds previously selected widgets.\n\t\t *\n\t\t * @private\n\t\t * @type {Set.<module:engine/view/element~Element>}\n\t\t */\n\t\tthis._previouslySelected = new Set();\n\n\t\t// Model to view selection converter.\n\t\t// Converts selection placed over widget element to fake selection\n\t\tthis.editor.editing.downcastDispatcher.on( 'selection', ( evt, data, conversionApi ) => {\n\t\t\t// Remove selected class from previously selected widgets.\n\t\t\tthis._clearPreviouslySelectedWidgets( conversionApi.writer );\n\n\t\t\tconst viewWriter = conversionApi.writer;\n\t\t\tconst viewSelection = viewWriter.document.selection;\n\t\t\tconst selectedElement = viewSelection.getSelectedElement();\n\t\t\tlet lastMarked = null;\n\n\t\t\tfor ( const range of viewSelection.getRanges() ) {\n\t\t\t\tfor ( const value of range ) {\n\t\t\t\t\tconst node = value.item;\n\n\t\t\t\t\t// Do not mark nested widgets in selected one. See: #57.\n\t\t\t\t\tif ( isWidget( node ) && !isChild( node, lastMarked ) ) {\n\t\t\t\t\t\tviewWriter.addClass( WIDGET_SELECTED_CLASS_NAME, node );\n\n\t\t\t\t\t\tthis._previouslySelected.add( node );\n\t\t\t\t\t\tlastMarked = node;\n\n\t\t\t\t\t\t// Check if widget is a single element selected.\n\t\t\t\t\t\tif ( node == selectedElement ) {\n\t\t\t\t\t\t\tviewWriter.setSelection( viewSelection.getRanges(), { fake: true, label: getLabel( selectedElement ) } );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\n\t\t// If mouse down is pressed on widget - create selection over whole widget.\n\t\tview.addObserver( MouseObserver );\n\t\tthis.listenTo( viewDocument, 'mousedown', ( ...args ) => this._onMousedown( ...args ) );\n\n\t\t// There are two keydown listeners working on different priorities. This allows other\n\t\t// features such as WidgetTypeAround or TableKeyboard to attach their listeners in between\n\t\t// and customize the behavior even further in different content/selection scenarios.\n\t\t//\n\t\t// * The first listener handles changing the selection on arrow key press\n\t\t// if the widget is selected or if the selection is next to a widget and the widget\n\t\t// should become selected upon the arrow key press.\n\t\t//\n\t\t// * The second (late) listener makes sure the default browser action on arrow key press is\n\t\t// prevented when a widget is selected. This prevents the selection from being moved\n\t\t// from a fake selection container.\n\t\tthis.listenTo( viewDocument, 'keydown', ( ...args ) => {\n\t\t\tthis._handleSelectionChangeOnArrowKeyPress( ...args );\n\t\t}, { priority: 'high' } );\n\n\t\tthis.listenTo( viewDocument, 'keydown', ( ...args ) => {\n\t\t\tthis._preventDefaultOnArrowKeyPress( ...args );\n\t\t}, { priority: priorities.get( 'high' ) - 20 } );\n\n\t\tthis.listenTo( viewDocument, 'keydown', verticalNavigationHandler( this.editor.editing ) );\n\n\t\t// Handle custom delete behaviour.\n\t\tthis.listenTo( viewDocument, 'delete', ( evt, data ) => {\n\t\t\tif ( this._handleDelete( data.direction == 'forward' ) ) {\n\t\t\t\tdata.preventDefault();\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * Handles {@link module:engine/view/document~Document#event:mousedown mousedown} events on widget elements.\n\t *\n\t * @private\n\t * @param {module:utils/eventinfo~EventInfo} eventInfo\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData\n\t */\n\t_onMousedown( eventInfo, domEventData ) {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\t\tlet element = domEventData.target;\n\n\t\t// Do nothing for single or double click inside nested editable.\n\t\tif ( isInsideNestedEditable( element ) ) {\n\t\t\t// But at least triple click inside nested editable causes broken selection in Safari.\n\t\t\t// For such event, we select the entire nested editable element.\n\t\t\t// See: https://github.com/ckeditor/ckeditor5/issues/1463.\n\t\t\tif ( ( env.isSafari || env.isGecko ) && domEventData.domEvent.detail >= 3 ) {\n\t\t\t\tconst mapper = editor.editing.mapper;\n\t\t\t\tconst viewElement = element.is( 'attributeElement' ) ?\n\t\t\t\t\telement.findAncestor( element => !element.is( 'attributeElement' ) ) : element;\n\t\t\t\tconst modelElement = mapper.toModelElement( viewElement );\n\n\t\t\t\tdomEventData.preventDefault();\n\n\t\t\t\tthis.editor.model.change( writer => {\n\t\t\t\t\twriter.setSelection( modelElement, 'in' );\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\t// If target is not a widget element - check if one of the ancestors is.\n\t\tif ( !isWidget( element ) ) {\n\t\t\telement = element.findAncestor( isWidget );\n\n\t\t\tif ( !element ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tdomEventData.preventDefault();\n\n\t\t// Focus editor if is not focused already.\n\t\tif ( !viewDocument.isFocused ) {\n\t\t\tview.focus();\n\t\t}\n\n\t\t// Create model selection over widget.\n\t\tconst modelElement = editor.editing.mapper.toModelElement( element );\n\n\t\tthis._setSelectionOverElement( modelElement );\n\t}\n\n\t/**\n\t * Handles {@link module:engine/view/document~Document#event:keydown keydown} events and changes\n\t * the model selection when:\n\t *\n\t * * arrow key is pressed when the widget is selected,\n\t * * the selection is next to a widget and the widget should become selected upon the arrow key press.\n\t *\n\t * See {@link #_preventDefaultOnArrowKeyPress}.\n\t *\n\t * @private\n\t * @param {module:utils/eventinfo~EventInfo} eventInfo\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData\n\t */\n\t_handleSelectionChangeOnArrowKeyPress( eventInfo, domEventData ) {\n\t\tconst keyCode = domEventData.keyCode;\n\n\t\t// Checks if the keys were handled and then prevents the default event behaviour and stops\n\t\t// the propagation.\n\t\tif ( !isArrowKeyCode( keyCode ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst model = this.editor.model;\n\t\tconst schema = model.schema;\n\t\tconst modelSelection = model.document.selection;\n\t\tconst objectElement = modelSelection.getSelectedElement();\n\t\tconst isForward = isForwardArrowKeyCode( keyCode, this.editor.locale.contentLanguageDirection );\n\n\t\t// If object element is selected.\n\t\tif ( objectElement && schema.isObject( objectElement ) ) {\n\t\t\tconst position = isForward ? modelSelection.getLastPosition() : modelSelection.getFirstPosition();\n\t\t\tconst newRange = schema.getNearestSelectionRange( position, isForward ? 'forward' : 'backward' );\n\n\t\t\tif ( newRange ) {\n\t\t\t\tmodel.change( writer => {\n\t\t\t\t\twriter.setSelection( newRange );\n\t\t\t\t} );\n\n\t\t\t\tdomEventData.preventDefault();\n\t\t\t\teventInfo.stop();\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\t// If selection is next to object element.\n\t\t// Return if not collapsed.\n\t\tif ( !modelSelection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst objectElementNextToSelection = this._getObjectElementNextToSelection( isForward );\n\n\t\tif ( objectElementNextToSelection && schema.isObject( objectElementNextToSelection ) ) {\n\t\t\tthis._setSelectionOverElement( objectElementNextToSelection );\n\n\t\t\tdomEventData.preventDefault();\n\t\t\teventInfo.stop();\n\t\t}\n\t}\n\n\t/**\n\t * Handles {@link module:engine/view/document~Document#event:keydown keydown} events and prevents\n\t * the default browser behavior to make sure the fake selection is not being moved from a fake selection\n\t * container.\n\t *\n\t * See {@link #_handleSelectionChangeOnArrowKeyPress}.\n\t *\n\t * @private\n\t * @param {module:utils/eventinfo~EventInfo} eventInfo\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData\n\t */\n\t_preventDefaultOnArrowKeyPress( eventInfo, domEventData ) {\n\t\tconst keyCode = domEventData.keyCode;\n\n\t\t// Checks if the keys were handled and then prevents the default event behaviour and stops\n\t\t// the propagation.\n\t\tif ( !isArrowKeyCode( keyCode ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst model = this.editor.model;\n\t\tconst schema = model.schema;\n\t\tconst objectElement = model.document.selection.getSelectedElement();\n\n\t\t// If object element is selected.\n\t\tif ( objectElement && schema.isObject( objectElement ) ) {\n\t\t\tdomEventData.preventDefault();\n\t\t\teventInfo.stop();\n\t\t}\n\t}\n\n\t/**\n\t * Handles delete keys: backspace and delete.\n\t *\n\t * @private\n\t * @param {Boolean} isForward Set to true if delete was performed in forward direction.\n\t * @returns {Boolean|undefined} Returns `true` if keys were handled correctly.\n\t */\n\t_handleDelete( isForward ) {\n\t\t// Do nothing when the read only mode is enabled.\n\t\tif ( this.editor.isReadOnly ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst modelDocument = this.editor.model.document;\n\t\tconst modelSelection = modelDocument.selection;\n\n\t\t// Do nothing on non-collapsed selection.\n\t\tif ( !modelSelection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst objectElement = this._getObjectElementNextToSelection( isForward );\n\n\t\tif ( objectElement ) {\n\t\t\tthis.editor.model.change( writer => {\n\t\t\t\tlet previousNode = modelSelection.anchor.parent;\n\n\t\t\t\t// Remove previous element if empty.\n\t\t\t\twhile ( previousNode.isEmpty ) {\n\t\t\t\t\tconst nodeToRemove = previousNode;\n\t\t\t\t\tpreviousNode = nodeToRemove.parent;\n\n\t\t\t\t\twriter.remove( nodeToRemove );\n\t\t\t\t}\n\n\t\t\t\tthis._setSelectionOverElement( objectElement );\n\t\t\t} );\n\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t/**\n\t * Sets {@link module:engine/model/selection~Selection document's selection} over given element.\n\t *\n\t * @protected\n\t * @param {module:engine/model/element~Element} element\n\t */\n\t_setSelectionOverElement( element ) {\n\t\tthis.editor.model.change( writer => {\n\t\t\twriter.setSelection( writer.createRangeOn( element ) );\n\t\t} );\n\t}\n\n\t/**\n\t * Checks if {@link module:engine/model/element~Element element} placed next to the current\n\t * {@link module:engine/model/selection~Selection model selection} exists and is marked in\n\t * {@link module:engine/model/schema~Schema schema} as `object`.\n\t *\n\t * @protected\n\t * @param {Boolean} forward Direction of checking.\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\t_getObjectElementNextToSelection( forward ) {\n\t\tconst model = this.editor.model;\n\t\tconst schema = model.schema;\n\t\tconst modelSelection = model.document.selection;\n\n\t\t// Clone current selection to use it as a probe. We must leave default selection as it is so it can return\n\t\t// to its current state after undo.\n\t\tconst probe = model.createSelection( modelSelection );\n\t\tmodel.modifySelection( probe, { direction: forward ? 'forward' : 'backward' } );\n\t\tconst objectElement = forward ? probe.focus.nodeBefore : probe.focus.nodeAfter;\n\n\t\tif ( !!objectElement && schema.isObject( objectElement ) ) {\n\t\t\treturn objectElement;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Removes CSS class from previously selected widgets.\n\t *\n\t * @private\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n\t */\n\t_clearPreviouslySelectedWidgets( writer ) {\n\t\tfor ( const widget of this._previouslySelected ) {\n\t\t\twriter.removeClass( WIDGET_SELECTED_CLASS_NAME, widget );\n\t\t}\n\n\t\tthis._previouslySelected.clear();\n\t}\n}\n\n// Returns `true` when element is a nested editable or is placed inside one.\n//\n// @param {module:engine/view/element~Element}\n// @returns {Boolean}\nfunction isInsideNestedEditable( element ) {\n\twhile ( element ) {\n\t\tif ( element.is( 'editableElement' ) && !element.is( 'rootElement' ) ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Click on nested widget should select it.\n\t\tif ( isWidget( element ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\telement = element.parent;\n\t}\n\n\treturn false;\n}\n\n// Checks whether the specified `element` is a child of the `parent` element.\n//\n// @param {module:engine/view/element~Element} element An element to check.\n// @param {module:engine/view/element~Element|null} parent A parent for the element.\n// @returns {Boolean}\nfunction isChild( element, parent ) {\n\tif ( !parent ) {\n\t\treturn false;\n\t}\n\n\treturn Array.from( element.getAncestors() ).includes( parent );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagetextalternative/imagetextalternativecommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { isImage } from '../image/utils';\n\n/**\n * The image text alternative command. It is used to change the `alt` attribute of `<image>` elements.\n *\n * @extends module:core/command~Command\n */\nexport default class ImageTextAlternativeCommand extends Command {\n\t/**\n\t * The command value: `false` if there is no `alt` attribute, otherwise the value of the `alt` attribute.\n\t *\n\t * @readonly\n\t * @observable\n\t * @member {String|Boolean} #value\n\t */\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst element = this.editor.model.document.selection.getSelectedElement();\n\n\t\tthis.isEnabled = isImage( element );\n\n\t\tif ( isImage( element ) && element.hasAttribute( 'alt' ) ) {\n\t\t\tthis.value = element.getAttribute( 'alt' );\n\t\t} else {\n\t\t\tthis.value = false;\n\t\t}\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @fires execute\n\t * @param {Object} options\n\t * @param {String} options.newValue The new value of the `alt` attribute to set.\n\t */\n\texecute( options ) {\n\t\tconst model = this.editor.model;\n\t\tconst imageElement = model.document.selection.getSelectedElement();\n\n\t\tmodel.change( writer => {\n\t\t\twriter.setAttribute( 'alt', options.newValue, imageElement );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagetextalternative/imagetextalternativeediting\n */\n\nimport ImageTextAlternativeCommand from './imagetextalternativecommand';\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\n/**\n * The image text alternative editing plugin.\n *\n * Registers the `'imageTextAlternative'` command.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageTextAlternativeEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageTextAlternativeEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tthis.editor.commands.add( 'imageTextAlternative', new ImageTextAlternativeCommand( this.editor ) );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/labeledfield/labeledfieldview\n */\n\nimport View from '../view';\nimport uid from '@ckeditor/ckeditor5-utils/src/uid';\nimport LabelView from '../label/labelview';\nimport '../../theme/components/labeledfield/labeledfieldview.css';\n\n/**\n * The labeled field view class. It can be used to enhance any view with the following features:\n *\n * * a label,\n * * (optional) an error message,\n * * (optional) an info (status) text,\n *\n * all bound logically by proper DOM attributes for UX and accessibility.  It also provides an interface\n * (e.g. observable properties) that allows controlling those additional features.\n *\n * The constructor of this class requires a callback that returns a view to be labeled. The callback\n * is called with unique ids that allow binding of DOM properties:\n *\n *\t\tconst labeledInputView = new LabeledFieldView( locale, ( labeledFieldView, viewUid, statusUid ) => {\n *\t\t\tconst inputView = new InputTextView( labeledFieldView.locale );\n *\n *\t\t\tinputView.set( {\n *\t\t\t\tid: viewUid,\n *\t\t\t\tariaDescribedById: statusUid\n *\t\t\t} );\n *\n *\t\t\tinputView.bind( 'isReadOnly' ).to( labeledFieldView, 'isEnabled', value => !value );\n *\t\t\tinputView.bind( 'hasError' ).to( labeledFieldView, 'errorText', value => !!value );\n *\n *\t\t\treturn inputView;\n *\t\t} );\n *\n *\t\tlabeledInputView.label = 'User name';\n *\t\tlabeledInputView.infoText = 'Full name like for instance, John Doe.';\n *\t\tlabeledInputView.render();\n *\n *\t\tdocument.body.append( labeledInputView.element );\n *\n * See {@link module:ui/labeledfield/utils} to discover ready–to–use labeled input helpers for common\n * UI components.\n *\n * @extends module:ui/view~View\n */\nexport default class LabeledFieldView extends View {\n\t/**\n\t * Creates an instance of the labeled field view class using a provided creator function\n\t * that provides the view to be labeled.\n\t *\n\t * @param {module:utils/locale~Locale} locale The locale instance.\n\t * @param {Function} viewCreator A function that returns a {@link module:ui/view~View}\n\t * that will be labeled. The following arguments are passed to the creator function:\n\t *\n\t * * an instance of the `LabeledFieldView` to allow binding observable properties,\n\t * * an UID string that connects the {@link #labelView label} and the labeled field view in DOM,\n\t * * an UID string that connects the {@link #statusView status} and the labeled field view in DOM.\n\t */\n\tconstructor( locale, viewCreator ) {\n\t\tsuper( locale );\n\n\t\tconst viewUid = `ck-labeled-field-view-${ uid() }`;\n\t\tconst statusUid = `ck-labeled-field-view-status-${ uid() }`;\n\n\t\t/**\n\t\t * The field view that gets labeled.\n\t\t *\n\t\t * @member {module:ui/view~View} #fieldView\n\t\t */\n\t\tthis.fieldView = viewCreator( this, viewUid, statusUid );\n\n\t\t/**\n\t\t * The text of the label.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #label\n\t\t */\n\t\tthis.set( 'label' );\n\n\t\t/**\n\t\t * Controls whether the component is in read-only mode.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isEnabled\n\t\t */\n\t\tthis.set( 'isEnabled', true );\n\n\t\t/**\n\t\t * An observable flag set `true` when {@link #fieldView} is empty (`false` otherwise).\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isEmpty\n\t\t * @default true\n\t\t */\n\t\tthis.set( 'isEmpty', true );\n\n\t\t/**\n\t\t * An observable flag set `true` when {@link #fieldView} is currently focused by\n\t\t * the user (`false` otherwise).\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isFocused\n\t\t * @default false\n\t\t */\n\t\tthis.set( 'isFocused', false );\n\n\t\t/**\n\t\t * The validation error text. When set, it will be displayed\n\t\t * next to the {@link #fieldView} as a typical validation error message.\n\t\t * Set it to `null` to hide the message.\n\t\t *\n\t\t * **Note:** Setting this property to anything but `null` will automatically\n\t\t * make the `hasError` of the {@link #fieldView} `true`.\n\t\t *\n\t\t * @observable\n\t\t * @member {String|null} #errorText\n\t\t */\n\t\tthis.set( 'errorText', null );\n\n\t\t/**\n\t\t * The additional information text displayed next to the {@link #fieldView} which can\n\t\t * be used to inform the user about its purpose, provide help or hints.\n\t\t *\n\t\t * Set it to `null` to hide the message.\n\t\t *\n\t\t * **Note:** This text will be displayed in the same place as {@link #errorText} but the\n\t\t * latter always takes precedence: if the {@link #errorText} is set, it replaces\n\t\t * {@link #infoText}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String|null} #infoText\n\t\t * @default null\n\t\t */\n\t\tthis.set( 'infoText', null );\n\n\t\t/**\n\t\t * (Optional) The additional CSS class set on the dropdown {@link #element}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #class\n\t\t */\n\t\tthis.set( 'class' );\n\n\t\t/**\n\t\t * The content of the `placeholder` attribute of the {@link #fieldView}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #placeholder\n\t\t */\n\t\tthis.set( 'placeholder' );\n\n\t\t/**\n\t\t * The label view instance that describes the entire view.\n\t\t *\n\t\t * @member {module:ui/label/labelview~LabelView} #labelView\n\t\t */\n\t\tthis.labelView = this._createLabelView( viewUid );\n\n\t\t/**\n\t\t * The status view for the {@link #fieldView}. It displays {@link #errorText} and\n\t\t * {@link #infoText}.\n\t\t *\n\t\t * @member {module:ui/view~View} #statusView\n\t\t */\n\t\tthis.statusView = this._createStatusView( statusUid );\n\n\t\t/**\n\t\t * The combined status text made of {@link #errorText} and {@link #infoText}.\n\t\t * Note that when present, {@link #errorText} always takes precedence in the\n\t\t * status.\n\t\t *\n\t\t * @see #errorText\n\t\t * @see #infoText\n\t\t * @see #statusView\n\t\t * @private\n\t\t * @observable\n\t\t * @member {String|null} #_statusText\n\t\t */\n\t\tthis.bind( '_statusText' ).to(\n\t\t\tthis, 'errorText',\n\t\t\tthis, 'infoText',\n\t\t\t( errorText, infoText ) => errorText || infoText\n\t\t);\n\n\t\tconst bind = this.bindTemplate;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-labeled-field-view',\n\t\t\t\t\tbind.to( 'class' ),\n\t\t\t\t\tbind.if( 'isEnabled', 'ck-disabled', value => !value ),\n\t\t\t\t\tbind.if( 'isEmpty', 'ck-labeled-field-view_empty' ),\n\t\t\t\t\tbind.if( 'isFocused', 'ck-labeled-field-view_focused' ),\n\t\t\t\t\tbind.if( 'placeholder', 'ck-labeled-field-view_placeholder' ),\n\t\t\t\t\tbind.if( 'errorText', 'ck-error' )\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [\n\t\t\t\t\t\t\t'ck',\n\t\t\t\t\t\t\t'ck-labeled-field-view__input-wrapper'\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\tthis.fieldView,\n\t\t\t\t\t\tthis.labelView\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\tthis.statusView\n\t\t\t]\n\t\t} );\n\t}\n\n\t/**\n\t * Creates label view class instance and bind with view.\n\t *\n\t * @private\n\t * @param {String} id Unique id to set as labelView#for attribute.\n\t * @returns {module:ui/label/labelview~LabelView}\n\t */\n\t_createLabelView( id ) {\n\t\tconst labelView = new LabelView( this.locale );\n\n\t\tlabelView.for = id;\n\t\tlabelView.bind( 'text' ).to( this, 'label' );\n\n\t\treturn labelView;\n\t}\n\n\t/**\n\t * Creates the status view instance. It displays {@link #errorText} and {@link #infoText}\n\t * next to the {@link #fieldView}. See {@link #_statusText}.\n\t *\n\t * @private\n\t * @param {String} statusUid Unique id of the status, shared with the {@link #fieldView view's}\n\t * `aria-describedby` attribute.\n\t * @returns {module:ui/view~View}\n\t */\n\t_createStatusView( statusUid ) {\n\t\tconst statusView = new View( this.locale );\n\t\tconst bind = this.bindTemplate;\n\n\t\tstatusView.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-labeled-field-view__status',\n\t\t\t\t\tbind.if( 'errorText', 'ck-labeled-field-view__status_error' ),\n\t\t\t\t\tbind.if( '_statusText', 'ck-hidden', value => !value )\n\t\t\t\t],\n\t\t\t\tid: statusUid,\n\t\t\t\trole: bind.if( 'errorText', 'alert' )\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttext: bind.to( '_statusText' )\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\treturn statusView;\n\t}\n\n\t/**\n\t * Focuses the {@link #fieldView}.\n\t */\n\tfocus() {\n\t\tthis.fieldView.focus();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/inputtext/inputtextview\n */\n\nimport View from '../view';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport '../../theme/components/inputtext/inputtext.css';\n\n/**\n * The text input view class.\n *\n * @extends module:ui/view~View\n */\nexport default class InputTextView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * The value of the input.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #value\n\t\t */\n\t\tthis.set( 'value' );\n\n\t\t/**\n\t\t * The `id` attribute of the input (i.e. to pair with a `<label>` element).\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #id\n\t\t */\n\t\tthis.set( 'id' );\n\n\t\t/**\n\t\t * The `placeholder` attribute of the input.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #placeholder\n\t\t */\n\t\tthis.set( 'placeholder' );\n\n\t\t/**\n\t\t * Controls whether the input view is in read-only mode.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isReadOnly\n\t\t */\n\t\tthis.set( 'isReadOnly', false );\n\n\t\t/**\n\t\t * Set to `true` when the field has some error. Usually controlled via\n\t\t * {@link module:ui/labeledinput/labeledinputview~LabeledInputView#errorText}.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #hasError\n\t\t */\n\t\tthis.set( 'hasError', false );\n\n\t\t/**\n\t\t * The `id` of the element describing this field, e.g. when it has\n\t\t * some error, it helps screen readers read the error text.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #ariaDescribedById\n\t\t */\n\t\tthis.set( 'ariaDescribedById' );\n\n\t\t/**\n\t\t * Stores the information about the editor UI focus and propagates it so various plugins and components\n\t\t * are unified as a focus group.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker} #focusTracker\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * An observable flag set to `true` when the input is currently focused by the user.\n\t\t * `false` otherwise.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isFocused\n\t\t * @default false\n\t\t */\n\t\tthis.bind( 'isFocused' ).to( this.focusTracker );\n\n\t\t/**\n\t\t * An observable flag set to `true` when the input contains no text, i.e.\n\t\t * when {@link #value} is `''`, `null`, or `false`.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isEmpty\n\t\t * @default true\n\t\t */\n\t\tthis.set( 'isEmpty', true );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'input',\n\t\t\tattributes: {\n\t\t\t\ttype: 'text',\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-input',\n\t\t\t\t\t'ck-input-text',\n\t\t\t\t\tbind.if( 'isFocused', 'ck-input_focused' ),\n\t\t\t\t\tbind.if( 'isEmpty', 'ck-input-text_empty' ),\n\t\t\t\t\tbind.if( 'hasError', 'ck-error' )\n\t\t\t\t],\n\t\t\t\tid: bind.to( 'id' ),\n\t\t\t\tplaceholder: bind.to( 'placeholder' ),\n\t\t\t\treadonly: bind.to( 'isReadOnly' ),\n\t\t\t\t'aria-invalid': bind.if( 'hasError', true ),\n\t\t\t\t'aria-describedby': bind.to( 'ariaDescribedById' )\n\t\t\t},\n\t\t\ton: {\n\t\t\t\tinput: bind.to( 'input' ),\n\t\t\t\tchange: bind.to( this._updateIsEmpty.bind( this ) )\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * Fired when the user types in the input. Corresponds to the native\n\t\t * DOM `input` event.\n\t\t *\n\t\t * @event input\n\t\t */\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.focusTracker.add( this.element );\n\n\t\tthis._setDomElementValue( this.value );\n\t\tthis._updateIsEmpty();\n\n\t\t// Bind `this.value` to the DOM element's value.\n\t\t// We cannot use `value` DOM attribute because removing it on Edge does not clear the DOM element's value property.\n\t\tthis.on( 'change:value', ( evt, name, value ) => {\n\t\t\tthis._setDomElementValue( value );\n\t\t\tthis._updateIsEmpty();\n\t\t} );\n\t}\n\n\t/**\n\t * Moves the focus to the input and selects the value.\n\t */\n\tselect() {\n\t\tthis.element.select();\n\t}\n\n\t/**\n\t * Focuses the input.\n\t */\n\tfocus() {\n\t\tthis.element.focus();\n\t}\n\n\t/**\n\t * Updates the {@link #isEmpty} property value on demand.\n\t *\n\t * @private\n\t */\n\t_updateIsEmpty() {\n\t\tthis.isEmpty = isInputElementEmpty( this.element );\n\t}\n\n\t/**\n\t * Sets the `value` property of the {@link #element DOM element} on demand.\n\t *\n\t * @private\n\t */\n\t_setDomElementValue( value ) {\n\t\tthis.element.value = ( !value && value !== 0 ) ? '' : value;\n\t}\n}\n\nfunction isInputElementEmpty( domElement ) {\n\treturn !domElement.value;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/labeledfield/utils\n */\n\nimport InputTextView from '../inputtext/inputtextview';\nimport { createDropdown } from '../dropdown/utils';\n\n/**\n * A helper for creating labeled inputs.\n *\n * It creates an instance of a {@link module:ui/inputtext/inputtextview~InputTextView input text} that is\n * logically related to a {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView labeled view} in DOM.\n *\n * The helper does the following:\n *\n * * It sets input's `id` and `ariaDescribedById` attributes.\n * * It binds input's `isReadOnly` to the labeled view.\n * * It binds input's `hasError` to the labeled view.\n * * It enables a logic that cleans up the error when user starts typing in the input..\n *\n * Usage:\n *\n *\t\tconst labeledInputView = new LabeledFieldView( locale, createLabeledDropdown );\n *\t\tconsole.log( labeledInputView.view ); // An input instance.\n *\n * @param {module:ui/labeledfield/labeledfieldview~LabeledFieldView} labeledFieldView The instance of the labeled field view.\n * @param {String} viewUid An UID string that allows DOM logical connection between the\n * {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView#labelView labeled view's label} and the input.\n * @param {String} statusUid An UID string that allows DOM logical connection between the\n * {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView#statusView labeled view's status} and the input.\n * @returns {module:ui/inputtext/inputtextview~InputTextView} The input text view instance.\n */\nexport function createLabeledInputText( labeledFieldView, viewUid, statusUid ) {\n\tconst inputView = new InputTextView( labeledFieldView.locale );\n\n\tinputView.set( {\n\t\tid: viewUid,\n\t\tariaDescribedById: statusUid\n\t} );\n\n\tinputView.bind( 'isReadOnly' ).to( labeledFieldView, 'isEnabled', value => !value );\n\tinputView.bind( 'hasError' ).to( labeledFieldView, 'errorText', value => !!value );\n\n\tinputView.on( 'input', () => {\n\t\t// UX: Make the error text disappear and disable the error indicator as the user\n\t\t// starts fixing the errors.\n\t\tlabeledFieldView.errorText = null;\n\t} );\n\n\tlabeledFieldView.bind( 'isEmpty', 'isFocused', 'placeholder' ).to( inputView );\n\n\treturn inputView;\n}\n\n/**\n * A helper for creating labeled dropdowns.\n *\n * It creates an instance of a {@link module:ui/dropdown/dropdownview~DropdownView dropdown} that is\n * logically related to a {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView labeled field view}.\n *\n * The helper does the following:\n *\n * * It sets dropdown's `id` and `ariaDescribedById` attributes.\n * * It binds input's `isEnabled` to the labeled view.\n *\n * Usage:\n *\n *\t\tconst labeledInputView = new LabeledFieldView( locale, createLabeledDropdown );\n *\t\tconsole.log( labeledInputView.view ); // A dropdown instance.\n *\n * @param {module:ui/labeledfield/labeledfieldview~LabeledFieldView} labeledFieldView The instance of the labeled field view.\n * @param {String} viewUid An UID string that allows DOM logical connection between the\n * {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView#labelView labeled view label} and the dropdown.\n * @param {String} statusUid An UID string that allows DOM logical connection between the\n * {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView#statusView labeled view status} and the dropdown.\n * @returns {module:ui/dropdown/dropdownview~DropdownView} The dropdown view instance.\n */\nexport function createLabeledDropdown( labeledFieldView, viewUid, statusUid ) {\n\tconst dropdownView = createDropdown( labeledFieldView.locale );\n\n\tdropdownView.set( {\n\t\tid: viewUid,\n\t\tariaDescribedById: statusUid\n\t} );\n\n\tdropdownView.bind( 'isEnabled' ).to( labeledFieldView );\n\n\treturn dropdownView;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/bindings/injectcsstransitiondisabler\n */\n\n/**\n * A decorator that brings possibility to temporarily disable CSS transitions using\n * {@link module:ui/view~View} methods. It is helpful when, for instance, the transitions should not happen\n * when the view is first displayed but they should work normally in other cases.\n *\n * The methods to control the CSS transitions are:\n * * `disableCssTransitions()` – adds the `.ck-transitions-disabled` class to the\n * {@link module:ui/view~View#element view element},\n * * `enableCssTransitions()` – removes the `.ck-transitions-disabled` class from the\n * {@link module:ui/view~View#element view element}.\n *\n * **Note**: This helper extends the {@link module:ui/view~View#template template} and must be used **after**\n * {@link module:ui/view~View#setTemplate} is called:\n *\n *\t\timport injectCssTransitionDisabler from '@ckeditor/ckeditor5-ui/src/bindings/injectcsstransitiondisabler';\n *\n *\t\tclass MyView extends View {\n *\t\t\tconstructor() {\n *\t\t\t\tsuper();\n *\n *\t\t\t\t// ...\n *\n *\t\t\t\tthis.setTemplate( { ... } );\n *\n *\t\t\t\t// ...\n *\n *\t\t\t\tinjectCssTransitionDisabler( this );\n *\n *\t\t\t\t// ...\n *\t\t\t}\n *\t\t}\n *\n * The usage comes down to:\n *\n *\t\tconst view = new MyView();\n *\n *\t\t// ...\n *\n *\t\tview.disableCssTransitions();\n *\t\tview.show();\n *\t\tview.enableCssTransitions();\n *\n * @param {module:ui/view~View} view View instance that should get this functionality.\n */\nexport default function injectCssTransitionDisabler( view ) {\n\tview.set( '_isCssTransitionsDisabled', false );\n\n\tview.disableCssTransitions = () => {\n\t\tview._isCssTransitionsDisabled = true;\n\t};\n\n\tview.enableCssTransitions = () => {\n\t\tview._isCssTransitionsDisabled = false;\n\t};\n\n\tview.extendTemplate( {\n\t\tattributes: {\n\t\t\tclass: [\n\t\t\t\tview.bindTemplate.if( '_isCssTransitionsDisabled', 'ck-transitions-disabled' )\n\t\t\t]\n\t\t}\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/bindings/submithandler\n */\n\n/**\n * A handler useful for {@link module:ui/view~View views} working as HTML forms. It intercepts a native DOM\n * `submit` event, prevents the default web browser behavior (navigation and page reload) and\n * fires the `submit` event on a view instead. Such a custom event can be then used by any\n * {@link module:utils/dom/emittermixin~Emitter emitter}, e.g. to serialize the form data.\n *\n *\t\timport submitHandler from '@ckeditor/ckeditor5-ui/src/bindings/submithandler';\n *\n *\t\t// ...\n *\n *\t\tclass AnyFormView extends View {\n *\t\t\tconstructor() {\n *\t\t\t\tsuper();\n *\n *\t\t\t\t// ...\n *\n *\t\t\t\tsubmitHandler( {\n *\t\t\t\t\tview: this\n *\t\t\t\t} );\n *\t\t\t}\n *\t\t}\n *\n *\t\t// ...\n *\n *\t\tconst view = new AnyFormView();\n *\n *\t\t// A sample listener attached by an emitter working with the view.\n *\t\tthis.listenTo( view, 'submit', () => {\n *\t\t\tsaveTheFormData();\n *\t\t\thideTheForm();\n *\t\t} );\n *\n * @param {Object} [options] Configuration options.\n * @param {module:ui/view~View} options.view The view which DOM `submit` events should be handled.\n */\nexport default function submitHandler( { view } ) {\n\tview.listenTo( view.element, 'submit', ( evt, domEvt ) => {\n\t\tdomEvt.preventDefault();\n\t\tview.fire( 'submit' );\n\t}, { useCapture: true } );\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M6.972 16.615a.997.997 0 0 1-.744-.292l-4.596-4.596a1 1 0 1 1 1.414-1.414l3.926 3.926 9.937-9.937a1 1 0 0 1 1.414 1.415L7.717 16.323a.997.997 0 0 1-.745.292z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M11.591 10.177l4.243 4.242a1 1 0 0 1-1.415 1.415l-4.242-4.243-4.243 4.243a1 1 0 0 1-1.414-1.415l4.243-4.242L4.52 5.934A1 1 0 0 1 5.934 4.52l4.243 4.243 4.242-4.243a1 1 0 1 1 1.415 1.414l-4.243 4.243z\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagetextalternative/ui/textalternativeformview\n */\n\nimport View from '@ckeditor/ckeditor5-ui/src/view';\nimport ViewCollection from '@ckeditor/ckeditor5-ui/src/viewcollection';\n\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\n\nimport LabeledFieldView from '@ckeditor/ckeditor5-ui/src/labeledfield/labeledfieldview';\nimport { createLabeledInputText } from '@ckeditor/ckeditor5-ui/src/labeledfield/utils';\nimport injectCssTransitionDisabler from '@ckeditor/ckeditor5-ui/src/bindings/injectcsstransitiondisabler';\n\nimport submitHandler from '@ckeditor/ckeditor5-ui/src/bindings/submithandler';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport FocusCycler from '@ckeditor/ckeditor5-ui/src/focuscycler';\n\nimport checkIcon from '@ckeditor/ckeditor5-core/theme/icons/check.svg';\nimport cancelIcon from '@ckeditor/ckeditor5-core/theme/icons/cancel.svg';\nimport '../../../theme/textalternativeform.css';\nimport '@ckeditor/ckeditor5-ui/theme/components/responsive-form/responsiveform.css';\n\n/**\n * The TextAlternativeFormView class.\n *\n * @extends module:ui/view~View\n */\nexport default class TextAlternativeFormView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst t = this.locale.t;\n\n\t\t/**\n\t\t * Tracks information about the DOM focus in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * An input with a label.\n\t\t *\n\t\t * @member {module:ui/labeledfield/labeledfieldview~LabeledFieldView} #labeledInput\n\t\t */\n\t\tthis.labeledInput = this._createLabeledInputView();\n\n\t\t/**\n\t\t * A button used to submit the form.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView} #saveButtonView\n\t\t */\n\t\tthis.saveButtonView = this._createButton( t( 'Save' ), checkIcon, 'ck-button-save' );\n\t\tthis.saveButtonView.type = 'submit';\n\n\t\t/**\n\t\t * A button used to cancel the form.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView} #cancelButtonView\n\t\t */\n\t\tthis.cancelButtonView = this._createButton( t( 'Cancel' ), cancelIcon, 'ck-button-cancel', 'cancel' );\n\n\t\t/**\n\t\t * A collection of views which can be focused in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis._focusables = new ViewCollection();\n\n\t\t/**\n\t\t * Helps cycling over {@link #_focusables} in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this._focusables,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate form fields backwards using the Shift + Tab keystroke.\n\t\t\t\tfocusPrevious: 'shift + tab',\n\n\t\t\t\t// Navigate form fields forwards using the Tab key.\n\t\t\t\tfocusNext: 'tab'\n\t\t\t}\n\t\t} );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'form',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-text-alternative-form',\n\t\t\t\t\t'ck-responsive-form'\n\t\t\t\t],\n\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-image/issues/40\n\t\t\t\ttabindex: '-1'\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\tthis.labeledInput,\n\t\t\t\tthis.saveButtonView,\n\t\t\t\tthis.cancelButtonView\n\t\t\t]\n\t\t} );\n\n\t\tinjectCssTransitionDisabler( this );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.keystrokes.listenTo( this.element );\n\n\t\tsubmitHandler( { view: this } );\n\n\t\t[ this.labeledInput, this.saveButtonView, this.cancelButtonView ]\n\t\t\t.forEach( v => {\n\t\t\t\t// Register the view as focusable.\n\t\t\t\tthis._focusables.add( v );\n\n\t\t\t\t// Register the view in the focus tracker.\n\t\t\t\tthis.focusTracker.add( v.element );\n\t\t\t} );\n\t}\n\n\t/**\n\t * Creates the button view.\n\t *\n\t * @private\n\t * @param {String} label The button label\n\t * @param {String} icon The button's icon.\n\t * @param {String} className The additional button CSS class name.\n\t * @param {String} [eventName] The event name that the ButtonView#execute event will be delegated to.\n\t * @returns {module:ui/button/buttonview~ButtonView} The button view instance.\n\t */\n\t_createButton( label, icon, className, eventName ) {\n\t\tconst button = new ButtonView( this.locale );\n\n\t\tbutton.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true\n\t\t} );\n\n\t\tbutton.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: className\n\t\t\t}\n\t\t} );\n\n\t\tif ( eventName ) {\n\t\t\tbutton.delegate( 'execute' ).to( this, eventName );\n\t\t}\n\n\t\treturn button;\n\t}\n\n\t/**\n\t * Creates an input with a label.\n\t *\n\t * @private\n\t * @returns {module:ui/labeledfield/labeledfieldview~LabeledFieldView} Labeled field view instance.\n\t */\n\t_createLabeledInputView() {\n\t\tconst t = this.locale.t;\n\t\tconst labeledInput = new LabeledFieldView( this.locale, createLabeledInputText );\n\n\t\tlabeledInput.label = t( 'Text alternative' );\n\n\t\treturn labeledInput;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/panel/balloon/contextualballoon\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport BalloonPanelView from './balloonpanelview';\nimport View from '../../view';\nimport ButtonView from '../../button/buttonview';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';\nimport Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';\n\nimport prevIcon from '../../../theme/icons/previous-arrow.svg';\nimport nextIcon from '../../../theme/icons/next-arrow.svg';\n\nimport '../../../theme/components/panel/balloonrotator.css';\nimport '../../../theme/components/panel/fakepanel.css';\n\nconst toPx = toUnit( 'px' );\n\n/**\n * Provides the common contextual balloon for the editor.\n *\n * The role of this plugin is to unify the contextual balloons logic, simplify views management and help\n * avoid the unnecessary complexity of handling multiple {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView}\n * instances in the editor.\n *\n * This plugin allows for creating single or multiple panel stacks.\n *\n * Each stack may have multiple views, with the one on the top being visible. When the visible view is removed from the stack,\n * the previous view becomes visible.\n *\n * It might be useful to implement nested navigation in a balloon. For instance, a toolbar view may contain a link button.\n * When you click it, a link view (which lets you set the URL) is created and put on top of the toolbar view, so the link panel\n * is displayed. When you finish editing the link and close (remove) the link view, the toolbar view is visible again.\n *\n * However, there are cases when there are multiple independent balloons to be displayed, for instance, if the selection\n * is inside two inline comments at the same time. For such cases, you can create two independent panel stacks.\n * The contextual balloon plugin will create a navigation bar to let the users switch between these panel stacks using the \"Next\"\n * and \"Previous\" buttons.\n *\n * If there are no views in the current stack, the balloon panel will try to switch to the next stack. If there are no\n * panels in any stack, the balloon panel will be hidden.\n *\n * **Note**: To force the balloon panel to show only one view, even if there are other stacks, use the `singleViewMode=true` option\n * when {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon#add adding} a view to a panel.\n *\n * From the implementation point of view, the contextual ballon plugin is reusing a single\n * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView} instance to display multiple contextual balloon\n * panels in the editor. It also creates a special {@link module:ui/panel/balloon/contextualballoon~RotatorView rotator view},\n * used to manage multiple panel stacks. Rotator view is a child of the balloon panel view and the parent of the specific\n * view you want to display. If there is more than one panel stack to be displayed, the rotator view will add a\n * navigation bar. If there is only one stack, the rotator view is transparent (it does not add any UI elements).\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ContextualBalloon extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ContextualBalloon';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The {@link module:utils/dom/position~Options#limiter position limiter}\n\t\t * for the {@link #view balloon}, used when no `limiter` has been passed into {@link #add}\n\t\t * or {@link #updatePosition}.\n\t\t *\n\t\t * By default, a function that obtains the farthest DOM\n\t\t * {@link module:engine/view/rooteditableelement~RootEditableElement}\n\t\t * of the {@link module:engine/view/document~Document#selection}.\n\t\t *\n\t\t * @member {module:utils/dom/position~Options#limiter} #positionLimiter\n\t\t */\n\t\tthis.positionLimiter = () => {\n\t\t\tconst view = this.editor.editing.view;\n\t\t\tconst viewDocument = view.document;\n\t\t\tconst editableElement = viewDocument.selection.editableElement;\n\n\t\t\tif ( editableElement ) {\n\t\t\t\treturn view.domConverter.mapViewToDom( editableElement.root );\n\t\t\t}\n\n\t\t\treturn null;\n\t\t};\n\n\t\t/**\n\t\t * The currently visible view or `null` when there are no views in any stack.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {module:ui/view~View|null} #visibleView\n\t\t */\n\t\tthis.set( 'visibleView', null );\n\n\t\t/**\n\t\t * The common balloon panel view.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/panel/balloon/balloonpanelview~BalloonPanelView} #view\n\t\t */\n\t\tthis.view = new BalloonPanelView( editor.locale );\n\t\teditor.ui.view.body.add( this.view );\n\t\teditor.ui.focusTracker.add( this.view.element );\n\n\t\t/**\n\t\t * The map of views and their stacks.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.<module:ui/view~View,Set>}\n\t\t */\n\t\tthis._viewToStack = new Map();\n\n\t\t/**\n\t\t * The map of IDs and stacks.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.<String,Set>}\n\t\t */\n\t\tthis._idToStack = new Map();\n\n\t\t/**\n\t\t * A total number of all stacks in the balloon.\n\t\t *\n\t\t * @private\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number} #_numberOfStacks\n\t\t */\n\t\tthis.set( '_numberOfStacks', 0 );\n\n\t\t/**\n\t\t * A flag that controls the single view mode.\n\t\t *\n\t\t * @private\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #_singleViewMode\n\t\t */\n\t\tthis.set( '_singleViewMode', false );\n\n\t\t/**\n\t\t * Rotator view embedded in the contextual balloon.\n\t\t * Displays the currently visible view in the balloon and provides navigation for switching stacks.\n\t\t *\n\t\t * @private\n\t\t * @type {module:ui/panel/balloon/contextualballoon~RotatorView}\n\t\t */\n\t\tthis._rotatorView = this._createRotatorView();\n\n\t\t/**\n\t\t * Displays fake panels under the balloon panel view when multiple stacks are added to the balloon.\n\t\t *\n\t\t * @private\n\t\t * @type {module:ui/view~View}\n\t\t */\n\t\tthis._fakePanelsView = this._createFakePanelsView();\n\t}\n\n\t/**\n\t * Returns `true` when the given view is in one of the stacks. Otherwise returns `false`.\n\t *\n\t * @param {module:ui/view~View} view\n\t * @returns {Boolean}\n\t */\n\thasView( view ) {\n\t\treturn Array.from( this._viewToStack.keys() ).includes( view );\n\t}\n\n\t/**\n\t * Adds a new view to the stack and makes it visible if the current stack is visible\n\t * or it is the first view in the balloon.\n\t *\n\t * @param {Object} data The configuration of the view.\n\t * @param {String} [data.stackId='main'] The ID of the stack that the view is added to.\n\t * @param {module:ui/view~View} [data.view] The content of the balloon.\n\t * @param {module:utils/dom/position~Options} [data.position] Positioning options.\n\t * @param {String} [data.balloonClassName] An additional CSS class added to the {@link #view balloon} when visible.\n\t * @param {Boolean} [data.withArrow=true] Whether the {@link #view balloon} should be rendered with an arrow.\n\t * @param {Boolean} [data.singleViewMode=false] Whether the view should be the only visible view even if other stacks were added.\n\t */\n\tadd( data ) {\n\t\tif ( this.hasView( data.view ) ) {\n\t\t\t/**\n\t\t\t * Trying to add configuration of the same view more than once.\n\t\t\t *\n\t\t\t * @error contextualballoon-add-view-exist\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'contextualballoon-add-view-exist',\n\t\t\t\t[ this, data ]\n\t\t\t);\n\t\t}\n\n\t\tconst stackId = data.stackId || 'main';\n\n\t\t// If new stack is added, creates it and show view from this stack.\n\t\tif ( !this._idToStack.has( stackId ) ) {\n\t\t\tthis._idToStack.set( stackId, new Map( [ [ data.view, data ] ] ) );\n\t\t\tthis._viewToStack.set( data.view, this._idToStack.get( stackId ) );\n\t\t\tthis._numberOfStacks = this._idToStack.size;\n\n\t\t\tif ( !this._visibleStack || data.singleViewMode ) {\n\t\t\t\tthis.showStack( stackId );\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst stack = this._idToStack.get( stackId );\n\n\t\tif ( data.singleViewMode ) {\n\t\t\tthis.showStack( stackId );\n\t\t}\n\n\t\t// Add new view to the stack.\n\t\tstack.set( data.view, data );\n\t\tthis._viewToStack.set( data.view, stack );\n\n\t\t// And display it if is added to the currently visible stack.\n\t\tif ( stack === this._visibleStack ) {\n\t\t\tthis._showView( data );\n\t\t}\n\t}\n\n\t/**\n\t * Removes the given view from the stack. If the removed view was visible,\n\t * the view preceding it in the stack will become visible instead.\n\t * When there is no view in the stack, the next stack will be displayed.\n\t * When there are no more stacks, the balloon will hide.\n\t *\n\t * @param {module:ui/view~View} view A view to be removed from the balloon.\n\t */\n\tremove( view ) {\n\t\tif ( !this.hasView( view ) ) {\n\t\t\t/**\n\t\t\t * Trying to remove the configuration of the view not defined in the stack.\n\t\t\t *\n\t\t\t * @error contextualballoon-remove-view-not-exist\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'contextualballoon-remove-view-not-exist',\n\t\t\t\t[ this, view ]\n\t\t\t);\n\t\t}\n\n\t\tconst stack = this._viewToStack.get( view );\n\n\t\tif ( this._singleViewMode && this.visibleView === view ) {\n\t\t\tthis._singleViewMode = false;\n\t\t}\n\n\t\t// When visible view will be removed we need to show a preceding view or next stack\n\t\t// if a view is the only view in the stack.\n\t\tif ( this.visibleView === view ) {\n\t\t\tif ( stack.size === 1 ) {\n\t\t\t\tif ( this._idToStack.size > 1 ) {\n\t\t\t\t\tthis._showNextStack();\n\t\t\t\t} else {\n\t\t\t\t\tthis.view.hide();\n\t\t\t\t\tthis.visibleView = null;\n\t\t\t\t\tthis._rotatorView.hideView();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis._showView( Array.from( stack.values() )[ stack.size - 2 ] );\n\t\t\t}\n\t\t}\n\n\t\tif ( stack.size === 1 ) {\n\t\t\tthis._idToStack.delete( this._getStackId( stack ) );\n\t\t\tthis._numberOfStacks = this._idToStack.size;\n\t\t} else {\n\t\t\tstack.delete( view );\n\t\t}\n\n\t\tthis._viewToStack.delete( view );\n\t}\n\n\t/**\n\t * Updates the position of the balloon using the position data of the first visible view in the stack.\n\t * When new position data is given, the position data of the currently visible view will be updated.\n\t *\n\t * @param {module:utils/dom/position~Options} [position] position options.\n\t */\n\tupdatePosition( position ) {\n\t\tif ( position ) {\n\t\t\tthis._visibleStack.get( this.visibleView ).position = position;\n\t\t}\n\n\t\tthis.view.pin( this._getBalloonPosition() );\n\t\tthis._fakePanelsView.updatePosition();\n\t}\n\n\t/**\n\t * Shows the last view from the stack of a given ID.\n\t *\n\t * @param {String} id\n\t */\n\tshowStack( id ) {\n\t\tthis.visibleStack = id;\n\t\tconst stack = this._idToStack.get( id );\n\n\t\tif ( !stack ) {\n\t\t\t/**\n\t\t\t * Trying to show a stack that does not exist.\n\t\t\t *\n\t\t\t * @error contextualballoon-showstack-stack-not-exist\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'contextualballoon-showstack-stack-not-exist',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tif ( this._visibleStack === stack ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._showView( Array.from( stack.values() ).pop() );\n\t}\n\n\t/**\n\t * Returns the stack of the currently visible view.\n\t *\n\t * @private\n\t * @type {Set}\n\t */\n\tget _visibleStack() {\n\t\treturn this._viewToStack.get( this.visibleView );\n\t}\n\n\t/**\n\t * Returns the ID of the given stack.\n\t *\n\t * @private\n\t * @param {Set} stack\n\t * @returns {String}\n\t */\n\t_getStackId( stack ) {\n\t\tconst entry = Array.from( this._idToStack.entries() ).find( entry => entry[ 1 ] === stack );\n\n\t\treturn entry[ 0 ];\n\t}\n\n\t/**\n\t * Shows the last view from the next stack.\n\t *\n\t * @private\n\t */\n\t_showNextStack() {\n\t\tconst stacks = Array.from( this._idToStack.values() );\n\n\t\tlet nextIndex = stacks.indexOf( this._visibleStack ) + 1;\n\n\t\tif ( !stacks[ nextIndex ] ) {\n\t\t\tnextIndex = 0;\n\t\t}\n\n\t\tthis.showStack( this._getStackId( stacks[ nextIndex ] ) );\n\t}\n\n\t/**\n\t * Shows the last view from the previous stack.\n\t *\n\t * @private\n\t */\n\t_showPrevStack() {\n\t\tconst stacks = Array.from( this._idToStack.values() );\n\n\t\tlet nextIndex = stacks.indexOf( this._visibleStack ) - 1;\n\n\t\tif ( !stacks[ nextIndex ] ) {\n\t\t\tnextIndex = stacks.length - 1;\n\t\t}\n\n\t\tthis.showStack( this._getStackId( stacks[ nextIndex ] ) );\n\t}\n\n\t/**\n\t * Creates a rotator view.\n\t *\n\t * @private\n\t * @returns {module:ui/panel/balloon/contextualballoon~RotatorView}\n\t */\n\t_createRotatorView() {\n\t\tconst view = new RotatorView( this.editor.locale );\n\t\tconst t = this.editor.locale.t;\n\n\t\tthis.view.content.add( view );\n\n\t\t// Hide navigation when there is only a one stack & not in single view mode.\n\t\tview.bind( 'isNavigationVisible' ).to( this, '_numberOfStacks', this, '_singleViewMode', ( value, isSingleViewMode ) => {\n\t\t\treturn !isSingleViewMode && value > 1;\n\t\t} );\n\n\t\t// Update balloon position after toggling navigation.\n\t\tview.on( 'change:isNavigationVisible', () => ( this.updatePosition() ), { priority: 'low' } );\n\n\t\t// Update stacks counter value.\n\t\tview.bind( 'counter' ).to( this, 'visibleView', this, '_numberOfStacks', ( visibleView, numberOfStacks ) => {\n\t\t\tif ( numberOfStacks < 2 ) {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tconst current = Array.from( this._idToStack.values() ).indexOf( this._visibleStack ) + 1;\n\n\t\t\treturn t( '%0 of %1', [ current, numberOfStacks ] );\n\t\t} );\n\n\t\tview.buttonNextView.on( 'execute', () => {\n\t\t\t// When current view has a focus then move focus to the editable before removing it,\n\t\t\t// otherwise editor will lost focus.\n\t\t\tif ( view.focusTracker.isFocused ) {\n\t\t\t\tthis.editor.editing.view.focus();\n\t\t\t}\n\n\t\t\tthis._showNextStack();\n\t\t} );\n\n\t\tview.buttonPrevView.on( 'execute', () => {\n\t\t\t// When current view has a focus then move focus to the editable before removing it,\n\t\t\t// otherwise editor will lost focus.\n\t\t\tif ( view.focusTracker.isFocused ) {\n\t\t\t\tthis.editor.editing.view.focus();\n\t\t\t}\n\n\t\t\tthis._showPrevStack();\n\t\t} );\n\n\t\treturn view;\n\t}\n\n\t/**\n\t * @private\n\t * @returns {module:ui/view~View}\n\t */\n\t_createFakePanelsView() {\n\t\tconst view = new FakePanelsView( this.editor.locale, this.view );\n\n\t\tview.bind( 'numberOfPanels' ).to( this, '_numberOfStacks', this, '_singleViewMode', ( number, isSingleViewMode ) => {\n\t\t\tconst showPanels = !isSingleViewMode && number >= 2;\n\n\t\t\treturn showPanels ? Math.min( number - 1, 2 ) : 0;\n\t\t} );\n\n\t\tview.listenTo( this.view, 'change:top', () => view.updatePosition() );\n\t\tview.listenTo( this.view, 'change:left', () => view.updatePosition() );\n\n\t\tthis.editor.ui.view.body.add( view );\n\n\t\treturn view;\n\t}\n\n\t/**\n\t * Sets the view as the content of the balloon and attaches the balloon using position\n\t * options of the first view.\n\t *\n\t * @private\n\t * @param {Object} data Configuration.\n\t * @param {module:ui/view~View} [data.view] The view to show in the balloon.\n\t * @param {String} [data.balloonClassName=''] Additional class name which will be added to the {@link #view balloon}.\n\t * @param {Boolean} [data.withArrow=true] Whether the {@link #view balloon} should be rendered with an arrow.\n\t */\n\t_showView( { view, balloonClassName = '', withArrow = true, singleViewMode = false } ) {\n\t\tthis.view.class = balloonClassName;\n\t\tthis.view.withArrow = withArrow;\n\n\t\tthis._rotatorView.showView( view );\n\t\tthis.visibleView = view;\n\t\tthis.view.pin( this._getBalloonPosition() );\n\t\tthis._fakePanelsView.updatePosition();\n\n\t\tif ( singleViewMode ) {\n\t\t\tthis._singleViewMode = true;\n\t\t}\n\t}\n\n\t/**\n\t * Returns position options of the last view in the stack.\n\t * This keeps the balloon in the same position when the view is changed.\n\t *\n\t * @private\n\t * @returns {module:utils/dom/position~Options}\n\t */\n\t_getBalloonPosition() {\n\t\tlet position = Array.from( this._visibleStack.values() ).pop().position;\n\n\t\t// Use the default limiter if none has been specified.\n\t\tif ( position && !position.limiter ) {\n\t\t\t// Don't modify the original options object.\n\t\t\tposition = Object.assign( {}, position, {\n\t\t\t\tlimiter: this.positionLimiter\n\t\t\t} );\n\t\t}\n\n\t\treturn position;\n\t}\n}\n\n/**\n * Rotator view is a helper class for the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon ContextualBalloon}.\n * It is used for displaying the last view from the current stack and providing navigation buttons for switching stacks.\n * See the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon ContextualBalloon} documentation to learn more.\n *\n * @extends module:ui/view~View\n */\nclass RotatorView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst t = locale.t;\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * Defines whether navigation is visible or not.\n\t\t *\n\t\t * @member {Boolean} #isNavigationVisible\n\t\t */\n\t\tthis.set( 'isNavigationVisible', true );\n\n\t\t/**\n\t\t * Used for checking if a view is focused or not.\n\t\t *\n\t\t * @type {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * Navigation button for switching the stack to the previous one.\n\t\t *\n\t\t * @type {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.buttonPrevView = this._createButtonView( t( 'Previous' ), prevIcon );\n\n\t\t/**\n\t\t * Navigation button for switching the stack to the next one.\n\t\t *\n\t\t * @type {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.buttonNextView = this._createButtonView( t( 'Next' ), nextIcon );\n\n\t\t/**\n\t\t * A collection of the child views that creates the rotator content.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.content = this.createCollection();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-balloon-rotator'\n\t\t\t\t],\n\t\t\t\t'z-index': '-1'\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [\n\t\t\t\t\t\t\t'ck-balloon-rotator__navigation',\n\t\t\t\t\t\t\tbind.to( 'isNavigationVisible', value => value ? '' : 'ck-hidden' )\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\tthis.buttonPrevView,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttag: 'span',\n\n\t\t\t\t\t\t\tattributes: {\n\t\t\t\t\t\t\t\tclass: [\n\t\t\t\t\t\t\t\t\t'ck-balloon-rotator__counter'\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t},\n\n\t\t\t\t\t\t\tchildren: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttext: bind.to( 'counter' )\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\tthis.buttonNextView\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttag: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: 'ck-balloon-rotator__content'\n\t\t\t\t\t},\n\t\t\t\t\tchildren: this.content\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.focusTracker.add( this.element );\n\t}\n\n\t/**\n\t * Shows a given view.\n\t *\n\t * @param {module:ui/view~View} view The view to show.\n\t */\n\tshowView( view ) {\n\t\tthis.hideView();\n\t\tthis.content.add( view );\n\t}\n\n\t/**\n\t * Hides the currently displayed view.\n\t */\n\thideView() {\n\t\tthis.content.clear();\n\t}\n\n\t/**\n\t * Creates a navigation button view.\n\t *\n\t * @private\n\t * @param {String} label The button label.\n\t * @param {String} icon The button icon.\n\t * @returns {module:ui/button/buttonview~ButtonView}\n\t */\n\t_createButtonView( label, icon ) {\n\t\tconst view = new ButtonView( this.locale );\n\n\t\tview.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true\n\t\t} );\n\n\t\treturn view;\n\t}\n}\n\n// Displays additional layers under the balloon when multiple stacks are added to the balloon.\n//\n// @private\n// @extends module:ui/view~View\nclass FakePanelsView extends View {\n\t// @inheritDoc\n\tconstructor( locale, balloonPanelView ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t// Fake panels top offset.\n\t\t//\n\t\t// @observable\n\t\t// @member {Number} #top\n\t\tthis.set( 'top', 0 );\n\n\t\t// Fake panels left offset.\n\t\t//\n\t\t// @observable\n\t\t// @member {Number} #left\n\t\tthis.set( 'left', 0 );\n\n\t\t// Fake panels height.\n\t\t//\n\t\t// @observable\n\t\t// @member {Number} #height\n\t\tthis.set( 'height', 0 );\n\n\t\t// Fake panels width.\n\t\t//\n\t\t// @observable\n\t\t// @member {Number} #width\n\t\tthis.set( 'width', 0 );\n\n\t\t// Number of rendered fake panels.\n\t\t//\n\t\t// @observable\n\t\t// @member {Number} #numberOfPanels\n\t\tthis.set( 'numberOfPanels', 0 );\n\n\t\t// Collection of the child views which creates fake panel content.\n\t\t//\n\t\t// @readonly\n\t\t// @type {module:ui/viewcollection~ViewCollection}\n\t\tthis.content = this.createCollection();\n\n\t\t// Context.\n\t\t//\n\t\t// @private\n\t\t// @type {module:ui/panel/balloon/balloonpanelview~BalloonPanelView}\n\t\tthis._balloonPanelView = balloonPanelView;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck-fake-panel',\n\t\t\t\t\tbind.to( 'numberOfPanels', number => number ? '' : 'ck-hidden' )\n\t\t\t\t],\n\t\t\t\tstyle: {\n\t\t\t\t\ttop: bind.to( 'top', toPx ),\n\t\t\t\t\tleft: bind.to( 'left', toPx ),\n\t\t\t\t\twidth: bind.to( 'width', toPx ),\n\t\t\t\t\theight: bind.to( 'height', toPx )\n\t\t\t\t}\n\t\t\t},\n\t\t\tchildren: this.content\n\t\t} );\n\n\t\tthis.on( 'change:numberOfPanels', ( evt, name, next, prev ) => {\n\t\t\tif ( next > prev ) {\n\t\t\t\tthis._addPanels( next - prev );\n\t\t\t} else {\n\t\t\t\tthis._removePanels( prev - next );\n\t\t\t}\n\n\t\t\tthis.updatePosition();\n\t\t} );\n\t}\n\n\t// @private\n\t// @param {Number} number\n\t_addPanels( number ) {\n\t\twhile ( number-- ) {\n\t\t\tconst view = new View();\n\n\t\t\tview.setTemplate( { tag: 'div' } );\n\n\t\t\tthis.content.add( view );\n\t\t\tthis.registerChild( view );\n\t\t}\n\t}\n\n\t// @private\n\t// @param {Number} number\n\t_removePanels( number ) {\n\t\twhile ( number-- ) {\n\t\t\tconst view = this.content.last;\n\n\t\t\tthis.content.remove( view );\n\t\t\tthis.deregisterChild( view );\n\t\t\tview.destroy();\n\t\t}\n\t}\n\n\t// Updates coordinates of fake panels.\n\tupdatePosition() {\n\t\tif ( this.numberOfPanels ) {\n\t\t\tconst { top, left } = this._balloonPanelView;\n\t\t\tconst { width, height } = new Rect( this._balloonPanelView.element );\n\n\t\t\tObject.assign( this, { top, left, width, height } );\n\t\t}\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M11.463 5.187a.888.888 0 1 1 1.254 1.255L9.16 10l3.557 3.557a.888.888 0 1 1-1.254 1.255L7.26 10.61a.888.888 0 0 1 .16-1.382l4.043-4.042z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M8.537 14.813a.888.888 0 1 1-1.254-1.255L10.84 10 7.283 6.442a.888.888 0 1 1 1.254-1.255L12.74 9.39a.888.888 0 0 1-.16 1.382l-4.043 4.042z\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/image/ui/utils\n */\n\nimport BalloonPanelView from '@ckeditor/ckeditor5-ui/src/panel/balloon/balloonpanelview';\nimport { getSelectedImageWidget } from '../utils';\n\n/**\n * A helper utility that positions the\n * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon} instance\n * with respect to the image in the editor content, if one is selected.\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n */\nexport function repositionContextualBalloon( editor ) {\n\tconst balloon = editor.plugins.get( 'ContextualBalloon' );\n\n\tif ( getSelectedImageWidget( editor.editing.view.document.selection ) ) {\n\t\tconst position = getBalloonPositionData( editor );\n\n\t\tballoon.updatePosition( position );\n\t}\n}\n\n/**\n * Returns the positioning options that control the geometry of the\n * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon} with respect\n * to the selected element in the editor content.\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n * @returns {module:utils/dom/position~Options}\n */\nexport function getBalloonPositionData( editor ) {\n\tconst editingView = editor.editing.view;\n\tconst defaultPositions = BalloonPanelView.defaultPositions;\n\n\treturn {\n\t\ttarget: editingView.domConverter.viewToDom( editingView.document.selection.getSelectedElement() ),\n\t\tpositions: [\n\t\t\tdefaultPositions.northArrowSouth,\n\t\t\tdefaultPositions.northArrowSouthWest,\n\t\t\tdefaultPositions.northArrowSouthEast,\n\t\t\tdefaultPositions.southArrowNorth,\n\t\t\tdefaultPositions.southArrowNorthWest,\n\t\t\tdefaultPositions.southArrowNorthEast\n\t\t]\n\t};\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagetextalternative/imagetextalternativeui\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport clickOutsideHandler from '@ckeditor/ckeditor5-ui/src/bindings/clickoutsidehandler';\nimport TextAlternativeFormView from './ui/textalternativeformview';\nimport ContextualBalloon from '@ckeditor/ckeditor5-ui/src/panel/balloon/contextualballoon';\nimport textAlternativeIcon from '@ckeditor/ckeditor5-core/theme/icons/low-vision.svg';\nimport { repositionContextualBalloon, getBalloonPositionData } from '../image/ui/utils';\nimport { getSelectedImageWidget } from '../image/utils';\n\n/**\n * The image text alternative UI plugin.\n *\n * The plugin uses the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageTextAlternativeUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ContextualBalloon ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageTextAlternativeUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tthis._createButton();\n\t\tthis._createForm();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\t// Destroy created UI components as they are not automatically destroyed (see ckeditor5#1341).\n\t\tthis._form.destroy();\n\t}\n\n\t/**\n\t * Creates a button showing the balloon panel for changing the image text alternative and\n\t * registers it in the editor {@link module:ui/componentfactory~ComponentFactory ComponentFactory}.\n\t *\n\t * @private\n\t */\n\t_createButton() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\teditor.ui.componentFactory.add( 'imageTextAlternative', locale => {\n\t\t\tconst command = editor.commands.get( 'imageTextAlternative' );\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: t( 'Change image text alternative' ),\n\t\t\t\ticon: textAlternativeIcon,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isEnabled' ).to( command, 'isEnabled' );\n\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\tthis._showForm();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n\n\t/**\n\t * Creates the {@link module:image/imagetextalternative/ui/textalternativeformview~TextAlternativeFormView}\n\t * form.\n\t *\n\t * @private\n\t */\n\t_createForm() {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\t/**\n\t\t * The contextual balloon plugin instance.\n\t\t *\n\t\t * @private\n\t\t * @member {module:ui/panel/balloon/contextualballoon~ContextualBalloon}\n\t\t */\n\t\tthis._balloon = this.editor.plugins.get( 'ContextualBalloon' );\n\n\t\t/**\n\t\t * A form containing a textarea and buttons, used to change the `alt` text value.\n\t\t *\n\t\t * @member {module:image/imagetextalternative/ui/textalternativeformview~TextAlternativeFormView}\n\t\t */\n\t\tthis._form = new TextAlternativeFormView( editor.locale );\n\n\t\t// Render the form so its #element is available for clickOutsideHandler.\n\t\tthis._form.render();\n\n\t\tthis.listenTo( this._form, 'submit', () => {\n\t\t\teditor.execute( 'imageTextAlternative', {\n\t\t\t\tnewValue: this._form.labeledInput.fieldView.element.value\n\t\t\t} );\n\n\t\t\tthis._hideForm( true );\n\t\t} );\n\n\t\tthis.listenTo( this._form, 'cancel', () => {\n\t\t\tthis._hideForm( true );\n\t\t} );\n\n\t\t// Close the form on Esc key press.\n\t\tthis._form.keystrokes.set( 'Esc', ( data, cancel ) => {\n\t\t\tthis._hideForm( true );\n\t\t\tcancel();\n\t\t} );\n\n\t\t// Reposition the balloon or hide the form if an image widget is no longer selected.\n\t\tthis.listenTo( editor.ui, 'update', () => {\n\t\t\tif ( !getSelectedImageWidget( viewDocument.selection ) ) {\n\t\t\t\tthis._hideForm( true );\n\t\t\t} else if ( this._isVisible ) {\n\t\t\t\trepositionContextualBalloon( editor );\n\t\t\t}\n\t\t} );\n\n\t\t// Close on click outside of balloon panel element.\n\t\tclickOutsideHandler( {\n\t\t\temitter: this._form,\n\t\t\tactivator: () => this._isVisible,\n\t\t\tcontextElements: [ this._balloon.view.element ],\n\t\t\tcallback: () => this._hideForm()\n\t\t} );\n\t}\n\n\t/**\n\t * Shows the {@link #_form} in the {@link #_balloon}.\n\t *\n\t * @private\n\t */\n\t_showForm() {\n\t\tif ( this._isVisible ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst editor = this.editor;\n\t\tconst command = editor.commands.get( 'imageTextAlternative' );\n\t\tconst labeledInput = this._form.labeledInput;\n\n\t\tthis._form.disableCssTransitions();\n\n\t\tif ( !this._isInBalloon ) {\n\t\t\tthis._balloon.add( {\n\t\t\t\tview: this._form,\n\t\t\t\tposition: getBalloonPositionData( editor )\n\t\t\t} );\n\t\t}\n\n\t\t// Make sure that each time the panel shows up, the field remains in sync with the value of\n\t\t// the command. If the user typed in the input, then canceled the balloon (`labeledInput#value`\n\t\t// stays unaltered) and re-opened it without changing the value of the command, they would see the\n\t\t// old value instead of the actual value of the command.\n\t\t// https://github.com/ckeditor/ckeditor5-image/issues/114\n\t\tlabeledInput.fieldView.value = labeledInput.fieldView.element.value = command.value || '';\n\n\t\tthis._form.labeledInput.fieldView.select();\n\n\t\tthis._form.enableCssTransitions();\n\t}\n\n\t/**\n\t * Removes the {@link #_form} from the {@link #_balloon}.\n\t *\n\t * @param {Boolean} [focusEditable=false] Controls whether the editing view is focused afterwards.\n\t * @private\n\t */\n\t_hideForm( focusEditable ) {\n\t\tif ( !this._isInBalloon ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Blur the input element before removing it from DOM to prevent issues in some browsers.\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/1501.\n\t\tif ( this._form.focusTracker.isFocused ) {\n\t\t\tthis._form.saveButtonView.focus();\n\t\t}\n\n\t\tthis._balloon.remove( this._form );\n\n\t\tif ( focusEditable ) {\n\t\t\tthis.editor.editing.view.focus();\n\t\t}\n\t}\n\n\t/**\n\t * Returns `true` when the {@link #_form} is the visible view in the {@link #_balloon}.\n\t *\n\t * @private\n\t * @type {Boolean}\n\t */\n\tget _isVisible() {\n\t\treturn this._balloon.visibleView === this._form;\n\t}\n\n\t/**\n\t * Returns `true` when the {@link #_form} is in the {@link #_balloon}.\n\t *\n\t * @private\n\t * @type {Boolean}\n\t */\n\tget _isInBalloon() {\n\t\treturn this._balloon.hasView( this._form );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M5.085 6.22L2.943 4.078a.75.75 0 1 1 1.06-1.06l2.592 2.59A11.094 11.094 0 0 1 10 5.068c4.738 0 8.578 3.101 8.578 5.083 0 1.197-1.401 2.803-3.555 3.887l1.714 1.713a.75.75 0 0 1-.09 1.138.488.488 0 0 1-.15.084.75.75 0 0 1-.821-.16L6.17 7.304c-.258.11-.51.233-.757.365l6.239 6.24-.006.005.78.78c-.388.094-.78.166-1.174.215l-1.11-1.11h.011L4.55 8.197a7.2 7.2 0 0 0-.665.514l-.112.098 4.897 4.897-.005.006 1.276 1.276a10.164 10.164 0 0 1-1.477-.117l-.479-.479-.009.009-4.863-4.863-.022.031a2.563 2.563 0 0 0-.124.2c-.043.077-.08.158-.108.241a.534.534 0 0 0-.028.133.29.29 0 0 0 .008.072.927.927 0 0 0 .082.226c.067.133.145.26.234.379l3.242 3.365.025.01.59.623c-3.265-.918-5.59-3.155-5.59-4.668 0-1.194 1.448-2.838 3.663-3.93zm7.07.531a4.632 4.632 0 0 1 1.108 5.992l.345.344.046-.018a9.313 9.313 0 0 0 2-1.112c.256-.187.5-.392.727-.613.137-.134.27-.277.392-.431.072-.091.141-.185.203-.286.057-.093.107-.19.148-.292a.72.72 0 0 0 .036-.12.29.29 0 0 0 .008-.072.492.492 0 0 0-.028-.133.999.999 0 0 0-.036-.096 2.165 2.165 0 0 0-.071-.145 2.917 2.917 0 0 0-.125-.2 3.592 3.592 0 0 0-.263-.335 5.444 5.444 0 0 0-.53-.523 7.955 7.955 0 0 0-1.054-.768 9.766 9.766 0 0 0-1.879-.891c-.337-.118-.68-.219-1.027-.301zm-2.85.21l-.069.002a.508.508 0 0 0-.254.097.496.496 0 0 0-.104.679.498.498 0 0 0 .326.199l.045.005c.091.003.181.003.272.012a2.45 2.45 0 0 1 2.017 1.513c.024.061.043.125.069.185a.494.494 0 0 0 .45.287h.008a.496.496 0 0 0 .35-.158.482.482 0 0 0 .13-.335.638.638 0 0 0-.048-.219 3.379 3.379 0 0 0-.36-.723 3.438 3.438 0 0 0-2.791-1.543l-.028-.001h-.013z\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagetextalternative\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ImageTextAlternativeEditing from './imagetextalternative/imagetextalternativeediting';\nimport ImageTextAlternativeUI from './imagetextalternative/imagetextalternativeui';\n\n/**\n * The image text alternative plugin.\n *\n * For a detailed overview, check the {@glink features/image#image-styles image styles} documentation.\n *\n * This is a \"glue\" plugin which loads the\n *  {@link module:image/imagetextalternative/imagetextalternativeediting~ImageTextAlternativeEditing}\n * and {@link module:image/imagetextalternative/imagetextalternativeui~ImageTextAlternativeUI} plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageTextAlternative extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ImageTextAlternativeEditing, ImageTextAlternativeUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageTextAlternative';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/image\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ImageEditing from '../src/image/imageediting';\nimport Widget from '@ckeditor/ckeditor5-widget/src/widget';\nimport ImageTextAlternative from './imagetextalternative';\n\nimport '../theme/image.css';\n\n/**\n * The image plugin.\n *\n * For a detailed overview, check the {@glink features/image image feature} documentation.\n *\n * This is a \"glue\" plugin which loads the following plugins:\n *\n * * {@link module:image/image/imageediting~ImageEditing},\n * * {@link module:image/imagetextalternative~ImageTextAlternative}.\n *\n * Usually, it is used in conjuction with other plugins from this package. See the {@glink api/image package page}\n * for more information.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Image extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ImageEditing, Widget, ImageTextAlternative ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Image';\n\t}\n}\n\n/**\n * The configuration of the image features. Used by the image features in the `@ckeditor/ckeditor5-image` package.\n *\n * Read more in {@link module:image/image~ImageConfig}.\n *\n * @member {module:image/image~ImageConfig} module:core/editor/editorconfig~EditorConfig#image\n */\n\n/**\n * The configuration of the image features. Used by the image features in the `@ckeditor/ckeditor5-image` package.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\timage: ... // Image feature options.\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface ImageConfig\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module upload/ui/filedialogbuttonview\n */\n\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport View from '@ckeditor/ckeditor5-ui/src/view';\n\n/**\n * The file dialog button view.\n *\n * This component provides a button that opens the native file selection dialog.\n * It can be used to implement the UI of a file upload feature.\n *\n *\t\tconst view = new FileDialogButtonView( locale );\n *\n *\t\tview.set( {\n *\t\t\tacceptedType: 'image/*',\n *\t\t\tallowMultipleFiles: true\n *\t\t} );\n *\n *\t\tview.buttonView.set( {\n *\t\t\tlabel: t( 'Insert image' ),\n *\t\t\ticon: imageIcon,\n *\t\t\ttooltip: true\n *\t\t} );\n *\n *\t\tview.on( 'done', ( evt, files ) => {\n *\t\t\tfor ( const file of Array.from( files ) ) {\n *\t\t\t\tconsole.log( 'Selected file', file );\n *\t\t\t}\n *\t\t} );\n *\n * @extends module:ui/view~View\n */\nexport default class FileDialogButtonView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * The button view of the component.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.buttonView = new ButtonView( locale );\n\n\t\t/**\n\t\t * A hidden `<input>` view used to execute file dialog.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:upload/ui/filedialogbuttonview~FileInputView}\n\t\t */\n\t\tthis._fileInputView = new FileInputView( locale );\n\n\t\t/**\n\t\t * Accepted file types. Can be provided in form of file extensions, media type or one of:\n\t\t * * `audio/*`,\n\t\t * * `video/*`,\n\t\t * * `image/*`.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #acceptedType\n\t\t */\n\t\tthis._fileInputView.bind( 'acceptedType' ).to( this );\n\n\t\t/**\n\t\t * Indicates if multiple files can be selected. Defaults to `true`.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #allowMultipleFiles\n\t\t */\n\t\tthis._fileInputView.bind( 'allowMultipleFiles' ).to( this );\n\n\t\t/**\n\t\t * Fired when file dialog is closed with file selected.\n\t\t *\n\t\t *\t\tview.on( 'done', ( evt, files ) => {\n\t\t *\t\t\tfor ( const file of files ) {\n\t\t *\t\t\t\tconsole.log( 'Selected file', file );\n\t\t *\t\t\t}\n\t\t *\t\t}\n\t\t *\n\t\t * @event done\n\t\t * @param {Array.<File>} files Array of selected files.\n\t\t */\n\t\tthis._fileInputView.delegate( 'done' ).to( this );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'span',\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-file-dialog-button'\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\tthis.buttonView,\n\t\t\t\tthis._fileInputView\n\t\t\t]\n\t\t} );\n\n\t\tthis.buttonView.on( 'execute', () => {\n\t\t\tthis._fileInputView.open();\n\t\t} );\n\t}\n\n\t/**\n\t * Focuses the {@link #buttonView}.\n\t */\n\tfocus() {\n\t\tthis.buttonView.focus();\n\t}\n}\n\n/**\n * The hidden file input view class.\n *\n * @private\n * @extends module:ui/view~View\n */\nclass FileInputView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * Accepted file types. Can be provided in form of file extensions, media type or one of:\n\t\t * * `audio/*`,\n\t\t * * `video/*`,\n\t\t * * `image/*`.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #acceptedType\n\t\t */\n\t\tthis.set( 'acceptedType' );\n\n\t\t/**\n\t\t * Indicates if multiple files can be selected. Defaults to `false`.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #allowMultipleFiles\n\t\t */\n\t\tthis.set( 'allowMultipleFiles', false );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'input',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck-hidden'\n\t\t\t\t],\n\t\t\t\ttype: 'file',\n\t\t\t\ttabindex: '-1',\n\t\t\t\taccept: bind.to( 'acceptedType' ),\n\t\t\t\tmultiple: bind.to( 'allowMultipleFiles' )\n\t\t\t},\n\n\t\t\ton: {\n\t\t\t\t// Removing from code coverage since we cannot programmatically set input element files.\n\t\t\t\tchange: bind.to( /* istanbul ignore next */ () => {\n\t\t\t\t\tif ( this.element && this.element.files && this.element.files.length ) {\n\t\t\t\t\t\tthis.fire( 'done', this.element.files );\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.element.value = '';\n\t\t\t\t} )\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Opens file dialog.\n\t */\n\topen() {\n\t\tthis.element.click();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imageupload/utils\n */\n\n/* global fetch, File */\n\n/**\n * Creates a regular expression used to test for image files.\n *\n *\t\tconst imageType = createImageTypeRegExp( [ 'png', 'jpeg', 'svg+xml', 'vnd.microsoft.icon' ] );\n *\n *\t\tconsole.log( 'is supported image', imageType.test( file.type ) );\n *\n * @param {Array.<String>} types\n * @returns {RegExp}\n */\nexport function createImageTypeRegExp( types ) {\n\t// Sanitize the MIME type name which may include: \"+\", \"-\" or \".\".\n\tconst regExpSafeNames = types.map( type => type.replace( '+', '\\\\+' ) );\n\n\treturn new RegExp( `^image\\\\/(${ regExpSafeNames.join( '|' ) })$` );\n}\n\n/**\n * Creates a promise that fetches the image local source (Base64 or blob) and resolves with a `File` object.\n *\n * @param {module:engine/view/element~Element} image Image whose source to fetch.\n * @returns {Promise.<File>} A promise which resolves when an image source is fetched and converted to a `File` instance.\n * It resolves with a `File` object. If there were any errors during file processing, the promise will be rejected.\n */\nexport function fetchLocalImage( image ) {\n\treturn new Promise( ( resolve, reject ) => {\n\t\tconst imageSrc = image.getAttribute( 'src' );\n\n\t\t// Fetch works asynchronously and so does not block browser UI when processing data.\n\t\tfetch( imageSrc )\n\t\t\t.then( resource => resource.blob() )\n\t\t\t.then( blob => {\n\t\t\t\tconst mimeType = getImageMimeType( blob, imageSrc );\n\t\t\t\tconst ext = mimeType.replace( 'image/', '' );\n\t\t\t\tconst filename = `image.${ ext }`;\n\t\t\t\tconst file = new File( [ blob ], filename, { type: mimeType } );\n\n\t\t\t\tresolve( file );\n\t\t\t} )\n\t\t\t.catch( reject );\n\t} );\n}\n\n/**\n * Checks whether a given node is an image element with a local source (Base64 or blob).\n *\n * @param {module:engine/view/node~Node} node The node to check.\n * @returns {Boolean}\n */\nexport function isLocalImage( node ) {\n\tif ( !node.is( 'element', 'img' ) || !node.getAttribute( 'src' ) ) {\n\t\treturn false;\n\t}\n\n\treturn node.getAttribute( 'src' ).match( /^data:image\\/\\w+;base64,/g ) ||\n\t\tnode.getAttribute( 'src' ).match( /^blob:/g );\n}\n\n// Extracts an image type based on its blob representation or its source.\n//\n// @param {String} src Image `src` attribute value.\n// @param {Blob} blob Image blob representation.\n// @returns {String}\nfunction getImageMimeType( blob, src ) {\n\tif ( blob.type ) {\n\t\treturn blob.type;\n\t} else if ( src.match( /data:(image\\/\\w+);base64/ ) ) {\n\t\treturn src.match( /data:(image\\/\\w+);base64/ )[ 1 ].toLowerCase();\n\t} else {\n\t\t// Fallback to 'jpeg' as common extension.\n\t\treturn 'image/jpeg';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imageupload/imageuploadui\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport FileDialogButtonView from '@ckeditor/ckeditor5-upload/src/ui/filedialogbuttonview';\nimport { createImageTypeRegExp } from './utils';\n\nimport imageIcon from '@ckeditor/ckeditor5-core/theme/icons/image.svg';\n\n/**\n * The image upload button plugin.\n *\n * For a detailed overview, check the {@glink features/image-upload/image-upload Image upload feature} documentation.\n *\n * Adds the `'imageUpload'` button to the {@link module:ui/componentfactory~ComponentFactory UI component factory}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageUploadUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageUploadUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\t// Setup `imageUpload` button.\n\t\teditor.ui.componentFactory.add( 'imageUpload', locale => {\n\t\t\tconst view = new FileDialogButtonView( locale );\n\t\t\tconst command = editor.commands.get( 'imageUpload' );\n\t\t\tconst imageTypes = editor.config.get( 'image.upload.types' );\n\t\t\tconst imageTypesRegExp = createImageTypeRegExp( imageTypes );\n\n\t\t\tview.set( {\n\t\t\t\tacceptedType: imageTypes.map( type => `image/${ type }` ).join( ',' ),\n\t\t\t\tallowMultipleFiles: true\n\t\t\t} );\n\n\t\t\tview.buttonView.set( {\n\t\t\t\tlabel: t( 'Insert image' ),\n\t\t\t\ticon: imageIcon,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tview.buttonView.bind( 'isEnabled' ).to( command );\n\n\t\t\tview.on( 'done', ( evt, files ) => {\n\t\t\t\tconst imagesToUpload = Array.from( files ).filter( file => imageTypesRegExp.test( file.type ) );\n\n\t\t\t\tif ( imagesToUpload.length ) {\n\t\t\t\t\teditor.execute( 'imageUpload', { file: imagesToUpload } );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M6.91 10.54c.26-.23.64-.21.88.03l3.36 3.14 2.23-2.06a.64.64 0 0 1 .87 0l2.52 2.97V4.5H3.2v10.12l3.71-4.08zm10.27-7.51c.6 0 1.09.47 1.09 1.05v11.84c0 .59-.49 1.06-1.09 1.06H2.79c-.6 0-1.09-.47-1.09-1.06V4.08c0-.58.49-1.05 1.1-1.05h14.38zm-5.22 5.56a1.96 1.96 0 1 1 3.4-1.96 1.96 1.96 0 0 1-3.4 1.96z\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imageupload/imageuploadprogress\n */\n\n/* globals setTimeout */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport FileRepository from '@ckeditor/ckeditor5-upload/src/filerepository';\nimport uploadingPlaceholder from '../../theme/icons/image_placeholder.svg';\nimport { getViewImgFromWidget } from '../image/utils';\n\nimport '../../theme/imageuploadprogress.css';\nimport '../../theme/imageuploadicon.css';\nimport '../../theme/imageuploadloader.css';\n\n/**\n * The image upload progress plugin.\n * It shows a placeholder when the image is read from the disk and a progress bar while the image is uploading.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageUploadProgress extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The image placeholder that is displayed before real image data can be accessed.\n\t\t *\n\t\t * @protected\n\t\t * @member {String} #placeholder\n\t\t */\n\t\tthis.placeholder = 'data:image/svg+xml;utf8,' + encodeURIComponent( uploadingPlaceholder );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Upload status change - update image's view according to that status.\n\t\teditor.editing.downcastDispatcher.on( 'attribute:uploadStatus:image', ( ...args ) => this.uploadStatusChange( ...args ) );\n\t}\n\n\t/**\n\t * This method is called each time the image `uploadStatus` attribute is changed.\n\t *\n\t * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n\t */\n\tuploadStatusChange( evt, data, conversionApi ) {\n\t\tconst editor = this.editor;\n\t\tconst modelImage = data.item;\n\t\tconst uploadId = modelImage.getAttribute( 'uploadId' );\n\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst fileRepository = editor.plugins.get( FileRepository );\n\t\tconst status = uploadId ? data.attributeNewValue : null;\n\t\tconst placeholder = this.placeholder;\n\t\tconst viewFigure = editor.editing.mapper.toViewElement( modelImage );\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\tif ( status == 'reading' ) {\n\t\t\t// Start \"appearing\" effect and show placeholder with infinite progress bar on the top\n\t\t\t// while image is read from disk.\n\t\t\t_startAppearEffect( viewFigure, viewWriter );\n\t\t\t_showPlaceholder( placeholder, viewFigure, viewWriter );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Show progress bar on the top of the image when image is uploading.\n\t\tif ( status == 'uploading' ) {\n\t\t\tconst loader = fileRepository.loaders.get( uploadId );\n\n\t\t\t// Start appear effect if needed - see https://github.com/ckeditor/ckeditor5-image/issues/191.\n\t\t\t_startAppearEffect( viewFigure, viewWriter );\n\n\t\t\tif ( !loader ) {\n\t\t\t\t// There is no loader associated with uploadId - this means that image came from external changes.\n\t\t\t\t// In such cases we still want to show the placeholder until image is fully uploaded.\n\t\t\t\t// Show placeholder if needed - see https://github.com/ckeditor/ckeditor5-image/issues/191.\n\t\t\t\t_showPlaceholder( placeholder, viewFigure, viewWriter );\n\t\t\t} else {\n\t\t\t\t// Hide placeholder and initialize progress bar showing upload progress.\n\t\t\t\t_hidePlaceholder( viewFigure, viewWriter );\n\t\t\t\t_showProgressBar( viewFigure, viewWriter, loader, editor.editing.view );\n\t\t\t\t_displayLocalImage( viewFigure, viewWriter, loader );\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tif ( status == 'complete' && fileRepository.loaders.get( uploadId ) ) {\n\t\t\t_showCompleteIcon( viewFigure, viewWriter, editor.editing.view );\n\t\t}\n\n\t\t// Clean up.\n\t\t_hideProgressBar( viewFigure, viewWriter );\n\t\t_hidePlaceholder( viewFigure, viewWriter );\n\t\t_stopAppearEffect( viewFigure, viewWriter );\n\t}\n}\n\n// Adds ck-appear class to the image figure if one is not already applied.\n//\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\nfunction _startAppearEffect( viewFigure, writer ) {\n\tif ( !viewFigure.hasClass( 'ck-appear' ) ) {\n\t\twriter.addClass( 'ck-appear', viewFigure );\n\t}\n}\n\n// Removes ck-appear class to the image figure if one is not already removed.\n//\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\nfunction _stopAppearEffect( viewFigure, writer ) {\n\twriter.removeClass( 'ck-appear', viewFigure );\n}\n\n// Shows placeholder together with infinite progress bar on given image figure.\n//\n// @param {String} Data-uri with a svg placeholder.\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\nfunction _showPlaceholder( placeholder, viewFigure, writer ) {\n\tif ( !viewFigure.hasClass( 'ck-image-upload-placeholder' ) ) {\n\t\twriter.addClass( 'ck-image-upload-placeholder', viewFigure );\n\t}\n\n\tconst viewImg = getViewImgFromWidget( viewFigure );\n\n\tif ( viewImg.getAttribute( 'src' ) !== placeholder ) {\n\t\twriter.setAttribute( 'src', placeholder, viewImg );\n\t}\n\n\tif ( !_getUIElement( viewFigure, 'placeholder' ) ) {\n\t\twriter.insert( writer.createPositionAfter( viewImg ), _createPlaceholder( writer ) );\n\t}\n}\n\n// Removes placeholder together with infinite progress bar on given image figure.\n//\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\nfunction _hidePlaceholder( viewFigure, writer ) {\n\tif ( viewFigure.hasClass( 'ck-image-upload-placeholder' ) ) {\n\t\twriter.removeClass( 'ck-image-upload-placeholder', viewFigure );\n\t}\n\n\t_removeUIElement( viewFigure, writer, 'placeholder' );\n}\n\n// Shows progress bar displaying upload progress.\n// Attaches it to the file loader to update when upload percentace is changed.\n//\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @param {module:upload/filerepository~FileLoader} loader\n// @param {module:engine/view/view~View} view\nfunction _showProgressBar( viewFigure, writer, loader, view ) {\n\tconst progressBar = _createProgressBar( writer );\n\twriter.insert( writer.createPositionAt( viewFigure, 'end' ), progressBar );\n\n\t// Update progress bar width when uploadedPercent is changed.\n\tloader.on( 'change:uploadedPercent', ( evt, name, value ) => {\n\t\tview.change( writer => {\n\t\t\twriter.setStyle( 'width', value + '%', progressBar );\n\t\t} );\n\t} );\n}\n\n// Hides upload progress bar.\n//\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\nfunction _hideProgressBar( viewFigure, writer ) {\n\t_removeUIElement( viewFigure, writer, 'progressBar' );\n}\n\n// Shows complete icon and hides after a certain amount of time.\n//\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @param {module:engine/view/view~View} view\nfunction _showCompleteIcon( viewFigure, writer, view ) {\n\tconst completeIcon = writer.createUIElement( 'div', { class: 'ck-image-upload-complete-icon' } );\n\n\twriter.insert( writer.createPositionAt( viewFigure, 'end' ), completeIcon );\n\n\tsetTimeout( () => {\n\t\tview.change( writer => writer.remove( writer.createRangeOn( completeIcon ) ) );\n\t}, 3000 );\n}\n\n// Create progress bar element using {@link module:engine/view/uielement~UIElement}.\n//\n// @private\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @returns {module:engine/view/uielement~UIElement}\nfunction _createProgressBar( writer ) {\n\tconst progressBar = writer.createUIElement( 'div', { class: 'ck-progress-bar' } );\n\n\twriter.setCustomProperty( 'progressBar', true, progressBar );\n\n\treturn progressBar;\n}\n\n// Create placeholder element using {@link module:engine/view/uielement~UIElement}.\n//\n// @private\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @returns {module:engine/view/uielement~UIElement}\nfunction _createPlaceholder( writer ) {\n\tconst placeholder = writer.createUIElement( 'div', { class: 'ck-upload-placeholder-loader' } );\n\n\twriter.setCustomProperty( 'placeholder', true, placeholder );\n\n\treturn placeholder;\n}\n\n// Returns {@link module:engine/view/uielement~UIElement} of given unique property from image figure element.\n// Returns `undefined` if element is not found.\n//\n// @private\n// @param {module:engine/view/element~Element} imageFigure\n// @param {String} uniqueProperty\n// @returns {module:engine/view/uielement~UIElement|undefined}\nfunction _getUIElement( imageFigure, uniqueProperty ) {\n\tfor ( const child of imageFigure.getChildren() ) {\n\t\tif ( child.getCustomProperty( uniqueProperty ) ) {\n\t\t\treturn child;\n\t\t}\n\t}\n}\n\n// Removes {@link module:engine/view/uielement~UIElement} of given unique property from image figure element.\n//\n// @private\n// @param {module:engine/view/element~Element} imageFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @param {String} uniqueProperty\nfunction _removeUIElement( viewFigure, writer, uniqueProperty ) {\n\tconst element = _getUIElement( viewFigure, uniqueProperty );\n\n\tif ( element ) {\n\t\twriter.remove( writer.createRangeOn( element ) );\n\t}\n}\n\n// Displays local data from file loader.\n//\n// @param {module:engine/view/element~Element} imageFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @param {module:upload/filerepository~FileLoader} loader\nfunction _displayLocalImage( viewFigure, writer, loader ) {\n\tif ( loader.data ) {\n\t\tconst viewImg = getViewImgFromWidget( viewFigure );\n\n\t\twriter.setAttribute( 'src', loader.data, viewImg );\n\t}\n}\n","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" viewBox=\\\"0 0 700 250\\\"><rect rx=\\\"4\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module module:engine/view/upcastwriter\n */\n\nimport DocumentFragment from './documentfragment';\nimport Element from './element';\nimport Text from './text';\nimport { isPlainObject } from 'lodash-es';\nimport Position from './position';\nimport Range from './range';\nimport Selection from './selection';\n\n/**\n * View upcast writer. It provides a set of methods used to manipulate non-semantic view trees.\n *\n * It should be used only while working on a non-semantic view\n * (e.g. a view created from HTML string on paste).\n * To manipulate a view which was or is being downcasted from the the model use the\n * {@link module:engine/view/downcastwriter~DowncastWriter downcast writer}.\n *\n * Read more about changing the view in the {@glink framework/guides/architecture/editing-engine#changing-the-view Changing the view}\n * section of the {@glink framework/guides/architecture/editing-engine Editing engine architecture} guide.\n *\n * Unlike `DowncastWriter`, which is available in the {@link module:engine/view/view~View#change `View#change()`} block,\n * `UpcastWriter` can be created wherever you need it:\n *\n *\t\tconst writer = new UpcastWriter( viewDocument );\n *\t\tconst text = writer.createText( 'foo!' );\n *\n *\t\twriter.appendChild( text, someViewElement );\n */\nexport default class UpcastWriter {\n\t/**\n\t * @param {module:engine/view/document~Document} document The view document instance in which this upcast writer operates.\n\t */\n\tconstructor( document ) {\n\t\t/**\n\t\t * The view document instance in which this upcast writer operates.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = document;\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/documentfragment~DocumentFragment} instance.\n\t *\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into the created document fragment.\n\t * @returns {module:engine/view/documentfragment~DocumentFragment} The created document fragment.\n\t */\n\tcreateDocumentFragment( children ) {\n\t\treturn new DocumentFragment( this.document, children );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/element~Element} instance.\n\t *\n\t * Attributes can be passed in various formats:\n\t *\n\t *\t\tupcastWriter.createElement( 'div', { class: 'editor', contentEditable: 'true' } ); // object\n\t *\t\tupcastWriter.createElement( 'div', [ [ 'class', 'editor' ], [ 'contentEditable', 'true' ] ] ); // map-like iterator\n\t *\t\tupcastWriter.createElement( 'div', mapOfAttributes ); // map\n\t *\n\t * @param {String} name Node name.\n\t * @param {Object|Iterable} [attrs] Collection of attributes.\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into created element.\n\t * @returns {module:engine/view/element~Element} Created element.\n\t */\n\tcreateElement( name, attrs, children ) {\n\t\treturn new Element( this.document, name, attrs, children );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/text~Text} instance.\n\t *\n\t * @param {String} data The text's data.\n\t * @returns {module:engine/view/text~Text} The created text node.\n\t */\n\tcreateText( data ) {\n\t\treturn new Text( this.document, data );\n\t}\n\n\t/**\n\t * Clones the provided element.\n\t *\n\t * @see module:engine/view/element~Element#_clone\n\t * @param {module:engine/view/element~Element} element Element to be cloned.\n\t * @param {Boolean} [deep=false] If set to `true` clones element and all its children recursively. When set to `false`,\n\t * element will be cloned without any children.\n\t * @returns {module:engine/view/element~Element} Clone of this element.\n\t */\n\tclone( element, deep = false ) {\n\t\treturn element._clone( deep );\n\t}\n\n\t/**\n\t * Appends a child node or a list of child nodes at the end of this node\n\t * and sets the parent of these nodes to this element.\n\t *\n\t * @see module:engine/view/element~Element#_appendChild\n\t * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} element Element\n\t * to which items will be appended.\n\t * @fires module:engine/view/node~Node#event:change\n\t * @returns {Number} Number of appended nodes.\n\t */\n\tappendChild( items, element ) {\n\t\treturn element._appendChild( items );\n\t}\n\n\t/**\n\t * Inserts a child node or a list of child nodes on the given index and sets the parent of these nodes to\n\t * this element.\n\t *\n\t * @see module:engine/view/element~Element#_insertChild\n\t * @param {Number} index Offset at which nodes should be inserted.\n\t * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} element Element\n\t * to which items will be inserted.\n\t * @fires module:engine/view/node~Node#event:change\n\t * @returns {Number} Number of inserted nodes.\n\t */\n\tinsertChild( index, items, element ) {\n\t\treturn element._insertChild( index, items );\n\t}\n\n\t/**\n\t * Removes the given number of child nodes starting at the given index and set the parent of these nodes to `null`.\n\t *\n\t * @see module:engine/view/element~Element#_removeChildren\n\t * @param {Number} index Offset from which nodes will be removed.\n\t * @param {Number} howMany Number of nodes to remove.\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} element Element\n\t * which children will be removed.\n\t * @fires module:engine/view/node~Node#event:change\n\t * @returns {Array.<module:engine/view/node~Node>} The array containing removed nodes.\n\t */\n\tremoveChildren( index, howMany, element ) {\n\t\treturn element._removeChildren( index, howMany );\n\t}\n\n\t/**\n\t * Removes given element from the view structure. Will not have effect on detached elements.\n\t *\n\t * @param {module:engine/view/element~Element} element Element which will be removed.\n\t * @returns {Array.<module:engine/view/node~Node>} The array containing removed nodes.\n\t */\n\tremove( element ) {\n\t\tconst parent = element.parent;\n\n\t\tif ( parent ) {\n\t\t\treturn this.removeChildren( parent.getChildIndex( element ), 1, parent );\n\t\t}\n\n\t\treturn [];\n\t}\n\n\t/**\n\t * Replaces given element with the new one in the view structure. Will not have effect on detached elements.\n\t *\n\t * @param {module:engine/view/element~Element} oldElement Element which will be replaced.\n\t * @param {module:engine/view/element~Element} newElement Element which will be inserted in the place of the old element.\n\t * @returns {Boolean} Whether old element was successfully replaced.\n\t */\n\treplace( oldElement, newElement ) {\n\t\tconst parent = oldElement.parent;\n\n\t\tif ( parent ) {\n\t\t\tconst index = parent.getChildIndex( oldElement );\n\n\t\t\tthis.removeChildren( index, 1, parent );\n\t\t\tthis.insertChild( index, newElement, parent );\n\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Removes given element from view structure and places its children in its position.\n\t * It does nothing if element has no parent.\n\t *\n\t * @param {module:engine/view/element~Element} element Element to unwrap.\n\t */\n\tunwrapElement( element ) {\n\t\tconst parent = element.parent;\n\n\t\tif ( parent ) {\n\t\t\tconst index = parent.getChildIndex( element );\n\n\t\t\tthis.remove( element );\n\t\t\tthis.insertChild( index, element.getChildren(), parent );\n\t\t}\n\t}\n\n\t/**\n\t * Renames element by creating a copy of a given element but with its name changed and then moving contents of the\n\t * old element to the new one.\n\t *\n\t * Since this function creates a new element and removes the given one, the new element is returned to keep reference.\n\t *\n\t * @param {String} newName New element name.\n\t * @param {module:engine/view/element~Element} element Element to be renamed.\n\t * @returns {module:engine/view/element~Element|null} New element or null if the old element\n\t * was not replaced (happens for detached elements).\n\t */\n\trename( newName, element ) {\n\t\tconst newElement = new Element( this.document, newName, element.getAttributes(), element.getChildren() );\n\n\t\treturn this.replace( element, newElement ) ? newElement : null;\n\t}\n\n\t/**\n\t * Adds or overwrites element's attribute with a specified key and value.\n\t *\n\t *\t\twriter.setAttribute( linkElement, 'href', 'http://ckeditor.com' );\n\t *\n\t * @see module:engine/view/element~Element#_setAttribute\n\t * @param {String} key Attribute key.\n\t * @param {String} value Attribute value.\n\t * @param {module:engine/view/element~Element} element Element for which attribute will be set.\n\t */\n\tsetAttribute( key, value, element ) {\n\t\telement._setAttribute( key, value );\n\t}\n\n\t/**\n\t * Removes attribute from the element.\n\t *\n\t *\t\twriter.removeAttribute( linkElement, 'href' );\n\t *\n\t * @see module:engine/view/element~Element#_removeAttribute\n\t * @param {String} key Attribute key.\n\t * @param {module:engine/view/element~Element} element Element from which attribute will be removed.\n\t */\n\tremoveAttribute( key, element ) {\n\t\telement._removeAttribute( key );\n\t}\n\n\t/**\n\t * Adds specified class to the element.\n\t *\n\t *\t\twriter.addClass( linkElement, 'foo' );\n\t *\t\twriter.addClass( linkElement, [ 'foo', 'bar' ] );\n\t *\n\t * @see module:engine/view/element~Element#_addClass\n\t * @param {Array.<String>|String} className Single class name or array of class names which will be added.\n\t * @param {module:engine/view/element~Element} element Element for which class will be added.\n\t */\n\taddClass( className, element ) {\n\t\telement._addClass( className );\n\t}\n\n\t/**\n\t * Removes specified class from the element.\n\t *\n\t *\t\twriter.removeClass( linkElement, 'foo' );\n\t *\t\twriter.removeClass( linkElement, [ 'foo', 'bar' ] );\n\t *\n\t * @see module:engine/view/element~Element#_removeClass\n\t * @param {Array.<String>|String} className Single class name or array of class names which will be removed.\n\t * @param {module:engine/view/element~Element} element Element from which class will be removed.\n\t */\n\tremoveClass( className, element ) {\n\t\telement._removeClass( className );\n\t}\n\n\t/**\n\t * Adds style to the element.\n\t *\n\t *\t\twriter.setStyle( element, 'color', 'red' );\n\t *\t\twriter.setStyle( element, {\n\t *\t\t\tcolor: 'red',\n\t *\t\t\tposition: 'fixed'\n\t *\t\t} );\n\t *\n\t * **Note**: This method can work with normalized style names if\n\t * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#set `StylesMap#set()`} for details.\n\t *\n\t * @see module:engine/view/element~Element#_setStyle\n\t * @param {String|Object} property Property name or object with key - value pairs.\n\t * @param {String} [value] Value to set. This parameter is ignored if object is provided as the first parameter.\n\t * @param {module:engine/view/element~Element} element Element for which style will be added.\n\t */\n\tsetStyle( property, value, element ) {\n\t\tif ( isPlainObject( property ) && element === undefined ) {\n\t\t\telement = value;\n\t\t}\n\t\telement._setStyle( property, value );\n\t}\n\n\t/**\n\t * Removes specified style from the element.\n\t *\n\t *\t\twriter.removeStyle( element, 'color' );  // Removes 'color' style.\n\t *\t\twriter.removeStyle( element, [ 'color', 'border-top' ] ); // Removes both 'color' and 'border-top' styles.\n\t *\n\t * **Note**: This method can work with normalized style names if\n\t * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#remove `StylesMap#remove()`} for details.\n\t *\n\t * @see module:engine/view/element~Element#_removeStyle\n\t * @param {Array.<String>|String} property Style property name or names to be removed.\n\t * @param {module:engine/view/element~Element} element Element from which style will be removed.\n\t */\n\tremoveStyle( property, element ) {\n\t\telement._removeStyle( property );\n\t}\n\n\t/**\n\t * Sets a custom property on element. Unlike attributes, custom properties are not rendered to the DOM,\n\t * so they can be used to add special data to elements.\n\t *\n\t * @see module:engine/view/element~Element#_setCustomProperty\n\t * @param {String|Symbol} key Custom property name/key.\n\t * @param {*} value Custom property value to be stored.\n\t * @param {module:engine/view/element~Element} element Element for which custom property will be set.\n\t */\n\tsetCustomProperty( key, value, element ) {\n\t\telement._setCustomProperty( key, value );\n\t}\n\n\t/**\n\t * Removes a custom property stored under the given key.\n\t *\n\t * @see module:engine/view/element~Element#_removeCustomProperty\n\t * @param {String|Symbol} key Name/key of the custom property to be removed.\n\t * @param {module:engine/view/element~Element} element Element from which the custom property will be removed.\n\t * @returns {Boolean} Returns true if property was removed.\n\t */\n\tremoveCustomProperty( key, element ) {\n\t\treturn element._removeCustomProperty( key );\n\t}\n\n\t/**\n\t * Creates position at the given location. The location can be specified as:\n\t *\n\t * * a {@link module:engine/view/position~Position position},\n\t * * parent element and offset (offset defaults to `0`),\n\t * * parent element and `'end'` (sets position at the end of that element),\n\t * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).\n\t *\n\t * This method is a shortcut to other constructors such as:\n\t *\n\t * * {@link #createPositionBefore},\n\t * * {@link #createPositionAfter},\n\t *\n\t * @param {module:engine/view/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/view/item~Item view item}.\n\t */\n\tcreatePositionAt( itemOrPosition, offset ) {\n\t\treturn Position._createAt( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Creates a new position after given view item.\n\t *\n\t * @param {module:engine/view/item~Item} item View item after which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tcreatePositionAfter( item ) {\n\t\treturn Position._createAfter( item );\n\t}\n\n\t/**\n\t * Creates a new position before given view item.\n\t *\n\t * @param {module:engine/view/item~Item} item View item before which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tcreatePositionBefore( item ) {\n\t\treturn Position._createBefore( item );\n\t}\n\n\t/**\n\t * Creates a range spanning from `start` position to `end` position.\n\t *\n\t * **Note:** This factory method creates it's own {@link module:engine/view/position~Position} instances basing on passed values.\n\t *\n\t * @param {module:engine/view/position~Position} start Start position.\n\t * @param {module:engine/view/position~Position} [end] End position. If not set, range will be collapsed at `start` position.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRange( start, end ) {\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.\n\t *\n\t * @param {module:engine/view/item~Item} item\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRangeOn( item ) {\n\t\treturn Range._createOn( item );\n\t}\n\n\t/**\n\t * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t * @param {module:engine/view/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRangeIn( element ) {\n\t\treturn Range._createIn( element );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/selection~Selection} instance.\n\t *\n\t * \t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = writer.createSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tconst selection = writer.createSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tconst selection = writer.createSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tconst selection = writer.createSelection( otherSelection );\n\t *\n\t *\t\t// Creates selection from the document selection.\n\t *\t\tconst selection = writer.createSelection( editor.editing.view.document.selection );\n\t *\n\t * \t\t// Creates selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\tconst selection = writer.createSelection( position );\n\t *\n\t *\t\t// Creates collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = writer.createContainerElement( 'paragraph' );\n\t *\t\tconst selection = writer.createSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'on' );\n\t *\n\t * `Selection`'s constructor allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = writer.createSelection( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * (and be  properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tconst selection = writer.createSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/selection~Selectable} [selectable=null]\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Offset or place when selectable is an `Item`.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t * @returns {module:engine/view/selection~Selection}\n\t */\n\tcreateSelection( selectable, placeOrOffset, options ) {\n\t\treturn new Selection( selectable, placeOrOffset, options );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport FileRepository from '@ckeditor/ckeditor5-upload/src/filerepository';\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { insertImage, isImageAllowed } from '../image/utils';\nimport toArray from '@ckeditor/ckeditor5-utils/src/toarray';\n\n/**\n * @module image/imageupload/imageuploadcommand\n */\n\n/**\n * The image upload command.\n *\n * The command is registered by the {@link module:image/imageupload/imageuploadediting~ImageUploadEditing} plugin as `'imageUpload'`.\n *\n * In order to upload an image at the current selection position\n * (according to the {@link module:widget/utils~findOptimalInsertionPosition} algorithm),\n * execute the command and pass the native image file instance:\n *\n *\t\tthis.listenTo( editor.editing.view.document, 'clipboardInput', ( evt, data ) => {\n *\t\t\t// Assuming that only images were pasted:\n *\t\t\tconst images = Array.from( data.dataTransfer.files );\n *\n *\t\t\t// Upload the first image:\n *\t\t\teditor.execute( 'imageUpload', { file: images[ 0 ] } );\n *\t\t} );\n *\n * It is also possible to insert multiple images at once:\n *\n *\t\teditor.execute( 'imageUpload', {\n *\t\t\tfile: [\n *\t\t\t\tfile1,\n *\t\t\t\tfile2\n *\t\t\t]\n *\t\t} );\n *\n * @extends module:core/command~Command\n */\nexport default class ImageUploadCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst imageElement = this.editor.model.document.selection.getSelectedElement();\n\t\tconst isImage = imageElement && imageElement.name === 'image' || false;\n\n\t\tthis.isEnabled = isImageAllowed( this.editor.model ) || isImage;\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @fires execute\n\t * @param {Object} options Options for the executed command.\n\t * @param {File|Array.<File>} options.file The image file or an array of image files to upload.\n\t */\n\texecute( options ) {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\n\t\tconst fileRepository = editor.plugins.get( FileRepository );\n\n\t\tfor ( const file of toArray( options.file ) ) {\n\t\t\tuploadImage( model, fileRepository, file );\n\t\t}\n\t}\n}\n\n// Handles uploading single file.\n//\n// @param {module:engine/model/model~Model} model\n// @param {File} file\nfunction uploadImage( model, fileRepository, file ) {\n\tconst loader = fileRepository.createLoader( file );\n\n\t// Do not throw when upload adapter is not set. FileRepository will log an error anyway.\n\tif ( !loader ) {\n\t\treturn;\n\t}\n\n\tinsertImage( model, { uploadId: loader.id } );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imageupload/imageuploadediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport FileRepository from '@ckeditor/ckeditor5-upload/src/filerepository';\nimport Notification from '@ckeditor/ckeditor5-ui/src/notification/notification';\nimport Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';\nimport UpcastWriter from '@ckeditor/ckeditor5-engine/src/view/upcastwriter';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\nimport ImageUploadCommand from '../../src/imageupload/imageuploadcommand';\nimport { fetchLocalImage, isLocalImage } from '../../src/imageupload/utils';\nimport { createImageTypeRegExp } from './utils';\nimport { getViewImgFromWidget } from '../image/utils';\n\n/**\n * The editing part of the image upload feature. It registers the `'imageUpload'` command.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageUploadEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ FileRepository, Notification, Clipboard ];\n\t}\n\n\tstatic get pluginName() {\n\t\treturn 'ImageUploadEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( 'image', {\n\t\t\tupload: {\n\t\t\t\ttypes: [ 'jpeg', 'png', 'gif', 'bmp', 'webp', 'tiff' ]\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst doc = editor.model.document;\n\t\tconst schema = editor.model.schema;\n\t\tconst conversion = editor.conversion;\n\t\tconst fileRepository = editor.plugins.get( FileRepository );\n\n\t\tconst imageTypes = createImageTypeRegExp( editor.config.get( 'image.upload.types' ) );\n\n\t\t// Setup schema to allow uploadId and uploadStatus for images.\n\t\tschema.extend( 'image', {\n\t\t\tallowAttributes: [ 'uploadId', 'uploadStatus' ]\n\t\t} );\n\n\t\t// Register imageUpload command.\n\t\teditor.commands.add( 'imageUpload', new ImageUploadCommand( editor ) );\n\n\t\t// Register upcast converter for uploadId.\n\t\tconversion.for( 'upcast' )\n\t\t\t.attributeToAttribute( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'img',\n\t\t\t\t\tkey: 'uploadId'\n\t\t\t\t},\n\t\t\t\tmodel: 'uploadId'\n\t\t\t} );\n\n\t\t// Handle pasted images.\n\t\t// For every image file, a new file loader is created and a placeholder image is\n\t\t// inserted into the content. Then, those images are uploaded once they appear in the model\n\t\t// (see Document#change listener below).\n\t\tthis.listenTo( editor.editing.view.document, 'clipboardInput', ( evt, data ) => {\n\t\t\t// Skip if non empty HTML data is included.\n\t\t\t// https://github.com/ckeditor/ckeditor5-upload/issues/68\n\t\t\tif ( isHtmlIncluded( data.dataTransfer ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst images = Array.from( data.dataTransfer.files ).filter( file => {\n\t\t\t\t// See https://github.com/ckeditor/ckeditor5-image/pull/254.\n\t\t\t\tif ( !file ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\treturn imageTypes.test( file.type );\n\t\t\t} );\n\n\t\t\tconst ranges = data.targetRanges.map( viewRange => editor.editing.mapper.toModelRange( viewRange ) );\n\n\t\t\teditor.model.change( writer => {\n\t\t\t\t// Set selection to paste target.\n\t\t\t\twriter.setSelection( ranges );\n\n\t\t\t\tif ( images.length ) {\n\t\t\t\t\tevt.stop();\n\n\t\t\t\t\t// Upload images after the selection has changed in order to ensure the command's state is refreshed.\n\t\t\t\t\teditor.model.enqueueChange( 'default', () => {\n\t\t\t\t\t\teditor.execute( 'imageUpload', { file: images } );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\n\t\t// Handle HTML pasted with images with base64 or blob sources.\n\t\t// For every image file, a new file loader is created and a placeholder image is\n\t\t// inserted into the content. Then, those images are uploaded once they appear in the model\n\t\t// (see Document#change listener below).\n\t\tthis.listenTo( editor.plugins.get( Clipboard ), 'inputTransformation', ( evt, data ) => {\n\t\t\tconst fetchableImages = Array.from( editor.editing.view.createRangeIn( data.content ) )\n\t\t\t\t.filter( value => isLocalImage( value.item ) && !value.item.getAttribute( 'uploadProcessed' ) )\n\t\t\t\t.map( value => { return { promise: fetchLocalImage( value.item ), imageElement: value.item }; } );\n\n\t\t\tif ( !fetchableImages.length ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst writer = new UpcastWriter( editor.editing.view.document );\n\n\t\t\tfor ( const fetchableImage of fetchableImages ) {\n\t\t\t\t// Set attribute marking that the image was processed already.\n\t\t\t\twriter.setAttribute( 'uploadProcessed', true, fetchableImage.imageElement );\n\n\t\t\t\tconst loader = fileRepository.createLoader( fetchableImage.promise );\n\n\t\t\t\tif ( loader ) {\n\t\t\t\t\twriter.setAttribute( 'src', '', fetchableImage.imageElement );\n\t\t\t\t\twriter.setAttribute( 'uploadId', loader.id, fetchableImage.imageElement );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\t// Prevents from the browser redirecting to the dropped image.\n\t\teditor.editing.view.document.on( 'dragover', ( evt, data ) => {\n\t\t\tdata.preventDefault();\n\t\t} );\n\n\t\t// Upload placeholder images that appeared in the model.\n\t\tdoc.on( 'change', () => {\n\t\t\tconst changes = doc.differ.getChanges( { includeChangesInGraveyard: true } );\n\n\t\t\tfor ( const entry of changes ) {\n\t\t\t\tif ( entry.type == 'insert' && entry.name != '$text' ) {\n\t\t\t\t\tconst item = entry.position.nodeAfter;\n\t\t\t\t\tconst isInGraveyard = entry.position.root.rootName == '$graveyard';\n\n\t\t\t\t\tfor ( const image of getImagesFromChangeItem( editor, item ) ) {\n\t\t\t\t\t\t// Check if the image element still has upload id.\n\t\t\t\t\t\tconst uploadId = image.getAttribute( 'uploadId' );\n\n\t\t\t\t\t\tif ( !uploadId ) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Check if the image is loaded on this client.\n\t\t\t\t\t\tconst loader = fileRepository.loaders.get( uploadId );\n\n\t\t\t\t\t\tif ( !loader ) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( isInGraveyard ) {\n\t\t\t\t\t\t\t// If the image was inserted to the graveyard - abort the loading process.\n\t\t\t\t\t\t\tloader.abort();\n\t\t\t\t\t\t} else if ( loader.status == 'idle' ) {\n\t\t\t\t\t\t\t// If the image was inserted into content and has not been loaded yet, start loading it.\n\t\t\t\t\t\t\tthis._readAndUpload( loader, image );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Reads and uploads an image.\n\t *\n\t * The image is read from the disk and as a Base64-encoded string it is set temporarily to\n\t * `image[src]`. When the image is successfully uploaded, the temporary data is replaced with the target\n\t * image's URL (the URL to the uploaded image on the server).\n\t *\n\t * @protected\n\t * @param {module:upload/filerepository~FileLoader} loader\n\t * @param {module:engine/model/element~Element} imageElement\n\t * @returns {Promise}\n\t */\n\t_readAndUpload( loader, imageElement ) {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst t = editor.locale.t;\n\t\tconst fileRepository = editor.plugins.get( FileRepository );\n\t\tconst notification = editor.plugins.get( Notification );\n\n\t\tmodel.enqueueChange( 'transparent', writer => {\n\t\t\twriter.setAttribute( 'uploadStatus', 'reading', imageElement );\n\t\t} );\n\n\t\treturn loader.read()\n\t\t\t.then( () => {\n\t\t\t\tconst promise = loader.upload();\n\n\t\t\t\t// Force re–paint in Safari. Without it, the image will display with a wrong size.\n\t\t\t\t// https://github.com/ckeditor/ckeditor5/issues/1975\n\t\t\t\t/* istanbul ignore next */\n\t\t\t\tif ( env.isSafari ) {\n\t\t\t\t\tconst viewFigure = editor.editing.mapper.toViewElement( imageElement );\n\t\t\t\t\tconst viewImg = getViewImgFromWidget( viewFigure );\n\n\t\t\t\t\teditor.editing.view.once( 'render', () => {\n\t\t\t\t\t\t// Early returns just to be safe. There might be some code ran\n\t\t\t\t\t\t// in between the outer scope and this callback.\n\t\t\t\t\t\tif ( !viewImg.parent ) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst domFigure = editor.editing.view.domConverter.mapViewToDom( viewImg.parent );\n\n\t\t\t\t\t\tif ( !domFigure ) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst originalDisplay = domFigure.style.display;\n\n\t\t\t\t\t\tdomFigure.style.display = 'none';\n\n\t\t\t\t\t\t// Make sure this line will never be removed during minification for having \"no effect\".\n\t\t\t\t\t\tdomFigure._ckHack = domFigure.offsetHeight;\n\n\t\t\t\t\t\tdomFigure.style.display = originalDisplay;\n\t\t\t\t\t} );\n\t\t\t\t}\n\n\t\t\t\tmodel.enqueueChange( 'transparent', writer => {\n\t\t\t\t\twriter.setAttribute( 'uploadStatus', 'uploading', imageElement );\n\t\t\t\t} );\n\n\t\t\t\treturn promise;\n\t\t\t} )\n\t\t\t.then( data => {\n\t\t\t\tmodel.enqueueChange( 'transparent', writer => {\n\t\t\t\t\twriter.setAttributes( { uploadStatus: 'complete', src: data.default }, imageElement );\n\t\t\t\t\tthis._parseAndSetSrcsetAttributeOnImage( data, imageElement, writer );\n\t\t\t\t} );\n\n\t\t\t\tclean();\n\t\t\t} )\n\t\t\t.catch( error => {\n\t\t\t\t// If status is not 'error' nor 'aborted' - throw error because it means that something else went wrong,\n\t\t\t\t// it might be generic error and it would be real pain to find what is going on.\n\t\t\t\tif ( loader.status !== 'error' && loader.status !== 'aborted' ) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\n\t\t\t\t// Might be 'aborted'.\n\t\t\t\tif ( loader.status == 'error' && error ) {\n\t\t\t\t\tnotification.showWarning( error, {\n\t\t\t\t\t\ttitle: t( 'Upload failed' ),\n\t\t\t\t\t\tnamespace: 'upload'\n\t\t\t\t\t} );\n\t\t\t\t}\n\n\t\t\t\tclean();\n\n\t\t\t\t// Permanently remove image from insertion batch.\n\t\t\t\tmodel.enqueueChange( 'transparent', writer => {\n\t\t\t\t\twriter.remove( imageElement );\n\t\t\t\t} );\n\t\t\t} );\n\n\t\tfunction clean() {\n\t\t\tmodel.enqueueChange( 'transparent', writer => {\n\t\t\t\twriter.removeAttribute( 'uploadId', imageElement );\n\t\t\t\twriter.removeAttribute( 'uploadStatus', imageElement );\n\t\t\t} );\n\n\t\t\tfileRepository.destroyLoader( loader );\n\t\t}\n\t}\n\n\t/**\n\t * Creates the `srcset` attribute based on a given file upload response and sets it as an attribute to a specific image element.\n\t *\n\t * @protected\n\t * @param {Object} data Data object from which `srcset` will be created.\n\t * @param {module:engine/model/element~Element} image The image element on which the `srcset` attribute will be set.\n\t * @param {module:engine/model/writer~Writer} writer\n\t */\n\t_parseAndSetSrcsetAttributeOnImage( data, image, writer ) {\n\t\t// Srcset attribute for responsive images support.\n\t\tlet maxWidth = 0;\n\n\t\tconst srcsetAttribute = Object.keys( data )\n\t\t// Filter out keys that are not integers.\n\t\t\t.filter( key => {\n\t\t\t\tconst width = parseInt( key, 10 );\n\n\t\t\t\tif ( !isNaN( width ) ) {\n\t\t\t\t\tmaxWidth = Math.max( maxWidth, width );\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t} )\n\n\t\t\t// Convert each key to srcset entry.\n\t\t\t.map( key => `${ data[ key ] } ${ key }w` )\n\n\t\t\t// Join all entries.\n\t\t\t.join( ', ' );\n\n\t\tif ( srcsetAttribute != '' ) {\n\t\t\twriter.setAttribute( 'srcset', {\n\t\t\t\tdata: srcsetAttribute,\n\t\t\t\twidth: maxWidth\n\t\t\t}, image );\n\t\t}\n\t}\n}\n\n// Returns `true` if non-empty `text/html` is included in the data transfer.\n//\n// @param {module:clipboard/datatransfer~DataTransfer} dataTransfer\n// @returns {Boolean}\nexport function isHtmlIncluded( dataTransfer ) {\n\treturn Array.from( dataTransfer.types ).includes( 'text/html' ) && dataTransfer.getData( 'text/html' ) !== '';\n}\n\nfunction getImagesFromChangeItem( editor, item ) {\n\treturn Array.from( editor.model.createRangeOn( item ) )\n\t\t.filter( value => value.item.is( 'element', 'image' ) )\n\t\t.map( value => value.item );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imageupload\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ImageUploadUI from './imageupload/imageuploadui';\nimport ImageUploadProgress from './imageupload/imageuploadprogress';\nimport ImageUploadEditing from './imageupload/imageuploadediting';\n\n/**\n * The image upload plugin.\n *\n * For a detailed overview, check the {@glink features/image-upload/image-upload image upload feature} documentation.\n *\n * This plugin does not do anything directly, but it loads a set of specific plugins to enable image uploading:\n *\n * * {@link module:image/imageupload/imageuploadediting~ImageUploadEditing},\n * * {@link module:image/imageupload/imageuploadui~ImageUploadUI},\n * * {@link module:image/imageupload/imageuploadprogress~ImageUploadProgress}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageUpload extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageUpload';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ImageUploadEditing, ImageUploadUI, ImageUploadProgress ];\n\t}\n}\n\n/**\n * The image upload configuration.\n *\n * @member {module:image/imageupload~ImageUploadConfig} module:image/image~ImageConfig#upload\n */\n\n/**\n * The configuration of the image upload feature. Used by the image upload feature in the `@ckeditor/ckeditor5-image` package.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\timage: {\n * \t\t\t\t\tupload:  ... // Image upload feature options.\n * \t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface module:image/imageupload~ImageUploadConfig\n */\n\n/**\n * The list of accepted image types.\n *\n * The accepted types of images can be customized to allow only certain types of images:\n *\n *\t\t// Allow only JPEG and PNG images:\n *\t\tconst imageUploadConfig = {\n *\t\t\ttypes: [ 'png', 'jpeg' ]\n *\t\t};\n *\n * The type string should match [one of the sub-types](https://www.iana.org/assignments/media-types/media-types.xhtml#image)\n * of the image MIME type. For example, for the `image/jpeg` MIME type, add `'jpeg'` to your image upload configuration.\n *\n * **Note:** This setting only restricts some image types to be selected and uploaded through the CKEditor UI and commands. Image type\n * recognition and filtering should also be implemented on the server which accepts image uploads.\n *\n * @member {Array.<String>} module:image/imageupload~ImageUploadConfig#types\n * @default [ 'jpeg', 'png', 'gif', 'bmp', 'webp', 'tiff' ]\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paragraph/paragraphcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport first from '@ckeditor/ckeditor5-utils/src/first';\n\n/**\n * The paragraph command.\n *\n * @extends module:core/command~Command\n */\nexport default class ParagraphCommand extends Command {\n\t/**\n\t * The value of the command. Indicates whether the selection start is placed in a paragraph.\n\t *\n\t * @readonly\n\t * @observable\n\t * @member {Boolean} #value\n\t */\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\t\tconst block = first( document.selection.getSelectedBlocks() );\n\n\t\tthis.value = !!block && block.is( 'element', 'paragraph' );\n\t\tthis.isEnabled = !!block && checkCanBecomeParagraph( block, model.schema );\n\t}\n\n\t/**\n\t * Executes the command. All the blocks (see {@link module:engine/model/schema~Schema}) in the selection\n\t * will be turned to paragraphs.\n\t *\n\t * @fires execute\n\t * @param {Object} [options] Options for the executed command.\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} [options.selection]\n\t * The selection that the command should be applied to.\n\t * By default, if not provided, the command is applied to the {@link module:engine/model/document~Document#selection}.\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\n\t\tmodel.change( writer => {\n\t\t\tconst blocks = ( options.selection || document.selection ).getSelectedBlocks();\n\n\t\t\tfor ( const block of blocks ) {\n\t\t\t\tif ( !block.is( 'element', 'paragraph' ) && checkCanBecomeParagraph( block, model.schema ) ) {\n\t\t\t\t\twriter.rename( block, 'paragraph' );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n}\n\n// Checks whether the given block can be replaced by a paragraph.\n//\n// @private\n// @param {module:engine/model/element~Element} block A block to be tested.\n// @param {module:engine/model/schema~Schema} schema The schema of the document.\n// @returns {Boolean}\nfunction checkCanBecomeParagraph( block, schema ) {\n\treturn schema.checkChild( block.parent, 'paragraph' ) && !schema.isObject( block );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paragraph/insertparagraphcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\n/**\n * The insert paragraph command. It inserts a new paragraph at a specific\n * {@link module:engine/model/position~Position document position}.\n *\n *\t\t// Insert a new paragraph before an element in the document.\n *\t\teditor.execute( 'insertParagraph', {\n *\t\t\tposition: editor.model.createPositionBefore( element )\n *\t\t} );\n *\n * If a paragraph is disallowed in the context of the specific position, the command\n * will attempt to split position ancestors to find a place where it is possible\n * to insert a paragraph.\n *\n * **Note**: This command moves the selection to the inserted paragraph.\n *\n * @extends module:core/command~Command\n */\nexport default class InsertParagraphCommand extends Command {\n\t/**\n\t * Executes the command.\n\t *\n\t * @param {Object} options Options for the executed command.\n\t * @param {module:engine/model/position~Position} options.position The model position at which\n\t * the new paragraph will be inserted.\n\t * @fires execute\n\t */\n\texecute( options ) {\n\t\tconst model = this.editor.model;\n\t\tlet position = options.position;\n\n\t\tmodel.change( writer => {\n\t\t\tconst paragraph = writer.createElement( 'paragraph' );\n\n\t\t\tif ( !model.schema.checkChild( position.parent, paragraph ) ) {\n\t\t\t\tconst allowedParent = model.schema.findAllowedParent( position, paragraph );\n\n\t\t\t\t// It could be there's no ancestor limit that would allow paragraph.\n\t\t\t\t// In theory, \"paragraph\" could be disallowed even in the \"$root\".\n\t\t\t\tif ( !allowedParent ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tposition = writer.split( position, allowedParent ).position;\n\t\t\t}\n\n\t\t\tmodel.insertContent( paragraph, position );\n\n\t\t\twriter.setSelection( paragraph, 'in' );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paragraph/paragraph\n */\n\nimport ParagraphCommand from './paragraphcommand';\nimport InsertParagraphCommand from './insertparagraphcommand';\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\n/**\n * The paragraph feature for the editor.\n *\n * It introduces the `<paragraph>` element in the model which renders as a `<p>` element in the DOM and data.\n *\n * It also brings two editors commands:\n *\n * * The {@link module:paragraph/paragraphcommand~ParagraphCommand `'paragraph'`} command that converts all\n * blocks in the model selection into paragraphs.\n * * The {@link module:paragraph/insertparagraphcommand~InsertParagraphCommand `'insertParagraph'`} command\n * that inserts a new paragraph at a specified location in the model.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Paragraph extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Paragraph';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\n\t\teditor.commands.add( 'paragraph', new ParagraphCommand( editor ) );\n\t\teditor.commands.add( 'insertParagraph', new InsertParagraphCommand( editor ) );\n\n\t\t// Schema.\n\t\tmodel.schema.register( 'paragraph', { inheritAllFrom: '$block' } );\n\n\t\teditor.conversion.elementToElement( { model: 'paragraph', view: 'p' } );\n\n\t\t// Conversion for paragraph-like elements which has not been converted by any plugin.\n\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t\t\tmodel: ( viewElement, { writer } ) => {\n\t\t\t\tif ( !Paragraph.paragraphLikeElements.has( viewElement.name ) ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\t// Do not auto-paragraph empty elements.\n\t\t\t\tif ( viewElement.isEmpty ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\treturn writer.createElement( 'paragraph' );\n\t\t\t},\n\t\t\tview: /.+/,\n\t\t\tconverterPriority: 'low'\n\t\t} );\n\t}\n}\n\n/**\n * A list of element names which should be treated by the autoparagraphing algorithms as\n * paragraph-like. This means that e.g. the following content:\n *\n *\t\t<h1>Foo</h1>\n *\t\t<table>\n *\t\t\t<tr>\n *\t\t\t\t<td>X</td>\n *\t\t\t\t<td>\n *\t\t\t\t\t<ul>\n *\t\t\t\t\t\t<li>Y</li>\n *\t\t\t\t\t\t<li>Z</li>\n *\t\t\t\t\t</ul>\n *\t\t\t\t</td>\n *\t\t\t</tr>\n *\t\t</table>\n *\n * contains five paragraph-like elements: `<h1>`, two `<td>`s and two `<li>`s.\n * Hence, if none of the features is going to convert those elements the above content will be automatically handled\n * by the paragraph feature and converted to:\n *\n *\t\t<p>Foo</p>\n *\t\t<p>X</p>\n *\t\t<p>Y</p>\n *\t\t<p>Z</p>\n *\n * Note: The `<td>` containing two `<li>` elements was ignored as the innermost paragraph-like elements\n * have a priority upon conversion.\n *\n * @member {Set.<String>} module:paragraph/paragraph~Paragraph.paragraphLikeElements\n */\nParagraph.paragraphLikeElements = new Set( [\n\t'blockquote',\n\t'dd',\n\t'div',\n\t'dt',\n\t'h1',\n\t'h2',\n\t'h3',\n\t'h4',\n\t'h5',\n\t'h6',\n\t'li',\n\t'p',\n\t'td',\n\t'th'\n] );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module heading/headingcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport first from '@ckeditor/ckeditor5-utils/src/first';\n\n/**\n * The heading command. It is used by the {@link module:heading/heading~Heading heading feature} to apply headings.\n *\n * @extends module:core/command~Command\n */\nexport default class HeadingCommand extends Command {\n\t/**\n\t * Creates an instance of the command.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor Editor instance.\n\t * @param {Array.<String>} modelElements Names of the element which this command can apply in the model.\n\t */\n\tconstructor( editor, modelElements ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * If the selection starts in a heading (which {@link #modelElements is supported by this command})\n\t\t * the value is set to the name of that heading model element.\n\t\t * It is  set to `false` otherwise.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean|String} #value\n\t\t */\n\n\t\t/**\n\t\t * Set of defined model's elements names that this command support.\n\t\t * See {@link module:heading/heading~HeadingOption}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<String>}\n\t\t */\n\t\tthis.modelElements = modelElements;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst block = first( this.editor.model.document.selection.getSelectedBlocks() );\n\n\t\tthis.value = !!block && this.modelElements.includes( block.name ) && block.name;\n\t\tthis.isEnabled = !!block && this.modelElements.some( heading => checkCanBecomeHeading( block, heading, this.editor.model.schema ) );\n\t}\n\n\t/**\n\t * Executes the command. Applies the heading to the selected blocks or, if the first selected\n\t * block is a heading already, turns selected headings (of this level only) to paragraphs.\n\t *\n\t * @param {Object} options\n\t * @param {String} options.value Name of the element which this command will apply in the model.\n\t * @fires execute\n\t */\n\texecute( options ) {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\n\t\tconst modelElement = options.value;\n\n\t\tmodel.change( writer => {\n\t\t\tconst blocks = Array.from( document.selection.getSelectedBlocks() )\n\t\t\t\t.filter( block => {\n\t\t\t\t\treturn checkCanBecomeHeading( block, modelElement, model.schema );\n\t\t\t\t} );\n\n\t\t\tfor ( const block of blocks ) {\n\t\t\t\tif ( !block.is( 'element', modelElement ) ) {\n\t\t\t\t\twriter.rename( block, modelElement );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n}\n\n// Checks whether the given block can be replaced by a specific heading.\n//\n// @private\n// @param {module:engine/model/element~Element} block A block to be tested.\n// @param {module:heading/headingcommand~HeadingCommand#modelElement} heading Command element name in the model.\n// @param {module:engine/model/schema~Schema} schema The schema of the document.\n// @returns {Boolean}\nfunction checkCanBecomeHeading( block, heading, schema ) {\n\treturn schema.checkChild( block.parent, heading ) && !schema.isObject( block );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module heading/headingediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';\nimport HeadingCommand from './headingcommand';\n\nimport priorities from '@ckeditor/ckeditor5-utils/src/priorities';\n\nconst defaultModelElement = 'paragraph';\n\n/**\n * The headings engine feature. It handles switching between block formats &ndash; headings and paragraph.\n * This class represents the engine part of the heading feature. See also {@link module:heading/heading~Heading}.\n * It introduces `heading1`-`headingN` commands which allow to convert paragraphs into headings.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class HeadingEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'HeadingEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( 'heading', {\n\t\t\toptions: [\n\t\t\t\t{ model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' },\n\t\t\t\t{ model: 'heading1', view: 'h2', title: 'Heading 1', class: 'ck-heading_heading1' },\n\t\t\t\t{ model: 'heading2', view: 'h3', title: 'Heading 2', class: 'ck-heading_heading2' },\n\t\t\t\t{ model: 'heading3', view: 'h4', title: 'Heading 3', class: 'ck-heading_heading3' }\n\t\t\t]\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ Paragraph ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst options = editor.config.get( 'heading.options' );\n\n\t\tconst modelElements = [];\n\n\t\tfor ( const option of options ) {\n\t\t\t// Skip paragraph - it is defined in required Paragraph feature.\n\t\t\tif ( option.model !== defaultModelElement ) {\n\t\t\t\t// Schema.\n\t\t\t\teditor.model.schema.register( option.model, {\n\t\t\t\t\tinheritAllFrom: '$block'\n\t\t\t\t} );\n\n\t\t\t\teditor.conversion.elementToElement( option );\n\n\t\t\t\tmodelElements.push( option.model );\n\t\t\t}\n\t\t}\n\n\t\tthis._addDefaultH1Conversion( editor );\n\n\t\t// Register the heading command for this option.\n\t\teditor.commands.add( 'heading', new HeadingCommand( editor, modelElements ) );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\t// If the enter command is added to the editor, alter its behavior.\n\t\t// Enter at the end of a heading element should create a paragraph.\n\t\tconst editor = this.editor;\n\t\tconst enterCommand = editor.commands.get( 'enter' );\n\t\tconst options = editor.config.get( 'heading.options' );\n\n\t\tif ( enterCommand ) {\n\t\t\tthis.listenTo( enterCommand, 'afterExecute', ( evt, data ) => {\n\t\t\t\tconst positionParent = editor.model.document.selection.getFirstPosition().parent;\n\t\t\t\tconst isHeading = options.some( option => positionParent.is( 'element', option.model ) );\n\n\t\t\t\tif ( isHeading && !positionParent.is( 'element', defaultModelElement ) && positionParent.childCount === 0 ) {\n\t\t\t\t\tdata.writer.rename( positionParent, defaultModelElement );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Adds default conversion for `h1` -> `heading1` with a low priority.\n\t *\n\t * @private\n\t * @param {module:core/editor/editor~Editor} editor Editor instance on which to add the `h1` conversion.\n\t */\n\t_addDefaultH1Conversion( editor ) {\n\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t\t\tmodel: 'heading1',\n\t\t\tview: 'h1',\n\t\t\t// With a `low` priority, `paragraph` plugin autoparagraphing mechanism is executed. Make sure\n\t\t\t// this listener is called before it. If not, `h1` will be transformed into a paragraph.\n\t\t\tconverterPriority: priorities.get( 'low' ) + 1\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/model\n */\n\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport { extend } from 'lodash-es';\n\n/**\n * The base MVC model class.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Model {\n\t/**\n\t * Creates a new Model instance.\n\t *\n\t * @param {Object} [attributes] The model state attributes to be defined during the instance creation.\n\t * @param {Object} [properties] The (out of state) properties to be appended to the instance during creation.\n\t */\n\tconstructor( attributes, properties ) {\n\t\t// Extend this instance with the additional (out of state) properties.\n\t\tif ( properties ) {\n\t\t\textend( this, properties );\n\t\t}\n\n\t\t// Initialize the attributes.\n\t\tif ( attributes ) {\n\t\t\tthis.set( attributes );\n\t\t}\n\t}\n}\n\nmix( Model, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module heading/headingui\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Model from '@ckeditor/ckeditor5-ui/src/model';\n\nimport { createDropdown, addListToDropdown } from '@ckeditor/ckeditor5-ui/src/dropdown/utils';\nimport { getLocalizedOptions } from './utils';\n\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\n\nimport '../theme/heading.css';\n\n/**\n * The headings UI feature. It introduces the `headings` dropdown.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class HeadingUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\t\tconst options = getLocalizedOptions( editor );\n\t\tconst defaultTitle = t( 'Choose heading' );\n\t\tconst dropdownTooltip = t( 'Heading' );\n\n\t\t// Register UI component.\n\t\teditor.ui.componentFactory.add( 'heading', locale => {\n\t\t\tconst titles = {};\n\t\t\tconst itemDefinitions = new Collection();\n\n\t\t\tconst headingCommand = editor.commands.get( 'heading' );\n\t\t\tconst paragraphCommand = editor.commands.get( 'paragraph' );\n\n\t\t\tconst commands = [ headingCommand ];\n\n\t\t\tfor ( const option of options ) {\n\t\t\t\tconst def = {\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: new Model( {\n\t\t\t\t\t\tlabel: option.title,\n\t\t\t\t\t\tclass: option.class,\n\t\t\t\t\t\twithText: true\n\t\t\t\t\t} )\n\t\t\t\t};\n\n\t\t\t\tif ( option.model === 'paragraph' ) {\n\t\t\t\t\tdef.model.bind( 'isOn' ).to( paragraphCommand, 'value' );\n\t\t\t\t\tdef.model.set( 'commandName', 'paragraph' );\n\t\t\t\t\tcommands.push( paragraphCommand );\n\t\t\t\t} else {\n\t\t\t\t\tdef.model.bind( 'isOn' ).to( headingCommand, 'value', value => value === option.model );\n\t\t\t\t\tdef.model.set( {\n\t\t\t\t\t\tcommandName: 'heading',\n\t\t\t\t\t\tcommandValue: option.model\n\t\t\t\t\t} );\n\t\t\t\t}\n\n\t\t\t\t// Add the option to the collection.\n\t\t\t\titemDefinitions.add( def );\n\n\t\t\t\ttitles[ option.model ] = option.title;\n\t\t\t}\n\n\t\t\tconst dropdownView = createDropdown( locale );\n\t\t\taddListToDropdown( dropdownView, itemDefinitions );\n\n\t\t\tdropdownView.buttonView.set( {\n\t\t\t\tisOn: false,\n\t\t\t\twithText: true,\n\t\t\t\ttooltip: dropdownTooltip\n\t\t\t} );\n\n\t\t\tdropdownView.extendTemplate( {\n\t\t\t\tattributes: {\n\t\t\t\t\tclass: [\n\t\t\t\t\t\t'ck-heading-dropdown'\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tdropdownView.bind( 'isEnabled' ).toMany( commands, 'isEnabled', ( ...areEnabled ) => {\n\t\t\t\treturn areEnabled.some( isEnabled => isEnabled );\n\t\t\t} );\n\n\t\t\tdropdownView.buttonView.bind( 'label' ).to( headingCommand, 'value', paragraphCommand, 'value', ( value, para ) => {\n\t\t\t\tconst whichModel = value || para && 'paragraph';\n\t\t\t\t// If none of the commands is active, display default title.\n\t\t\t\treturn titles[ whichModel ] ? titles[ whichModel ] : defaultTitle;\n\t\t\t} );\n\n\t\t\t// Execute command when an item from the dropdown is selected.\n\t\t\tthis.listenTo( dropdownView, 'execute', evt => {\n\t\t\t\teditor.execute( evt.source.commandName, evt.source.commandValue ? { value: evt.source.commandValue } : undefined );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn dropdownView;\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module heading/utils\n */\n\n/**\n * Returns heading options as defined in `config.heading.options` but processed to consider\n * the editor localization, i.e. to display {@link module:heading/heading~HeadingOption}\n * in the correct language.\n *\n * Note: The reason behind this method is that there is no way to use {@link module:utils/locale~Locale#t}\n * when the user configuration is defined because the editor does not exist yet.\n *\n * @param {module:core/editor/editor~Editor} editor\n * @returns {Array.<module:heading/heading~HeadingOption>}.\n */\nexport function getLocalizedOptions( editor ) {\n\tconst t = editor.t;\n\tconst localizedTitles = {\n\t\tParagraph: t( 'Paragraph' ),\n\t\t'Heading 1': t( 'Heading 1' ),\n\t\t'Heading 2': t( 'Heading 2' ),\n\t\t'Heading 3': t( 'Heading 3' ),\n\t\t'Heading 4': t( 'Heading 4' ),\n\t\t'Heading 5': t( 'Heading 5' ),\n\t\t'Heading 6': t( 'Heading 6' )\n\t};\n\n\treturn editor.config.get( 'heading.options' ).map( option => {\n\t\tconst title = localizedTitles[ option.title ];\n\n\t\tif ( title && title != option.title ) {\n\t\t\toption.title = title;\n\t\t}\n\n\t\treturn option;\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagecaption/utils\n */\n\nimport { enablePlaceholder } from '@ckeditor/ckeditor5-engine/src/view/placeholder';\nimport { toWidgetEditable } from '@ckeditor/ckeditor5-widget/src/utils';\n\n/**\n * Returns a function that creates a caption editable element for the given {@link module:engine/view/document~Document}.\n *\n * @param {module:engine/view/view~View} view\n * @param {String} placeholderText The text to be displayed when the caption is empty.\n * @returns {Function}\n */\nexport function captionElementCreator( view, placeholderText ) {\n\treturn writer => {\n\t\tconst editable = writer.createEditableElement( 'figcaption' );\n\t\twriter.setCustomProperty( 'imageCaption', true, editable );\n\n\t\tenablePlaceholder( {\n\t\t\tview,\n\t\t\telement: editable,\n\t\t\ttext: placeholderText\n\t\t} );\n\n\t\treturn toWidgetEditable( editable, writer );\n\t};\n}\n\n/**\n * Returns `true` if a given view element is the image caption editable.\n *\n * @param {module:engine/view/element~Element} viewElement\n * @returns {Boolean}\n */\nexport function isCaption( viewElement ) {\n\treturn !!viewElement.getCustomProperty( 'imageCaption' );\n}\n\n/**\n * Returns the caption model element from a given image element. Returns `null` if no caption is found.\n *\n * @param {module:engine/model/element~Element} imageModelElement\n * @returns {module:engine/model/element~Element|null}\n */\nexport function getCaptionFromImage( imageModelElement ) {\n\tfor ( const node of imageModelElement.getChildren() ) {\n\t\tif ( !!node && node.is( 'element', 'caption' ) ) {\n\t\t\treturn node;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * {@link module:engine/view/matcher~Matcher} pattern. Checks if a given element is a `<figcaption>` element that is placed\n * inside the image `<figure>` element.\n *\n * @param {module:engine/view/element~Element} element\n * @returns {Object|null} Returns the object accepted by {@link module:engine/view/matcher~Matcher} or `null` if the element\n * cannot be matched.\n */\nexport function matchImageCaption( element ) {\n\tconst parent = element.parent;\n\n\t// Convert only captions for images.\n\tif ( element.name == 'figcaption' && parent && parent.name == 'figure' && parent.hasClass( 'image' ) ) {\n\t\treturn { name: true };\n\t}\n\n\treturn null;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagecaption/imagecaptionediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport { isImage } from '../image/utils';\nimport { captionElementCreator, getCaptionFromImage, matchImageCaption } from './utils';\n\n/**\n * The image caption engine plugin.\n *\n * It registers proper converters. It takes care of adding a caption element if the image without it is inserted\n * to the model document.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageCaptionEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageCaptionEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\t\tconst schema = editor.model.schema;\n\t\tconst data = editor.data;\n\t\tconst editing = editor.editing;\n\t\tconst t = editor.t;\n\n\t\t/**\n\t\t * The last selected caption editable.\n\t\t * It is used for hiding the editable when it is empty and the image widget is no longer selected.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/view/editableelement~EditableElement} #_lastSelectedCaption\n\t\t */\n\n\t\t// Schema configuration.\n\t\tschema.register( 'caption', {\n\t\t\tallowIn: 'image',\n\t\t\tallowContentOf: '$block',\n\t\t\tisLimit: true\n\t\t} );\n\n\t\t// Add caption element to each image inserted without it.\n\t\teditor.model.document.registerPostFixer( writer => this._insertMissingModelCaptionElement( writer ) );\n\n\t\t// View to model converter for the data pipeline.\n\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t\t\tview: matchImageCaption,\n\t\t\tmodel: 'caption'\n\t\t} );\n\n\t\t// Model to view converter for the data pipeline.\n\t\tconst createCaptionForData = writer => writer.createContainerElement( 'figcaption' );\n\t\tdata.downcastDispatcher.on( 'insert:caption', captionModelToView( createCaptionForData, false ) );\n\n\t\t// Model to view converter for the editing pipeline.\n\t\tconst createCaptionForEditing = captionElementCreator( view, t( 'Enter image caption' ) );\n\t\tediting.downcastDispatcher.on( 'insert:caption', captionModelToView( createCaptionForEditing ) );\n\n\t\t// Always show caption in view when something is inserted in model.\n\t\tediting.downcastDispatcher.on(\n\t\t\t'insert',\n\t\t\tthis._fixCaptionVisibility( data => data.item ),\n\t\t\t{ priority: 'high' }\n\t\t);\n\n\t\t// Hide caption when everything is removed from it.\n\t\tediting.downcastDispatcher.on( 'remove', this._fixCaptionVisibility( data => data.position.parent ), { priority: 'high' } );\n\n\t\t// Update caption visibility on view in post fixer.\n\t\tview.document.registerPostFixer( writer => this._updateCaptionVisibility( writer ) );\n\t}\n\n\t/**\n\t * Updates the view before each rendering, making sure that empty captions (so unnecessary ones) are hidden\n\t * and then visible when the image is selected.\n\t *\n\t * @private\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter\n\t * @returns {Boolean} Returns `true` when the view is updated.\n\t */\n\t_updateCaptionVisibility( viewWriter ) {\n\t\tconst mapper = this.editor.editing.mapper;\n\t\tconst lastCaption = this._lastSelectedCaption;\n\t\tlet viewCaption;\n\n\t\t// If whole image is selected.\n\t\tconst modelSelection = this.editor.model.document.selection;\n\t\tconst selectedElement = modelSelection.getSelectedElement();\n\n\t\tif ( selectedElement && selectedElement.is( 'element', 'image' ) ) {\n\t\t\tconst modelCaption = getCaptionFromImage( selectedElement );\n\t\t\tviewCaption = mapper.toViewElement( modelCaption );\n\t\t}\n\n\t\t// If selection is placed inside caption.\n\t\tconst position = modelSelection.getFirstPosition();\n\t\tconst modelCaption = getParentCaption( position.parent );\n\n\t\tif ( modelCaption ) {\n\t\t\tviewCaption = mapper.toViewElement( modelCaption );\n\t\t}\n\n\t\t// Is currently any caption selected?\n\t\tif ( viewCaption ) {\n\t\t\t// Was any caption selected before?\n\t\t\tif ( lastCaption ) {\n\t\t\t\t// Same caption as before?\n\t\t\t\tif ( lastCaption === viewCaption ) {\n\t\t\t\t\treturn showCaption( viewCaption, viewWriter );\n\t\t\t\t} else {\n\t\t\t\t\thideCaptionIfEmpty( lastCaption, viewWriter );\n\t\t\t\t\tthis._lastSelectedCaption = viewCaption;\n\n\t\t\t\t\treturn showCaption( viewCaption, viewWriter );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis._lastSelectedCaption = viewCaption;\n\t\t\t\treturn showCaption( viewCaption, viewWriter );\n\t\t\t}\n\t\t} else {\n\t\t\t// Was any caption selected before?\n\t\t\tif ( lastCaption ) {\n\t\t\t\tconst viewModified = hideCaptionIfEmpty( lastCaption, viewWriter );\n\t\t\t\tthis._lastSelectedCaption = null;\n\n\t\t\t\treturn viewModified;\n\t\t\t} else {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns a converter that fixes caption visibility during the model-to-view conversion.\n\t * Checks if the changed node is placed inside the caption element and fixes its visibility in the view.\n\t *\n\t * @private\n\t * @param {Function} nodeFinder\n\t * @returns {Function}\n\t */\n\t_fixCaptionVisibility( nodeFinder ) {\n\t\treturn ( evt, data, conversionApi ) => {\n\t\t\tconst node = nodeFinder( data );\n\t\t\tconst modelCaption = getParentCaption( node );\n\t\t\tconst mapper = this.editor.editing.mapper;\n\t\t\tconst viewWriter = conversionApi.writer;\n\n\t\t\tif ( modelCaption ) {\n\t\t\t\tconst viewCaption = mapper.toViewElement( modelCaption );\n\n\t\t\t\tif ( viewCaption ) {\n\t\t\t\t\tif ( modelCaption.childCount ) {\n\t\t\t\t\t\tviewWriter.removeClass( 'ck-hidden', viewCaption );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tviewWriter.addClass( 'ck-hidden', viewCaption );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Checks whether the data inserted to the model document have an image element that has no caption element inside it.\n\t * If there is none, it adds it to the image element.\n\t *\n\t * @private\n\t * @param {module:engine/model/writer~Writer} writer The writer to make changes with.\n\t * @returns {Boolean} `true` if any change was applied, `false` otherwise.\n\t */\n\t_insertMissingModelCaptionElement( writer ) {\n\t\tconst model = this.editor.model;\n\t\tconst changes = model.document.differ.getChanges();\n\n\t\tconst imagesWithoutCaption = [];\n\n\t\tfor ( const entry of changes ) {\n\t\t\tif ( entry.type == 'insert' && entry.name != '$text' ) {\n\t\t\t\tconst item = entry.position.nodeAfter;\n\n\t\t\t\tif ( item.is( 'element', 'image' ) && !getCaptionFromImage( item ) ) {\n\t\t\t\t\timagesWithoutCaption.push( item );\n\t\t\t\t}\n\n\t\t\t\t// Check elements with children for nested images.\n\t\t\t\tif ( !item.is( 'element', 'image' ) && item.childCount ) {\n\t\t\t\t\tfor ( const nestedItem of model.createRangeIn( item ).getItems() ) {\n\t\t\t\t\t\tif ( nestedItem.is( 'element', 'image' ) && !getCaptionFromImage( nestedItem ) ) {\n\t\t\t\t\t\t\timagesWithoutCaption.push( nestedItem );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor ( const image of imagesWithoutCaption ) {\n\t\t\twriter.appendElement( 'caption', image );\n\t\t}\n\n\t\treturn !!imagesWithoutCaption.length;\n\t}\n}\n\n// Creates a converter that converts image caption model element to view element.\n//\n// @private\n// @param {Function} elementCreator\n// @param {Boolean} [hide=true] When set to `false` view element will not be inserted when it's empty.\n// @returns {Function}\nfunction captionModelToView( elementCreator, hide = true ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst captionElement = data.item;\n\n\t\t// Return if element shouldn't be present when empty.\n\t\tif ( !captionElement.childCount && !hide ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( isImage( captionElement.parent ) ) {\n\t\t\tif ( !conversionApi.consumable.consume( data.item, 'insert' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst viewImage = conversionApi.mapper.toViewElement( data.range.start.parent );\n\t\t\tconst viewCaption = elementCreator( conversionApi.writer );\n\t\t\tconst viewWriter = conversionApi.writer;\n\n\t\t\t// Hide if empty.\n\t\t\tif ( !captionElement.childCount ) {\n\t\t\t\tviewWriter.addClass( 'ck-hidden', viewCaption );\n\t\t\t}\n\n\t\t\tinsertViewCaptionAndBind( viewCaption, data.item, viewImage, conversionApi );\n\t\t}\n\t};\n}\n\n// Inserts `viewCaption` at the end of `viewImage` and binds it to `modelCaption`.\n//\n// @private\n// @param {module:engine/view/containerelement~ContainerElement} viewCaption\n// @param {module:engine/model/element~Element} modelCaption\n// @param {module:engine/view/containerelement~ContainerElement} viewImage\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\nfunction insertViewCaptionAndBind( viewCaption, modelCaption, viewImage, conversionApi ) {\n\tconst viewPosition = conversionApi.writer.createPositionAt( viewImage, 'end' );\n\n\tconversionApi.writer.insert( viewPosition, viewCaption );\n\tconversionApi.mapper.bindElements( modelCaption, viewCaption );\n}\n\n// Checks if the provided node or one of its ancestors is a caption element, and returns it.\n//\n// @private\n// @param {module:engine/model/node~Node} node\n// @returns {module:engine/model/element~Element|null}\nfunction getParentCaption( node ) {\n\tconst ancestors = node.getAncestors( { includeSelf: true } );\n\tconst caption = ancestors.find( ancestor => ancestor.name == 'caption' );\n\n\tif ( caption && caption.parent && caption.parent.name == 'image' ) {\n\t\treturn caption;\n\t}\n\n\treturn null;\n}\n\n// Hides a given caption in the view if it is empty.\n//\n// @private\n// @param {module:engine/view/containerelement~ContainerElement} caption\n// @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter\n// @returns {Boolean} Returns `true` if the view was modified.\nfunction hideCaptionIfEmpty( caption, viewWriter ) {\n\tif ( !caption.childCount && !caption.hasClass( 'ck-hidden' ) ) {\n\t\tviewWriter.addClass( 'ck-hidden', caption );\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n// Shows the caption.\n//\n// @private\n// @param {module:engine/view/containerelement~ContainerElement} caption\n// @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter\n// @returns {Boolean} Returns `true` if the view was modified.\nfunction showCaption( caption, viewWriter ) {\n\tif ( caption.hasClass( 'ck-hidden' ) ) {\n\t\tviewWriter.removeClass( 'ck-hidden', caption );\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagestyle/imagestylecommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { isImage } from '../image/utils';\n\n/**\n * The image style command. It is used to apply different image styles.\n *\n * @extends module:core/command~Command\n */\nexport default class ImageStyleCommand extends Command {\n\t/**\n\t * Creates an instance of the image style command. Each command instance is handling one style.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t * @param {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} styles The styles that this command supports.\n\t */\n\tconstructor( editor, styles ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The name of the default style, if it is present. If there is no default style, it defaults to `false`.\n\t\t *\n\t\t * @readonly\n\t\t * @type {Boolean|String}\n\t\t */\n\t\tthis.defaultStyle = false;\n\n\t\t/**\n\t\t * A style handled by this command.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} #styles\n\t\t */\n\t\tthis.styles = styles.reduce( ( styles, style ) => {\n\t\t\tstyles[ style.name ] = style;\n\n\t\t\tif ( style.isDefault ) {\n\t\t\t\tthis.defaultStyle = style.name;\n\t\t\t}\n\n\t\t\treturn styles;\n\t\t}, {} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst element = this.editor.model.document.selection.getSelectedElement();\n\n\t\tthis.isEnabled = isImage( element );\n\n\t\tif ( !element ) {\n\t\t\tthis.value = false;\n\t\t} else if ( element.hasAttribute( 'imageStyle' ) ) {\n\t\t\tconst attributeValue = element.getAttribute( 'imageStyle' );\n\t\t\tthis.value = this.styles[ attributeValue ] ? attributeValue : false;\n\t\t} else {\n\t\t\tthis.value = this.defaultStyle;\n\t\t}\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t *\t\teditor.execute( 'imageStyle', { value: 'side' } );\n\t *\n\t * @param {Object} options\n\t * @param {String} options.value The name of the style (based on the\n\t * {@link module:image/image~ImageConfig#styles `image.styles`} configuration option).\n\t * @fires execute\n\t */\n\texecute( options ) {\n\t\tconst styleName = options.value;\n\n\t\tconst model = this.editor.model;\n\t\tconst imageElement = model.document.selection.getSelectedElement();\n\n\t\tmodel.change( writer => {\n\t\t\t// Default style means that there is no `imageStyle` attribute in the model.\n\t\t\t// https://github.com/ckeditor/ckeditor5-image/issues/147\n\t\t\tif ( this.styles[ styleName ].isDefault ) {\n\t\t\t\twriter.removeAttribute( 'imageStyle', imageElement );\n\t\t\t} else {\n\t\t\t\twriter.setAttribute( 'imageStyle', styleName, imageElement );\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport first from '@ckeditor/ckeditor5-utils/src/first';\n\n/**\n * @module image/imagestyle/converters\n */\n\n/**\n * Returns a converter for the `imageStyle` attribute. It can be used for adding, changing and removing the attribute.\n *\n * @param {Object} styles An object containing available styles. See {@link module:image/imagestyle/imagestyleediting~ImageStyleFormat}\n * for more details.\n * @returns {Function} A model-to-view attribute converter.\n */\nexport function modelToViewStyleAttribute( styles ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if there is class name associated with given value.\n\t\tconst newStyle = getStyleByName( data.attributeNewValue, styles );\n\t\tconst oldStyle = getStyleByName( data.attributeOldValue, styles );\n\n\t\tconst viewElement = conversionApi.mapper.toViewElement( data.item );\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\tif ( oldStyle ) {\n\t\t\tviewWriter.removeClass( oldStyle.className, viewElement );\n\t\t}\n\n\t\tif ( newStyle ) {\n\t\t\tviewWriter.addClass( newStyle.className, viewElement );\n\t\t}\n\t};\n}\n\n/**\n * Returns a view-to-model converter converting image CSS classes to a proper value in the model.\n *\n * @param {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} styles The styles for which the converter is created.\n * @returns {Function} A view-to-model converter.\n */\nexport function viewToModelStyleAttribute( styles ) {\n\t// Convert only non–default styles.\n\tconst filteredStyles = styles.filter( style => !style.isDefault );\n\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !data.modelRange ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewFigureElement = data.viewItem;\n\t\tconst modelImageElement = first( data.modelRange.getItems() );\n\n\t\t// Check if `imageStyle` attribute is allowed for current element.\n\t\tif ( !conversionApi.schema.checkAttribute( modelImageElement, 'imageStyle' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Convert style one by one.\n\t\tfor ( const style of filteredStyles ) {\n\t\t\t// Try to consume class corresponding with style.\n\t\t\tif ( conversionApi.consumable.consume( viewFigureElement, { classes: style.className } ) ) {\n\t\t\t\t// And convert this style to model attribute.\n\t\t\t\tconversionApi.writer.setAttribute( 'imageStyle', style.name, modelImageElement );\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Returns the style with a given `name` from an array of styles.\n//\n// @param {String} name\n// @param {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat> } styles\n// @returns {module:image/imagestyle/imagestyleediting~ImageStyleFormat|undefined}\nfunction getStyleByName( name, styles ) {\n\tfor ( const style of styles ) {\n\t\tif ( style.name === name ) {\n\t\t\treturn style;\n\t\t}\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 4.5V3h16v1.5zm2.5 3V12h11V7.5h-11zM4.061 6H15.94c.586 0 1.061.407 1.061.91v5.68c0 .503-.475.91-1.061.91H4.06c-.585 0-1.06-.407-1.06-.91V6.91C3 6.406 3.475 6 4.061 6zM2 16.5V15h16v1.5z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\" clip-rule=\\\"evenodd\\\" stroke-linejoin=\\\"round\\\" stroke-miterlimit=\\\"1.414\\\"><path d=\\\"M18 4.5V3H2v1.5h16zm0 3V6h-5.674v1.5H18zm0 3V9h-5.674v1.5H18zm0 3V12h-5.674v1.5H18zm-8.5-6V12h-6V7.5h6zm.818-1.5H2.682C2.305 6 2 6.407 2 6.91v5.68c0 .503.305.91.682.91h7.636c.377 0 .682-.407.682-.91V6.91c0-.503-.305-.91-.682-.91zM18 16.5V15H2v1.5h16z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 4.5V3h16v1.5zm4.5 3V12h7V7.5h-7zM5.758 6h8.484c.419 0 .758.407.758.91v5.681c0 .502-.34.909-.758.909H5.758c-.419 0-.758-.407-.758-.91V6.91c0-.503.34-.91.758-.91zM2 16.5V15h16v1.5z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 4.5V3h16v1.5zm0 3V6h5.674v1.5zm0 3V9h5.674v1.5zm0 3V12h5.674v1.5zm8.5-6V12h6V7.5h-6zM9.682 6h7.636c.377 0 .682.407.682.91v5.68c0 .503-.305.91-.682.91H9.682c-.377 0-.682-.407-.682-.91V6.91c0-.503.305-.91.682-.91zM2 16.5V15h16v1.5z\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagestyle/utils\n */\n\nimport fullWidthIcon from '@ckeditor/ckeditor5-core/theme/icons/object-full-width.svg';\nimport leftIcon from '@ckeditor/ckeditor5-core/theme/icons/object-left.svg';\nimport centerIcon from '@ckeditor/ckeditor5-core/theme/icons/object-center.svg';\nimport rightIcon from '@ckeditor/ckeditor5-core/theme/icons/object-right.svg';\nimport { logWarning } from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Default image styles provided by the plugin that can be referred in the\n * {@link module:image/image~ImageConfig#styles} configuration.\n *\n * Among them, 2 default semantic content styles are available:\n *\n * * `full` is a full–width image without any CSS class,\n * * `side` is a side image styled with the `image-style-side` CSS class.\n *\n * There are also 3 styles focused on formatting:\n *\n * * `alignLeft` aligns the image to the left using the `image-style-align-left` class,\n * * `alignCenter` centers the image using the `image-style-align-center` class,\n * * `alignRight` aligns the image to the right using the `image-style-align-right` class,\n *\n * @member {Object.<String,Object>}\n */\nconst defaultStyles = {\n\t// This option is equal to the situation when no style is applied.\n\tfull: {\n\t\tname: 'full',\n\t\ttitle: 'Full size image',\n\t\ticon: fullWidthIcon,\n\t\tisDefault: true\n\t},\n\n\t// This represents a side image.\n\tside: {\n\t\tname: 'side',\n\t\ttitle: 'Side image',\n\t\ticon: rightIcon,\n\t\tclassName: 'image-style-side'\n\t},\n\n\t// This style represents an image aligned to the left.\n\talignLeft: {\n\t\tname: 'alignLeft',\n\t\ttitle: 'Left aligned image',\n\t\ticon: leftIcon,\n\t\tclassName: 'image-style-align-left'\n\t},\n\n\t// This style represents a centered image.\n\talignCenter: {\n\t\tname: 'alignCenter',\n\t\ttitle: 'Centered image',\n\t\ticon: centerIcon,\n\t\tclassName: 'image-style-align-center'\n\t},\n\n\t// This style represents an image aligned to the right.\n\talignRight: {\n\t\tname: 'alignRight',\n\t\ttitle: 'Right aligned image',\n\t\ticon: rightIcon,\n\t\tclassName: 'image-style-align-right'\n\t}\n};\n\n/**\n * Default image style icons provided by the plugin that can be referred in the\n * {@link module:image/image~ImageConfig#styles} configuration.\n *\n * There are 4 icons available: `'full'`, `'left'`, `'center'` and `'right'`.\n *\n * @member {Object.<String, String>}\n */\nconst defaultIcons = {\n\tfull: fullWidthIcon,\n\tleft: leftIcon,\n\tright: rightIcon,\n\tcenter: centerIcon\n};\n\n/**\n * Returns a {@link module:image/image~ImageConfig#styles} array with items normalized in the\n * {@link module:image/imagestyle/imagestyleediting~ImageStyleFormat} format and a complete `icon` markup for each style.\n *\n * @returns {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>}\n */\nexport function normalizeImageStyles( configuredStyles = [] ) {\n\treturn configuredStyles.map( _normalizeStyle );\n}\n\n// Normalizes an image style provided in the {@link module:image/image~ImageConfig#styles}\n// and returns it in a {@link module:image/imagestyle/imagestyleediting~ImageStyleFormat}.\n//\n// @param {Object} style\n// @returns {@link module:image/imagestyle/imagestyleediting~ImageStyleFormat}\nfunction _normalizeStyle( style ) {\n\t// Just the name of the style has been passed.\n\tif ( typeof style == 'string' ) {\n\t\tconst styleName = style;\n\n\t\t// If it's one of the defaults, just use it.\n\t\tif ( defaultStyles[ styleName ] ) {\n\t\t\t// Clone the style to avoid overriding defaults.\n\t\t\tstyle = Object.assign( {}, defaultStyles[ styleName ] );\n\t\t}\n\t\t// If it's just a name but none of the defaults, warn because probably it's a mistake.\n\t\telse {\n\t\t\t/**\n\t\t\t * There is no such image style of given name.\n\t\t\t *\n\t\t\t * @error image-style-not-found\n\t\t\t * @param {String} name Name of a missing style name.\n\t\t\t */\n\t\t\tlogWarning( 'image-style-not-found', { name: styleName } );\n\n\t\t\t// Normalize the style anyway to prevent errors.\n\t\t\tstyle = {\n\t\t\t\tname: styleName\n\t\t\t};\n\t\t}\n\t}\n\t// If an object style has been passed and if the name matches one of the defaults,\n\t// extend it with defaults – the user wants to customize a default style.\n\t// Note: Don't override the user–defined style object, clone it instead.\n\telse if ( defaultStyles[ style.name ] ) {\n\t\tconst defaultStyle = defaultStyles[ style.name ];\n\t\tconst extendedStyle = Object.assign( {}, style );\n\n\t\tfor ( const prop in defaultStyle ) {\n\t\t\tif ( !Object.prototype.hasOwnProperty.call( style, prop ) ) {\n\t\t\t\textendedStyle[ prop ] = defaultStyle[ prop ];\n\t\t\t}\n\t\t}\n\n\t\tstyle = extendedStyle;\n\t}\n\n\t// If an icon is defined as a string and correspond with a name\n\t// in default icons, use the default icon provided by the plugin.\n\tif ( typeof style.icon == 'string' && defaultIcons[ style.icon ] ) {\n\t\tstyle.icon = defaultIcons[ style.icon ];\n\t}\n\n\treturn style;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagestyle/imagestyleediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ImageStyleCommand from './imagestylecommand';\nimport { viewToModelStyleAttribute, modelToViewStyleAttribute } from './converters';\nimport { normalizeImageStyles } from './utils';\n\n/**\n * The image style engine plugin. It sets the default configuration, creates converters and registers\n * {@link module:image/imagestyle/imagestylecommand~ImageStyleCommand ImageStyleCommand}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageStyleEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageStyleEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\t\tconst data = editor.data;\n\t\tconst editing = editor.editing;\n\n\t\t// Define default configuration.\n\t\teditor.config.define( 'image.styles', [ 'full', 'side' ] );\n\n\t\t// Get configuration.\n\t\tconst styles = normalizeImageStyles( editor.config.get( 'image.styles' ) );\n\n\t\t// Allow imageStyle attribute in image.\n\t\t// We could call it 'style' but https://github.com/ckeditor/ckeditor5-engine/issues/559.\n\t\tschema.extend( 'image', { allowAttributes: 'imageStyle' } );\n\n\t\t// Converters for imageStyle attribute from model to view.\n\t\tconst modelToViewConverter = modelToViewStyleAttribute( styles );\n\t\tediting.downcastDispatcher.on( 'attribute:imageStyle:image', modelToViewConverter );\n\t\tdata.downcastDispatcher.on( 'attribute:imageStyle:image', modelToViewConverter );\n\n\t\t// Converter for figure element from view to model.\n\t\tdata.upcastDispatcher.on( 'element:figure', viewToModelStyleAttribute( styles ), { priority: 'low' } );\n\n\t\t// Register imageStyle command.\n\t\teditor.commands.add( 'imageStyle', new ImageStyleCommand( editor, styles ) );\n\t}\n}\n\n/**\n * The image style format descriptor.\n *\n *\t\timport fullSizeIcon from 'path/to/icon.svg';\n *\n *\t\tconst imageStyleFormat = {\n *\t\t\tname: 'fullSize',\n *\t\t\ticon: fullSizeIcon,\n *\t\t\ttitle: 'Full size image',\n *\t\t\tclassName: 'image-full-size'\n *\t\t}\n *\n * @typedef {Object} module:image/imagestyle/imagestyleediting~ImageStyleFormat\n *\n * @property {String} name The unique name of the style. It will be used to:\n *\n * * Store the chosen style in the model by setting the `imageStyle` attribute of the `<image>` element.\n * * As a value of the {@link module:image/imagestyle/imagestylecommand~ImageStyleCommand#execute `imageStyle` command},\n * * when registering a button for each of the styles (`'imageStyle:{name}'`) in the\n * {@link module:ui/componentfactory~ComponentFactory UI components factory} (this functionality is provided by the\n * {@link module:image/imagestyle/imagestyleui~ImageStyleUI} plugin).\n *\n * @property {Boolean} [isDefault] When set, the style will be used as the default one.\n * A default style does not apply any CSS class to the view element.\n *\n * @property {String} icon One of the following to be used when creating the style's button:\n *\n * * An SVG icon source (as an XML string).\n * * One of {@link module:image/imagestyle/utils~defaultIcons} to use a default icon provided by the plugin.\n *\n * @property {String} title The style's title.\n *\n * @property {String} className The CSS class used to represent the style in the view.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagestyle/imagestyleui\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\n\nimport { normalizeImageStyles } from './utils';\n\nimport '../../theme/imagestyle.css';\n\n/**\n * The image style UI plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageStyleUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageStyleUI';\n\t}\n\n\t/**\n\t * Returns the default localized style titles provided by the plugin.\n\t *\n\t * The following localized titles corresponding with\n\t * {@link module:image/imagestyle/utils~defaultStyles} are available:\n\t *\n\t * * `'Full size image'`,\n\t * * `'Side image'`,\n\t * * `'Left aligned image'`,\n\t * * `'Centered image'`,\n\t * * `'Right aligned image'`\n\t *\n\t * @returns {Object.<String,String>}\n\t */\n\tget localizedDefaultStylesTitles() {\n\t\tconst t = this.editor.t;\n\n\t\treturn {\n\t\t\t'Full size image': t( 'Full size image' ),\n\t\t\t'Side image': t( 'Side image' ),\n\t\t\t'Left aligned image': t( 'Left aligned image' ),\n\t\t\t'Centered image': t( 'Centered image' ),\n\t\t\t'Right aligned image': t( 'Right aligned image' )\n\t\t};\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst configuredStyles = editor.config.get( 'image.styles' );\n\n\t\tconst translatedStyles = translateStyles( normalizeImageStyles( configuredStyles ), this.localizedDefaultStylesTitles );\n\n\t\tfor ( const style of translatedStyles ) {\n\t\t\tthis._createButton( style );\n\t\t}\n\t}\n\n\t/**\n\t * Creates a button for each style and stores it in the editor {@link module:ui/componentfactory~ComponentFactory ComponentFactory}.\n\t *\n\t * @private\n\t * @param {module:image/imagestyle/imagestyleediting~ImageStyleFormat} style\n\t */\n\t_createButton( style ) {\n\t\tconst editor = this.editor;\n\n\t\tconst componentName = `imageStyle:${ style.name }`;\n\n\t\teditor.ui.componentFactory.add( componentName, locale => {\n\t\t\tconst command = editor.commands.get( 'imageStyle' );\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: style.title,\n\t\t\t\ticon: style.icon,\n\t\t\t\ttooltip: true,\n\t\t\t\tisToggleable: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isEnabled' ).to( command, 'isEnabled' );\n\t\t\tview.bind( 'isOn' ).to( command, 'value', value => value === style.name );\n\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\teditor.execute( 'imageStyle', { value: style.name } );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n\n/**\n * Returns the translated `title` from the passed styles array.\n *\n * @param {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} styles\n * @param titles\n * @returns {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>}\n */\nfunction translateStyles( styles, titles ) {\n\tfor ( const style of styles ) {\n\t\t// Localize the titles of the styles, if a title corresponds with\n\t\t// a localized default provided by the plugin.\n\t\tif ( titles[ style.title ] ) {\n\t\t\tstyle.title = titles[ style.title ];\n\t\t}\n\t}\n\n\treturn styles;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module widget/widgettoolbarrepository\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ContextualBalloon from '@ckeditor/ckeditor5-ui/src/panel/balloon/contextualballoon';\nimport ToolbarView from '@ckeditor/ckeditor5-ui/src/toolbar/toolbarview';\nimport BalloonPanelView from '@ckeditor/ckeditor5-ui/src/panel/balloon/balloonpanelview';\nimport {\n\tisWidget,\n\tcenteredBalloonPositionForLongWidgets\n} from './utils';\nimport CKEditorError, { logWarning } from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Widget toolbar repository plugin. A central point for registering widget toolbars. This plugin handles the whole\n * toolbar rendering process and exposes a concise API.\n *\n * To add a toolbar for your widget use the {@link ~WidgetToolbarRepository#register `WidgetToolbarRepository#register()`} method.\n *\n * The following example comes from the {@link module:image/imagetoolbar~ImageToolbar} plugin:\n *\n * \t\tclass ImageToolbar extends Plugin {\n *\t\t\tstatic get requires() {\n *\t\t\t\treturn [ WidgetToolbarRepository ];\n *\t\t\t}\n *\n *\t\t\tafterInit() {\n *\t\t\t\tconst editor = this.editor;\n *\t\t\t\tconst widgetToolbarRepository = editor.plugins.get( WidgetToolbarRepository );\n *\n *\t\t\t\twidgetToolbarRepository.register( 'image', {\n *\t\t\t\t\titems: editor.config.get( 'image.toolbar' ),\n *\t\t\t\t\tgetRelatedElement: getSelectedImageWidget\n *\t\t\t\t} );\n *\t\t\t}\n *\t\t}\n */\nexport default class WidgetToolbarRepository extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ContextualBalloon ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'WidgetToolbarRepository';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Disables the default balloon toolbar for all widgets.\n\t\tif ( editor.plugins.has( 'BalloonToolbar' ) ) {\n\t\t\tconst balloonToolbar = editor.plugins.get( 'BalloonToolbar' );\n\n\t\t\tthis.listenTo( balloonToolbar, 'show', evt => {\n\t\t\t\tif ( isWidgetSelected( editor.editing.view.document.selection ) ) {\n\t\t\t\t\tevt.stop();\n\t\t\t\t}\n\t\t\t}, { priority: 'high' } );\n\t\t}\n\n\t\t/**\n\t\t * A map of toolbar definitions.\n\t\t *\n\t\t * @protected\n\t\t * @member {Map.<String,module:widget/widgettoolbarrepository~WidgetRepositoryToolbarDefinition>} #_toolbarDefinitions\n\t\t */\n\t\tthis._toolbarDefinitions = new Map();\n\n\t\t/**\n\t\t * @private\n\t\t */\n\t\tthis._balloon = this.editor.plugins.get( 'ContextualBalloon' );\n\n\t\tthis.on( 'change:isEnabled', () => {\n\t\t\tthis._updateToolbarsVisibility();\n\t\t} );\n\n\t\tthis.listenTo( editor.ui, 'update', () => {\n\t\t\tthis._updateToolbarsVisibility();\n\t\t} );\n\n\t\t// UI#update is not fired after focus is back in editor, we need to check if balloon panel should be visible.\n\t\tthis.listenTo( editor.ui.focusTracker, 'change:isFocused', () => {\n\t\t\tthis._updateToolbarsVisibility();\n\t\t}, { priority: 'low' } );\n\t}\n\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tfor ( const toolbarConfig of this._toolbarDefinitions.values() ) {\n\t\t\ttoolbarConfig.view.destroy();\n\t\t}\n\t}\n\n\t/**\n\t * Registers toolbar in the WidgetToolbarRepository. It renders it in the `ContextualBalloon` based on the value of the invoked\n\t * `getRelatedElement` function. Toolbar items are gathered from `items` array.\n\t * The balloon's CSS class is by default `ck-toolbar-container` and may be override with the `balloonClassName` option.\n\t *\n\t * Note: This method should be called in the {@link module:core/plugin~PluginInterface#afterInit `Plugin#afterInit()`}\n\t * callback (or later) to make sure that the given toolbar items were already registered by other plugins.\n\t *\n\t * @param {String} toolbarId An id for the toolbar. Used to\n\t * @param {Object} options\n\t * @param {String} [options.ariaLabel] Label used by assistive technologies to describe this toolbar element.\n\t * @param {Array.<String>} options.items Array of toolbar items.\n\t * @param {Function} options.getRelatedElement Callback which returns an element the toolbar should be attached to.\n\t * @param {String} [options.balloonClassName='ck-toolbar-container'] CSS class for the widget balloon.\n\t */\n\tregister( toolbarId, { ariaLabel, items, getRelatedElement, balloonClassName = 'ck-toolbar-container' } ) {\n\t\t// Trying to register a toolbar without any item.\n\t\tif ( !items.length ) {\n\t\t\t/**\n\t\t\t * When {@link #register} a new toolbar, you need to provide a non-empty array with\n\t\t\t * the items that will be inserted into the toolbar.\n\t\t\t *\n\t\t\t * @error widget-toolbar-no-items\n\t\t\t */\n\t\t\tlogWarning( 'widget-toolbar-no-items', { toolbarId } );\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\t\tconst toolbarView = new ToolbarView( editor.locale );\n\n\t\ttoolbarView.ariaLabel = ariaLabel || t( 'Widget toolbar' );\n\n\t\tif ( this._toolbarDefinitions.has( toolbarId ) ) {\n\t\t\t/**\n\t\t\t * Toolbar with the given id was already added.\n\t\t\t *\n\t\t\t * @error widget-toolbar-duplicated\n\t\t\t * @param toolbarId Toolbar id.\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'widget-toolbar-duplicated', this, { toolbarId } );\n\t\t}\n\n\t\ttoolbarView.fillFromConfig( items, editor.ui.componentFactory );\n\n\t\tthis._toolbarDefinitions.set( toolbarId, {\n\t\t\tview: toolbarView,\n\t\t\tgetRelatedElement,\n\t\t\tballoonClassName\n\t\t} );\n\t}\n\n\t/**\n\t * Iterates over stored toolbars and makes them visible or hidden.\n\t *\n\t * @private\n\t */\n\t_updateToolbarsVisibility() {\n\t\tlet maxRelatedElementDepth = 0;\n\t\tlet deepestRelatedElement = null;\n\t\tlet deepestToolbarDefinition = null;\n\n\t\tfor ( const definition of this._toolbarDefinitions.values() ) {\n\t\t\tconst relatedElement = definition.getRelatedElement( this.editor.editing.view.document.selection );\n\n\t\t\tif ( !this.isEnabled || !relatedElement ) {\n\t\t\t\tif ( this._isToolbarInBalloon( definition ) ) {\n\t\t\t\t\tthis._hideToolbar( definition );\n\t\t\t\t}\n\t\t\t} else if ( !this.editor.ui.focusTracker.isFocused ) {\n\t\t\t\tif ( this._isToolbarVisible( definition ) ) {\n\t\t\t\t\tthis._hideToolbar( definition );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst relatedElementDepth = relatedElement.getAncestors().length;\n\n\t\t\t\t// Many toolbars can express willingness to be displayed but they do not know about\n\t\t\t\t// each other. Figure out which toolbar is deepest in the view tree to decide which\n\t\t\t\t// should be displayed. For instance, if a selected image is inside a table cell, display\n\t\t\t\t// the ImageToolbar rather than the TableToolbar (#60).\n\t\t\t\tif ( relatedElementDepth > maxRelatedElementDepth ) {\n\t\t\t\t\tmaxRelatedElementDepth = relatedElementDepth;\n\t\t\t\t\tdeepestRelatedElement = relatedElement;\n\t\t\t\t\tdeepestToolbarDefinition = definition;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( deepestToolbarDefinition ) {\n\t\t\tthis._showToolbar( deepestToolbarDefinition, deepestRelatedElement );\n\t\t}\n\t}\n\n\t/**\n\t * Hides the given toolbar.\n\t *\n\t * @private\n\t * @param {module:widget/widgettoolbarrepository~WidgetRepositoryToolbarDefinition} toolbarDefinition\n\t */\n\t_hideToolbar( toolbarDefinition ) {\n\t\tthis._balloon.remove( toolbarDefinition.view );\n\t\tthis.stopListening( this._balloon, 'change:visibleView' );\n\t}\n\n\t/**\n\t * Shows up the toolbar if the toolbar is not visible.\n\t * Otherwise, repositions the toolbar's balloon when toolbar's view is the most top view in balloon stack.\n\t *\n\t * It might happen here that the toolbar's view is under another view. Then do nothing as the other toolbar view\n\t * should be still visible after the {@link module:core/editor/editorui~EditorUI#event:update}.\n\t *\n\t * @private\n\t * @param {module:widget/widgettoolbarrepository~WidgetRepositoryToolbarDefinition} toolbarDefinition\n\t * @param {module:engine/view/element~Element} relatedElement\n\t */\n\t_showToolbar( toolbarDefinition, relatedElement ) {\n\t\tif ( this._isToolbarVisible( toolbarDefinition ) ) {\n\t\t\trepositionContextualBalloon( this.editor, relatedElement );\n\t\t} else if ( !this._isToolbarInBalloon( toolbarDefinition ) ) {\n\t\t\tthis._balloon.add( {\n\t\t\t\tview: toolbarDefinition.view,\n\t\t\t\tposition: getBalloonPositionData( this.editor, relatedElement ),\n\t\t\t\tballoonClassName: toolbarDefinition.balloonClassName\n\t\t\t} );\n\n\t\t\t// Update toolbar position each time stack with toolbar view is switched to visible.\n\t\t\t// This is in a case target element has changed when toolbar was in invisible stack\n\t\t\t// e.g. target image was wrapped by a block quote.\n\t\t\t// See https://github.com/ckeditor/ckeditor5-widget/issues/92.\n\t\t\tthis.listenTo( this._balloon, 'change:visibleView', () => {\n\t\t\t\tfor ( const definition of this._toolbarDefinitions.values() ) {\n\t\t\t\t\tif ( this._isToolbarVisible( definition ) ) {\n\t\t\t\t\t\tconst relatedElement = definition.getRelatedElement( this.editor.editing.view.document.selection );\n\t\t\t\t\t\trepositionContextualBalloon( this.editor, relatedElement );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * @private\n\t * @param {Object} toolbar\n\t * @returns {Boolean}\n\t */\n\t_isToolbarVisible( toolbar ) {\n\t\treturn this._balloon.visibleView === toolbar.view;\n\t}\n\n\t/**\n\t * @private\n\t * @param {Object} toolbar\n\t * @returns {Boolean}\n\t */\n\t_isToolbarInBalloon( toolbar ) {\n\t\treturn this._balloon.hasView( toolbar.view );\n\t}\n}\n\nfunction repositionContextualBalloon( editor, relatedElement ) {\n\tconst balloon = editor.plugins.get( 'ContextualBalloon' );\n\tconst position = getBalloonPositionData( editor, relatedElement );\n\n\tballoon.updatePosition( position );\n}\n\nfunction getBalloonPositionData( editor, relatedElement ) {\n\tconst editingView = editor.editing.view;\n\tconst defaultPositions = BalloonPanelView.defaultPositions;\n\n\treturn {\n\t\ttarget: editingView.domConverter.mapViewToDom( relatedElement ),\n\t\tpositions: [\n\t\t\tdefaultPositions.northArrowSouth,\n\t\t\tdefaultPositions.northArrowSouthWest,\n\t\t\tdefaultPositions.northArrowSouthEast,\n\t\t\tdefaultPositions.southArrowNorth,\n\t\t\tdefaultPositions.southArrowNorthWest,\n\t\t\tdefaultPositions.southArrowNorthEast,\n\t\t\tcenteredBalloonPositionForLongWidgets\n\t\t]\n\t};\n}\n\nfunction isWidgetSelected( selection ) {\n\tconst viewElement = selection.getSelectedElement();\n\n\treturn !!( viewElement && isWidget( viewElement ) );\n}\n\n/**\n * The toolbar definition object used by the toolbar repository to manage toolbars.\n * It contains information necessary to display the toolbar in the\n * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon} and\n * update it during its life (display) cycle.\n *\n * @typedef {Object} module:widget/widgettoolbarrepository~WidgetRepositoryToolbarDefinition\n *\n * @property {module:ui/view~View} view The UI view of the toolbar.\n * @property {Function} getRelatedElement A function that returns an engine {@link module:engine/view/view~View}\n * element the toolbar is to be attached to. For instance, an image widget or a table widget (or `null` when\n * there is no such element). The function accepts an instance of {@link module:engine/view/selection~Selection}.\n * @property {String} balloonClassName CSS class for the widget balloon when a toolbar is displayed.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport Command from './command';\n\n/**\n * @module core/multicommand\n */\n\n/**\n * A CKEditor command that aggregates other commands.\n *\n * This command is used to proxy multiple commands. The multi-command is enabled when\n * at least one of its registered child commands is enabled.\n * When executing a multi-command the first command that is enabled will be executed.\n *\n *\t\tconst multiCommand = new MultiCommand( editor );\n *\n *\t\tconst commandFoo = new Command( editor );\n *\t\tconst commandBar = new Command( editor );\n *\n *\t\t// Register child commands.\n *\t\tmultiCommand.registerChildCommand( commandFoo );\n *\t\tmultiCommand.registerChildCommand( commandBar );\n *\n *\t\t// Enable one of the commands.\n *\t\tcommandBar.isEnabled = true;\n *\n *\t\tmultiCommand.execute(); // Will execute commandBar.\n *\n * @extends module:core/command~Command\n */\nexport default class MultiCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * Registered child commands.\n\t\t *\n\t\t * @type {Array.<module:core/command~Command>}\n\t\t * @private\n\t\t */\n\t\tthis._childCommands = [];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\t// Override base command refresh(): the command's state is changed when one of child commands changes states.\n\t}\n\n\t/**\n\t * Executes the first of it registered child commands.\n\t *\n\t * @returns {*} The value returned by the {@link module:core/command~Command#execute `command.execute()`}.\n\t */\n\texecute( ...args ) {\n\t\tconst command = this._getFirstEnabledCommand();\n\n\t\treturn command.execute( args );\n\t}\n\n\t/**\n\t * Registers a child command.\n\t *\n\t * @param {module:core/command~Command} command\n\t */\n\tregisterChildCommand( command ) {\n\t\tthis._childCommands.push( command );\n\n\t\t// Change multi command enabled state when one of registered commands changes state.\n\t\tcommand.on( 'change:isEnabled', () => this._checkEnabled() );\n\n\t\tthis._checkEnabled();\n\t}\n\n\t/**\n\t * Checks if any of child commands is enabled.\n\t *\n\t * @private\n\t */\n\t_checkEnabled() {\n\t\tthis.isEnabled = !!this._getFirstEnabledCommand();\n\t}\n\n\t/**\n\t * Returns a first enabled command or undefined if none of them is enabled.\n\t *\n\t * @returns {module:core/command~Command|undefined}\n\t * @private\n\t */\n\t_getFirstEnabledCommand() {\n\t\treturn this._childCommands.find( command => command.isEnabled );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module indent/indentediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport MultiCommand from '@ckeditor/ckeditor5-core/src/multicommand';\n\n/**\n * The indent editing feature.\n *\n * This plugin registers the `'indent'` and `'outdent'` commands.\n *\n * **Note**: In order for the commands to work, at least one of the compatible features is required. Read more in the\n * {@link module:indent/indent~Indent indent feature} API documentation.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class IndentEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'IndentEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\teditor.commands.add( 'indent', new MultiCommand( editor ) );\n\t\teditor.commands.add( 'outdent', new MultiCommand( editor ) );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm5 6c0 .414.336.75.75.75h9.5a.75.75 0 1 0 0-1.5h-9.5a.75.75 0 0 0-.75.75zM2.75 16.5h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 1 0 0 1.5zM1.632 6.95L5.02 9.358a.4.4 0 0 1-.013.661l-3.39 2.207A.4.4 0 0 1 1 11.892V7.275a.4.4 0 0 1 .632-.326z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm5 6c0 .414.336.75.75.75h9.5a.75.75 0 1 0 0-1.5h-9.5a.75.75 0 0 0-.75.75zM2.75 16.5h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 1 0 0 1.5zm1.618-9.55L.98 9.358a.4.4 0 0 0 .013.661l3.39 2.207A.4.4 0 0 0 5 11.892V7.275a.4.4 0 0 0-.632-.326z\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module indent/indentui\n */\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport indentIcon from '../theme/icons/indent.svg';\nimport outdentIcon from '../theme/icons/outdent.svg';\n\n/**\n * The indent UI feature.\n *\n * This plugin registers the `'indent'` and `'outdent'` buttons.\n *\n * **Note**: In order for the commands to work, at least one of the compatible features is required. Read more in\n * the {@link module:indent/indent~Indent indent feature} API documentation.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class IndentUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'IndentUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst locale = editor.locale;\n\t\tconst t = editor.t;\n\n\t\tconst localizedIndentIcon = locale.uiLanguageDirection == 'ltr' ? indentIcon : outdentIcon;\n\t\tconst localizedOutdentIcon = locale.uiLanguageDirection == 'ltr' ? outdentIcon : indentIcon;\n\n\t\tthis._defineButton( 'indent', t( 'Increase indent' ), localizedIndentIcon );\n\t\tthis._defineButton( 'outdent', t( 'Decrease indent' ), localizedOutdentIcon );\n\t}\n\n\t/**\n\t * Defines a UI button.\n\t *\n\t * @param {String} commandName\n\t * @param {String} label\n\t * @param {String} icon\n\t * @private\n\t */\n\t_defineButton( commandName, label, icon ) {\n\t\tconst editor = this.editor;\n\n\t\teditor.ui.componentFactory.add( commandName, locale => {\n\t\t\tconst command = editor.commands.get( commandName );\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel,\n\t\t\t\ticon,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );\n\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\teditor.execute( commandName );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","\n/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/observer/clickobserver\n */\n\nimport DomEventObserver from './domeventobserver';\n\n/**\n * {@link module:engine/view/document~Document#event:click Click} event observer.\n *\n * Note that this observer is not available by default. To make it available it needs to be added to\n * {@link module:engine/view/view~View view controller}\n * by a {@link module:engine/view/view~View#addObserver} method.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class ClickObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = 'click';\n\t}\n\n\tonDomEvent( domEvent ) {\n\t\tthis.fire( domEvent.type, domEvent );\n\t}\n}\n\n/**\n * Fired when one of the editables has been clicked.\n *\n * Introduced by {@link module:engine/view/observer/clickobserver~ClickObserver}.\n *\n * Note that this event is not available by default. To make it available\n * {@link module:engine/view/observer/clickobserver~ClickObserver} needs to be added\n * to {@link module:engine/view/view~View} by a {@link module:engine/view/view~View#addObserver} method.\n *\n * @see module:engine/view/observer/clickobserver~ClickObserver\n * @event module:engine/view/document~Document#event:click\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module link/ui/linkformview\n */\n\nimport View from '@ckeditor/ckeditor5-ui/src/view';\nimport ViewCollection from '@ckeditor/ckeditor5-ui/src/viewcollection';\n\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport SwitchButtonView from '@ckeditor/ckeditor5-ui/src/button/switchbuttonview';\n\nimport LabeledFieldView from '@ckeditor/ckeditor5-ui/src/labeledfield/labeledfieldview';\nimport { createLabeledInputText } from '@ckeditor/ckeditor5-ui/src/labeledfield/utils';\nimport injectCssTransitionDisabler from '@ckeditor/ckeditor5-ui/src/bindings/injectcsstransitiondisabler';\n\nimport submitHandler from '@ckeditor/ckeditor5-ui/src/bindings/submithandler';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport FocusCycler from '@ckeditor/ckeditor5-ui/src/focuscycler';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\n\nimport checkIcon from '@ckeditor/ckeditor5-core/theme/icons/check.svg';\nimport cancelIcon from '@ckeditor/ckeditor5-core/theme/icons/cancel.svg';\nimport '../../theme/linkform.css';\nimport '@ckeditor/ckeditor5-ui/theme/components/responsive-form/responsiveform.css';\n\n/**\n * The link form view controller class.\n *\n * See {@link module:link/ui/linkformview~LinkFormView}.\n *\n * @extends module:ui/view~View\n */\nexport default class LinkFormView extends View {\n\t/**\n\t * Creates an instance of the {@link module:link/ui/linkformview~LinkFormView} class.\n\t *\n\t * Also see {@link #render}.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The localization services instance.\n\t * @param {module:link/linkcommand~LinkCommand} linkCommand Reference to {@link module:link/linkcommand~LinkCommand}.\n\t * @param {String} [protocol] A value of a protocol to be displayed in the input's placeholder.\n\t */\n\tconstructor( locale, linkCommand ) {\n\t\tsuper( locale );\n\n\t\tconst t = locale.t;\n\n\t\t/**\n\t\t * Tracks information about DOM focus in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * The URL input view.\n\t\t *\n\t\t * @member {module:ui/labeledfield/labeledfieldview~LabeledFieldView}\n\t\t */\n\t\tthis.urlInputView = this._createUrlInput();\n\n\t\t/**\n\t\t * The Save button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.saveButtonView = this._createButton( t( 'Save' ), checkIcon, 'ck-button-save' );\n\t\tthis.saveButtonView.type = 'submit';\n\n\t\t/**\n\t\t * The Cancel button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.cancelButtonView = this._createButton( t( 'Cancel' ), cancelIcon, 'ck-button-cancel', 'cancel' );\n\n\t\t/**\n\t\t * A collection of {@link module:ui/button/switchbuttonview~SwitchButtonView},\n\t\t * which corresponds to {@link module:link/linkcommand~LinkCommand#manualDecorators manual decorators}\n\t\t * configured in the editor.\n\t\t *\n\t\t * @private\n\t\t * @readonly\n\t\t * @type {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis._manualDecoratorSwitches = this._createManualDecoratorSwitches( linkCommand );\n\n\t\t/**\n\t\t * A collection of child views in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this._createFormChildren( linkCommand.manualDecorators );\n\n\t\t/**\n\t\t * A collection of views that can be focused in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis._focusables = new ViewCollection();\n\n\t\t/**\n\t\t * Helps cycling over {@link #_focusables} in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this._focusables,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate form fields backwards using the Shift + Tab keystroke.\n\t\t\t\tfocusPrevious: 'shift + tab',\n\n\t\t\t\t// Navigate form fields forwards using the Tab key.\n\t\t\t\tfocusNext: 'tab'\n\t\t\t}\n\t\t} );\n\n\t\tconst classList = [ 'ck', 'ck-link-form', 'ck-responsive-form' ];\n\n\t\tif ( linkCommand.manualDecorators.length ) {\n\t\t\tclassList.push( 'ck-link-form_layout-vertical', 'ck-vertical-form' );\n\t\t}\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'form',\n\n\t\t\tattributes: {\n\t\t\t\tclass: classList,\n\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-link/issues/90\n\t\t\t\ttabindex: '-1'\n\t\t\t},\n\n\t\t\tchildren: this.children\n\t\t} );\n\n\t\tinjectCssTransitionDisabler( this );\n\t}\n\n\t/**\n\t * Obtains the state of the {@link module:ui/button/switchbuttonview~SwitchButtonView switch buttons} representing\n\t * {@link module:link/linkcommand~LinkCommand#manualDecorators manual link decorators}\n\t * in the {@link module:link/ui/linkformview~LinkFormView}.\n\t *\n\t * @returns {Object.<String,Boolean>} Key-value pairs, where the key is the name of the decorator and the value is\n\t * its state.\n\t */\n\tgetDecoratorSwitchesState() {\n\t\treturn Array.from( this._manualDecoratorSwitches ).reduce( ( accumulator, switchButton ) => {\n\t\t\taccumulator[ switchButton.name ] = switchButton.isOn;\n\t\t\treturn accumulator;\n\t\t}, {} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tsubmitHandler( {\n\t\t\tview: this\n\t\t} );\n\n\t\tconst childViews = [\n\t\t\tthis.urlInputView,\n\t\t\t...this._manualDecoratorSwitches,\n\t\t\tthis.saveButtonView,\n\t\t\tthis.cancelButtonView\n\t\t];\n\n\t\tchildViews.forEach( v => {\n\t\t\t// Register the view as focusable.\n\t\t\tthis._focusables.add( v );\n\n\t\t\t// Register the view in the focus tracker.\n\t\t\tthis.focusTracker.add( v.element );\n\t\t} );\n\n\t\t// Start listening for the keystrokes coming from #element.\n\t\tthis.keystrokes.listenTo( this.element );\n\t}\n\n\t/**\n\t * Focuses the fist {@link #_focusables} in the form.\n\t */\n\tfocus() {\n\t\tthis._focusCycler.focusFirst();\n\t}\n\n\t/**\n\t * Creates a labeled input view.\n\t *\n\t * @private\n\t * @returns {module:ui/labeledfield/labeledfieldview~LabeledFieldView} Labeled field view instance.\n\t */\n\t_createUrlInput() {\n\t\tconst t = this.locale.t;\n\t\tconst labeledInput = new LabeledFieldView( this.locale, createLabeledInputText );\n\n\t\tlabeledInput.label = t( 'Link URL' );\n\n\t\treturn labeledInput;\n\t}\n\n\t/**\n\t * Creates a button view.\n\t *\n\t * @private\n\t * @param {String} label The button label.\n\t * @param {String} icon The button icon.\n\t * @param {String} className The additional button CSS class name.\n\t * @param {String} [eventName] An event name that the `ButtonView#execute` event will be delegated to.\n\t * @returns {module:ui/button/buttonview~ButtonView} The button view instance.\n\t */\n\t_createButton( label, icon, className, eventName ) {\n\t\tconst button = new ButtonView( this.locale );\n\n\t\tbutton.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true\n\t\t} );\n\n\t\tbutton.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: className\n\t\t\t}\n\t\t} );\n\n\t\tif ( eventName ) {\n\t\t\tbutton.delegate( 'execute' ).to( this, eventName );\n\t\t}\n\n\t\treturn button;\n\t}\n\n\t/**\n\t * Populates {@link module:ui/viewcollection~ViewCollection} of {@link module:ui/button/switchbuttonview~SwitchButtonView}\n\t * made based on {@link module:link/linkcommand~LinkCommand#manualDecorators}.\n\t *\n\t * @private\n\t * @param {module:link/linkcommand~LinkCommand} linkCommand A reference to the link command.\n\t * @returns {module:ui/viewcollection~ViewCollection} of switch buttons.\n\t */\n\t_createManualDecoratorSwitches( linkCommand ) {\n\t\tconst switches = this.createCollection();\n\n\t\tfor ( const manualDecorator of linkCommand.manualDecorators ) {\n\t\t\tconst switchButton = new SwitchButtonView( this.locale );\n\n\t\t\tswitchButton.set( {\n\t\t\t\tname: manualDecorator.id,\n\t\t\t\tlabel: manualDecorator.label,\n\t\t\t\twithText: true\n\t\t\t} );\n\n\t\t\tswitchButton.bind( 'isOn' ).toMany( [ manualDecorator, linkCommand ], 'value', ( decoratorValue, commandValue ) => {\n\t\t\t\treturn commandValue === undefined && decoratorValue === undefined ? manualDecorator.defaultValue : decoratorValue;\n\t\t\t} );\n\n\t\t\tswitchButton.on( 'execute', () => {\n\t\t\t\tmanualDecorator.set( 'value', !switchButton.isOn );\n\t\t\t} );\n\n\t\t\tswitches.add( switchButton );\n\t\t}\n\n\t\treturn switches;\n\t}\n\n\t/**\n\t * Populates the {@link #children} collection of the form.\n\t *\n\t * If {@link module:link/linkcommand~LinkCommand#manualDecorators manual decorators} are configured in the editor, it creates an\n\t * additional `View` wrapping all {@link #_manualDecoratorSwitches} switch buttons corresponding\n\t * to these decorators.\n\t *\n\t * @private\n\t * @param {module:utils/collection~Collection} manualDecorators A reference to\n\t * the collection of manual decorators stored in the link command.\n\t * @returns {module:ui/viewcollection~ViewCollection} The children of link form view.\n\t */\n\t_createFormChildren( manualDecorators ) {\n\t\tconst children = this.createCollection();\n\n\t\tchildren.add( this.urlInputView );\n\n\t\tif ( manualDecorators.length ) {\n\t\t\tconst additionalButtonsView = new View();\n\n\t\t\tadditionalButtonsView.setTemplate( {\n\t\t\t\ttag: 'ul',\n\t\t\t\tchildren: this._manualDecoratorSwitches.map( switchButton => ( {\n\t\t\t\t\ttag: 'li',\n\t\t\t\t\tchildren: [ switchButton ],\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [\n\t\t\t\t\t\t\t'ck',\n\t\t\t\t\t\t\t'ck-list__item'\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t} ) ),\n\t\t\t\tattributes: {\n\t\t\t\t\tclass: [\n\t\t\t\t\t\t'ck',\n\t\t\t\t\t\t'ck-reset',\n\t\t\t\t\t\t'ck-list'\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t} );\n\t\t\tchildren.add( additionalButtonsView );\n\t\t}\n\n\t\tchildren.add( this.saveButtonView );\n\t\tchildren.add( this.cancelButtonView );\n\n\t\treturn children;\n\t}\n}\n\n/**\n * Fired when the form view is submitted (when one of the children triggered the submit event),\n * for example with a click on {@link #saveButtonView}.\n *\n * @event submit\n */\n\n/**\n * Fired when the form view is canceled, for example with a click on {@link #cancelButtonView}.\n *\n * @event cancel\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module link/ui/linkactionsview\n */\n\nimport View from '@ckeditor/ckeditor5-ui/src/view';\nimport ViewCollection from '@ckeditor/ckeditor5-ui/src/viewcollection';\n\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\n\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport FocusCycler from '@ckeditor/ckeditor5-ui/src/focuscycler';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\n\nimport { ensureSafeUrl } from '../utils';\n\nimport unlinkIcon from '../../theme/icons/unlink.svg';\nimport pencilIcon from '@ckeditor/ckeditor5-core/theme/icons/pencil.svg';\nimport '../../theme/linkactions.css';\nimport '@ckeditor/ckeditor5-ui/theme/components/responsive-form/responsiveform.css';\n\n/**\n * The link actions view class. This view displays the link preview, allows\n * unlinking or editing the link.\n *\n * @extends module:ui/view~View\n */\nexport default class LinkActionsView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst t = locale.t;\n\n\t\t/**\n\t\t * Tracks information about DOM focus in the actions.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * The href preview view.\n\t\t *\n\t\t * @member {module:ui/view~View}\n\t\t */\n\t\tthis.previewButtonView = this._createPreviewButton();\n\n\t\t/**\n\t\t * The unlink button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.unlinkButtonView = this._createButton( t( 'Unlink' ), unlinkIcon, 'unlink' );\n\n\t\t/**\n\t\t * The edit link button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.editButtonView = this._createButton( t( 'Edit link' ), pencilIcon, 'edit' );\n\n\t\t/**\n\t\t * The value of the \"href\" attribute of the link to use in the {@link #previewButtonView}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String}\n\t\t */\n\t\tthis.set( 'href' );\n\n\t\t/**\n\t\t * A collection of views that can be focused in the view.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis._focusables = new ViewCollection();\n\n\t\t/**\n\t\t * Helps cycling over {@link #_focusables} in the view.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this._focusables,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate fields backwards using the Shift + Tab keystroke.\n\t\t\t\tfocusPrevious: 'shift + tab',\n\n\t\t\t\t// Navigate fields forwards using the Tab key.\n\t\t\t\tfocusNext: 'tab'\n\t\t\t}\n\t\t} );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-link-actions',\n\t\t\t\t\t'ck-responsive-form'\n\t\t\t\t],\n\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-link/issues/90\n\t\t\t\ttabindex: '-1'\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\tthis.previewButtonView,\n\t\t\t\tthis.editButtonView,\n\t\t\t\tthis.unlinkButtonView\n\t\t\t]\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tconst childViews = [\n\t\t\tthis.previewButtonView,\n\t\t\tthis.editButtonView,\n\t\t\tthis.unlinkButtonView\n\t\t];\n\n\t\tchildViews.forEach( v => {\n\t\t\t// Register the view as focusable.\n\t\t\tthis._focusables.add( v );\n\n\t\t\t// Register the view in the focus tracker.\n\t\t\tthis.focusTracker.add( v.element );\n\t\t} );\n\n\t\t// Start listening for the keystrokes coming from #element.\n\t\tthis.keystrokes.listenTo( this.element );\n\t}\n\n\t/**\n\t * Focuses the fist {@link #_focusables} in the actions.\n\t */\n\tfocus() {\n\t\tthis._focusCycler.focusFirst();\n\t}\n\n\t/**\n\t * Creates a button view.\n\t *\n\t * @private\n\t * @param {String} label The button label.\n\t * @param {String} icon The button icon.\n\t * @param {String} [eventName] An event name that the `ButtonView#execute` event will be delegated to.\n\t * @returns {module:ui/button/buttonview~ButtonView} The button view instance.\n\t */\n\t_createButton( label, icon, eventName ) {\n\t\tconst button = new ButtonView( this.locale );\n\n\t\tbutton.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true\n\t\t} );\n\n\t\tbutton.delegate( 'execute' ).to( this, eventName );\n\n\t\treturn button;\n\t}\n\n\t/**\n\t * Creates a link href preview button.\n\t *\n\t * @private\n\t * @returns {module:ui/button/buttonview~ButtonView} The button view instance.\n\t */\n\t_createPreviewButton() {\n\t\tconst button = new ButtonView( this.locale );\n\t\tconst bind = this.bindTemplate;\n\t\tconst t = this.t;\n\n\t\tbutton.set( {\n\t\t\twithText: true,\n\t\t\ttooltip: t( 'Open link in new tab' )\n\t\t} );\n\n\t\tbutton.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-link-actions__preview'\n\t\t\t\t],\n\t\t\t\thref: bind.to( 'href', href => href && ensureSafeUrl( href ) ),\n\t\t\t\ttarget: '_blank',\n\t\t\t\trel: 'noopener noreferrer'\n\t\t\t}\n\t\t} );\n\n\t\tbutton.bind( 'label' ).to( this, 'href', href => {\n\t\t\treturn href || t( 'This link has no URL' );\n\t\t} );\n\n\t\tbutton.bind( 'isEnabled' ).to( this, 'href', href => !!href );\n\n\t\tbutton.template.tag = 'a';\n\t\tbutton.template.eventListeners = {};\n\n\t\treturn button;\n\t}\n}\n\n/**\n * Fired when the {@link #editButtonView} is clicked.\n *\n * @event edit\n */\n\n/**\n * Fired when the {@link #unlinkButtonView} is clicked.\n *\n * @event unlink\n */\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M11.077 15l.991-1.416a.75.75 0 1 1 1.229.86l-1.148 1.64a.748.748 0 0 1-.217.206 5.251 5.251 0 0 1-8.503-5.955.741.741 0 0 1 .12-.274l1.147-1.639a.75.75 0 1 1 1.228.86L4.933 10.7l.006.003a3.75 3.75 0 0 0 6.132 4.294l.006.004zm5.494-5.335a.748.748 0 0 1-.12.274l-1.147 1.639a.75.75 0 1 1-1.228-.86l.86-1.23a3.75 3.75 0 0 0-6.144-4.301l-.86 1.229a.75.75 0 0 1-1.229-.86l1.148-1.64a.748.748 0 0 1 .217-.206 5.251 5.251 0 0 1 8.503 5.955zm-4.563-2.532a.75.75 0 0 1 .184 1.045l-3.155 4.505a.75.75 0 1 1-1.229-.86l3.155-4.506a.75.75 0 0 1 1.045-.184zm4.919 10.562l-1.414 1.414a.75.75 0 1 1-1.06-1.06l1.414-1.415-1.415-1.414a.75.75 0 0 1 1.061-1.06l1.414 1.414 1.414-1.415a.75.75 0 0 1 1.061 1.061l-1.414 1.414 1.414 1.415a.75.75 0 0 1-1.06 1.06l-1.415-1.414z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M7.3 17.37l-.061.088a1.518 1.518 0 0 1-.934.535l-4.178.663-.806-4.153a1.495 1.495 0 0 1 .187-1.058l.056-.086L8.77 2.639c.958-1.351 2.803-1.076 4.296-.03 1.497 1.047 2.387 2.693 1.433 4.055L7.3 17.37zM9.14 4.728l-5.545 8.346 3.277 2.294 5.544-8.346L9.14 4.728zM6.07 16.512l-3.276-2.295.53 2.73 2.746-.435zM9.994 3.506L13.271 5.8c.316-.452-.16-1.333-1.065-1.966-.905-.634-1.895-.78-2.212-.328zM8 18.5L9.375 17H19v1.5H8z\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module link/linkui\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ClickObserver from '@ckeditor/ckeditor5-engine/src/view/observer/clickobserver';\nimport { addLinkProtocolIfApplicable, isLinkElement, LINK_KEYSTROKE } from './utils';\n\nimport ContextualBalloon from '@ckeditor/ckeditor5-ui/src/panel/balloon/contextualballoon';\n\nimport clickOutsideHandler from '@ckeditor/ckeditor5-ui/src/bindings/clickoutsidehandler';\n\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport LinkFormView from './ui/linkformview';\nimport LinkActionsView from './ui/linkactionsview';\n\nimport linkIcon from '../theme/icons/link.svg';\n\nconst VISUAL_SELECTION_MARKER_NAME = 'link-ui';\n\n/**\n * The link UI plugin. It introduces the `'link'` and `'unlink'` buttons and support for the <kbd>Ctrl+K</kbd> keystroke.\n *\n * It uses the\n * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon plugin}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class LinkUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ContextualBalloon ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'LinkUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\teditor.editing.view.addObserver( ClickObserver );\n\n\t\t/**\n\t\t * The actions view displayed inside of the balloon.\n\t\t *\n\t\t * @member {module:link/ui/linkactionsview~LinkActionsView}\n\t\t */\n\t\tthis.actionsView = this._createActionsView();\n\n\t\t/**\n\t\t * The form view displayed inside the balloon.\n\t\t *\n\t\t * @member {module:link/ui/linkformview~LinkFormView}\n\t\t */\n\t\tthis.formView = this._createFormView();\n\n\t\t/**\n\t\t * The contextual balloon plugin instance.\n\t\t *\n\t\t * @private\n\t\t * @member {module:ui/panel/balloon/contextualballoon~ContextualBalloon}\n\t\t */\n\t\tthis._balloon = editor.plugins.get( ContextualBalloon );\n\n\t\t// Create toolbar buttons.\n\t\tthis._createToolbarLinkButton();\n\n\t\t// Attach lifecycle actions to the the balloon.\n\t\tthis._enableUserBalloonInteractions();\n\n\t\t// Renders a fake visual selection marker on an expanded selection.\n\t\teditor.conversion.for( 'editingDowncast' ).markerToHighlight( {\n\t\t\tmodel: VISUAL_SELECTION_MARKER_NAME,\n\t\t\tview: {\n\t\t\t\tclasses: [ 'ck-fake-link-selection' ]\n\t\t\t}\n\t\t} );\n\n\t\t// Renders a fake visual selection marker on a collapsed selection.\n\t\teditor.conversion.for( 'editingDowncast' ).markerToElement( {\n\t\t\tmodel: VISUAL_SELECTION_MARKER_NAME,\n\t\t\tview: {\n\t\t\t\tname: 'span',\n\t\t\t\tclasses: [ 'ck-fake-link-selection', 'ck-fake-link-selection_collapsed' ]\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\t// Destroy created UI components as they are not automatically destroyed (see ckeditor5#1341).\n\t\tthis.formView.destroy();\n\t}\n\n\t/**\n\t * Creates the {@link module:link/ui/linkactionsview~LinkActionsView} instance.\n\t *\n\t * @private\n\t * @returns {module:link/ui/linkactionsview~LinkActionsView} The link actions view instance.\n\t */\n\t_createActionsView() {\n\t\tconst editor = this.editor;\n\t\tconst actionsView = new LinkActionsView( editor.locale );\n\t\tconst linkCommand = editor.commands.get( 'link' );\n\t\tconst unlinkCommand = editor.commands.get( 'unlink' );\n\n\t\tactionsView.bind( 'href' ).to( linkCommand, 'value' );\n\t\tactionsView.editButtonView.bind( 'isEnabled' ).to( linkCommand );\n\t\tactionsView.unlinkButtonView.bind( 'isEnabled' ).to( unlinkCommand );\n\n\t\t// Execute unlink command after clicking on the \"Edit\" button.\n\t\tthis.listenTo( actionsView, 'edit', () => {\n\t\t\tthis._addFormView();\n\t\t} );\n\n\t\t// Execute unlink command after clicking on the \"Unlink\" button.\n\t\tthis.listenTo( actionsView, 'unlink', () => {\n\t\t\teditor.execute( 'unlink' );\n\t\t\tthis._hideUI();\n\t\t} );\n\n\t\t// Close the panel on esc key press when the **actions have focus**.\n\t\tactionsView.keystrokes.set( 'Esc', ( data, cancel ) => {\n\t\t\tthis._hideUI();\n\t\t\tcancel();\n\t\t} );\n\n\t\t// Open the form view on Ctrl+K when the **actions have focus**..\n\t\tactionsView.keystrokes.set( LINK_KEYSTROKE, ( data, cancel ) => {\n\t\t\tthis._addFormView();\n\t\t\tcancel();\n\t\t} );\n\n\t\treturn actionsView;\n\t}\n\n\t/**\n\t * Creates the {@link module:link/ui/linkformview~LinkFormView} instance.\n\t *\n\t * @private\n\t * @returns {module:link/ui/linkformview~LinkFormView} The link form view instance.\n\t */\n\t_createFormView() {\n\t\tconst editor = this.editor;\n\t\tconst linkCommand = editor.commands.get( 'link' );\n\t\tconst defaultProtocol = editor.config.get( 'link.defaultProtocol' );\n\n\t\tconst formView = new LinkFormView( editor.locale, linkCommand );\n\n\t\tformView.urlInputView.fieldView.bind( 'value' ).to( linkCommand, 'value' );\n\n\t\t// Form elements should be read-only when corresponding commands are disabled.\n\t\tformView.urlInputView.bind( 'isReadOnly' ).to( linkCommand, 'isEnabled', value => !value );\n\t\tformView.saveButtonView.bind( 'isEnabled' ).to( linkCommand );\n\n\t\t// Execute link command after clicking the \"Save\" button.\n\t\tthis.listenTo( formView, 'submit', () => {\n\t\t\tconst { value } = formView.urlInputView.fieldView.element;\n\t\t\tconst parsedUrl = addLinkProtocolIfApplicable( value, defaultProtocol );\n\t\t\teditor.execute( 'link', parsedUrl, formView.getDecoratorSwitchesState() );\n\t\t\tthis._closeFormView();\n\t\t} );\n\n\t\t// Hide the panel after clicking the \"Cancel\" button.\n\t\tthis.listenTo( formView, 'cancel', () => {\n\t\t\tthis._closeFormView();\n\t\t} );\n\n\t\t// Close the panel on esc key press when the **form has focus**.\n\t\tformView.keystrokes.set( 'Esc', ( data, cancel ) => {\n\t\t\tthis._closeFormView();\n\t\t\tcancel();\n\t\t} );\n\n\t\treturn formView;\n\t}\n\n\t/**\n\t * Creates a toolbar Link button. Clicking this button will show\n\t * a {@link #_balloon} attached to the selection.\n\t *\n\t * @private\n\t */\n\t_createToolbarLinkButton() {\n\t\tconst editor = this.editor;\n\t\tconst linkCommand = editor.commands.get( 'link' );\n\t\tconst t = editor.t;\n\n\t\t// Handle the `Ctrl+K` keystroke and show the panel.\n\t\teditor.keystrokes.set( LINK_KEYSTROKE, ( keyEvtData, cancel ) => {\n\t\t\t// Prevent focusing the search bar in FF, Chrome and Edge. See https://github.com/ckeditor/ckeditor5/issues/4811.\n\t\t\tcancel();\n\n\t\t\tif ( linkCommand.isEnabled ) {\n\t\t\t\tthis._showUI( true );\n\t\t\t}\n\t\t} );\n\n\t\teditor.ui.componentFactory.add( 'link', locale => {\n\t\t\tconst button = new ButtonView( locale );\n\n\t\t\tbutton.isEnabled = true;\n\t\t\tbutton.label = t( 'Link' );\n\t\t\tbutton.icon = linkIcon;\n\t\t\tbutton.keystroke = LINK_KEYSTROKE;\n\t\t\tbutton.tooltip = true;\n\t\t\tbutton.isToggleable = true;\n\n\t\t\t// Bind button to the command.\n\t\t\tbutton.bind( 'isEnabled' ).to( linkCommand, 'isEnabled' );\n\t\t\tbutton.bind( 'isOn' ).to( linkCommand, 'value', value => !!value );\n\n\t\t\t// Show the panel on button click.\n\t\t\tthis.listenTo( button, 'execute', () => this._showUI( true ) );\n\n\t\t\treturn button;\n\t\t} );\n\t}\n\n\t/**\n\t * Attaches actions that control whether the balloon panel containing the\n\t * {@link #formView} is visible or not.\n\t *\n\t * @private\n\t */\n\t_enableUserBalloonInteractions() {\n\t\tconst viewDocument = this.editor.editing.view.document;\n\n\t\t// Handle click on view document and show panel when selection is placed inside the link element.\n\t\t// Keep panel open until selection will be inside the same link element.\n\t\tthis.listenTo( viewDocument, 'click', () => {\n\t\t\tconst parentLink = this._getSelectedLinkElement();\n\n\t\t\tif ( parentLink ) {\n\t\t\t\t// Then show panel but keep focus inside editor editable.\n\t\t\t\tthis._showUI();\n\t\t\t}\n\t\t} );\n\n\t\t// Focus the form if the balloon is visible and the Tab key has been pressed.\n\t\tthis.editor.keystrokes.set( 'Tab', ( data, cancel ) => {\n\t\t\tif ( this._areActionsVisible && !this.actionsView.focusTracker.isFocused ) {\n\t\t\t\tthis.actionsView.focus();\n\t\t\t\tcancel();\n\t\t\t}\n\t\t}, {\n\t\t\t// Use the high priority because the link UI navigation is more important\n\t\t\t// than other feature's actions, e.g. list indentation.\n\t\t\t// https://github.com/ckeditor/ckeditor5-link/issues/146\n\t\t\tpriority: 'high'\n\t\t} );\n\n\t\t// Close the panel on the Esc key press when the editable has focus and the balloon is visible.\n\t\tthis.editor.keystrokes.set( 'Esc', ( data, cancel ) => {\n\t\t\tif ( this._isUIVisible ) {\n\t\t\t\tthis._hideUI();\n\t\t\t\tcancel();\n\t\t\t}\n\t\t} );\n\n\t\t// Close on click outside of balloon panel element.\n\t\tclickOutsideHandler( {\n\t\t\temitter: this.formView,\n\t\t\tactivator: () => this._isUIInPanel,\n\t\t\tcontextElements: [ this._balloon.view.element ],\n\t\t\tcallback: () => this._hideUI()\n\t\t} );\n\t}\n\n\t/**\n\t * Adds the {@link #actionsView} to the {@link #_balloon}.\n\t *\n\t * @protected\n\t */\n\t_addActionsView() {\n\t\tif ( this._areActionsInPanel ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._balloon.add( {\n\t\t\tview: this.actionsView,\n\t\t\tposition: this._getBalloonPositionData()\n\t\t} );\n\t}\n\n\t/**\n\t * Adds the {@link #formView} to the {@link #_balloon}.\n\t *\n\t * @protected\n\t */\n\t_addFormView() {\n\t\tif ( this._isFormInPanel ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst editor = this.editor;\n\t\tconst linkCommand = editor.commands.get( 'link' );\n\n\t\tthis.formView.disableCssTransitions();\n\n\t\tthis._balloon.add( {\n\t\t\tview: this.formView,\n\t\t\tposition: this._getBalloonPositionData()\n\t\t} );\n\n\t\t// Select input when form view is currently visible.\n\t\tif ( this._balloon.visibleView === this.formView ) {\n\t\t\tthis.formView.urlInputView.fieldView.select();\n\t\t}\n\n\t\tthis.formView.enableCssTransitions();\n\n\t\t// Make sure that each time the panel shows up, the URL field remains in sync with the value of\n\t\t// the command. If the user typed in the input, then canceled the balloon (`urlInputView.fieldView#value` stays\n\t\t// unaltered) and re-opened it without changing the value of the link command (e.g. because they\n\t\t// clicked the same link), they would see the old value instead of the actual value of the command.\n\t\t// https://github.com/ckeditor/ckeditor5-link/issues/78\n\t\t// https://github.com/ckeditor/ckeditor5-link/issues/123\n\t\tthis.formView.urlInputView.fieldView.element.value = linkCommand.value || '';\n\t}\n\n\t/**\n\t * Closes the form view. Decides whether the balloon should be hidden completely or if the action view should be shown. This is\n\t * decided upon the link command value (which has a value if the document selection is in the link).\n\t *\n\t * Additionally, if any {@link module:link/link~LinkConfig#decorators} are defined in the editor configuration, the state of\n\t * switch buttons responsible for manual decorator handling is restored.\n\t *\n\t * @private\n\t */\n\t_closeFormView() {\n\t\tconst linkCommand = this.editor.commands.get( 'link' );\n\n\t\t// Restore manual decorator states to represent the current model state. This case is important to reset the switch buttons\n\t\t// when the user cancels the editing form.\n\t\tlinkCommand.restoreManualDecoratorStates();\n\n\t\tif ( linkCommand.value !== undefined ) {\n\t\t\tthis._removeFormView();\n\t\t} else {\n\t\t\tthis._hideUI();\n\t\t}\n\t}\n\n\t/**\n\t * Removes the {@link #formView} from the {@link #_balloon}.\n\t *\n\t * @protected\n\t */\n\t_removeFormView() {\n\t\tif ( this._isFormInPanel ) {\n\t\t\t// Blur the input element before removing it from DOM to prevent issues in some browsers.\n\t\t\t// See https://github.com/ckeditor/ckeditor5/issues/1501.\n\t\t\tthis.formView.saveButtonView.focus();\n\n\t\t\tthis._balloon.remove( this.formView );\n\n\t\t\t// Because the form has an input which has focus, the focus must be brought back\n\t\t\t// to the editor. Otherwise, it would be lost.\n\t\t\tthis.editor.editing.view.focus();\n\n\t\t\tthis._hideFakeVisualSelection();\n\t\t}\n\t}\n\n\t/**\n\t * Shows the correct UI type. It is either {@link #formView} or {@link #actionsView}.\n\t *\n\t * @param {Boolean} forceVisible\n\t * @private\n\t */\n\t_showUI( forceVisible = false ) {\n\t\t// When there's no link under the selection, go straight to the editing UI.\n\t\tif ( !this._getSelectedLinkElement() ) {\n\t\t\t// Show visual selection on a text without a link when the contextual balloon is displayed.\n\t\t\t// See https://github.com/ckeditor/ckeditor5/issues/4721.\n\t\t\tthis._showFakeVisualSelection();\n\n\t\t\tthis._addActionsView();\n\n\t\t\t// Be sure panel with link is visible.\n\t\t\tif ( forceVisible ) {\n\t\t\t\tthis._balloon.showStack( 'main' );\n\t\t\t}\n\n\t\t\tthis._addFormView();\n\t\t}\n\t\t// If there's a link under the selection...\n\t\telse {\n\t\t\t// Go to the editing UI if actions are already visible.\n\t\t\tif ( this._areActionsVisible ) {\n\t\t\t\tthis._addFormView();\n\t\t\t}\n\t\t\t// Otherwise display just the actions UI.\n\t\t\telse {\n\t\t\t\tthis._addActionsView();\n\t\t\t}\n\n\t\t\t// Be sure panel with link is visible.\n\t\t\tif ( forceVisible ) {\n\t\t\t\tthis._balloon.showStack( 'main' );\n\t\t\t}\n\t\t}\n\n\t\t// Begin responding to ui#update once the UI is added.\n\t\tthis._startUpdatingUI();\n\t}\n\n\t/**\n\t * Removes the {@link #formView} from the {@link #_balloon}.\n\t *\n\t * See {@link #_addFormView}, {@link #_addActionsView}.\n\t *\n\t * @protected\n\t */\n\t_hideUI() {\n\t\tif ( !this._isUIInPanel ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst editor = this.editor;\n\n\t\tthis.stopListening( editor.ui, 'update' );\n\t\tthis.stopListening( this._balloon, 'change:visibleView' );\n\n\t\t// Make sure the focus always gets back to the editable _before_ removing the focused form view.\n\t\t// Doing otherwise causes issues in some browsers. See https://github.com/ckeditor/ckeditor5-link/issues/193.\n\t\teditor.editing.view.focus();\n\n\t\t// Remove form first because it's on top of the stack.\n\t\tthis._removeFormView();\n\n\t\t// Then remove the actions view because it's beneath the form.\n\t\tthis._balloon.remove( this.actionsView );\n\n\t\tthis._hideFakeVisualSelection();\n\t}\n\n\t/**\n\t * Makes the UI react to the {@link module:core/editor/editorui~EditorUI#event:update} event to\n\t * reposition itself when the editor UI should be refreshed.\n\t *\n\t * See: {@link #_hideUI} to learn when the UI stops reacting to the `update` event.\n\t *\n\t * @protected\n\t */\n\t_startUpdatingUI() {\n\t\tconst editor = this.editor;\n\t\tconst viewDocument = editor.editing.view.document;\n\n\t\tlet prevSelectedLink = this._getSelectedLinkElement();\n\t\tlet prevSelectionParent = getSelectionParent();\n\n\t\tconst update = () => {\n\t\t\tconst selectedLink = this._getSelectedLinkElement();\n\t\t\tconst selectionParent = getSelectionParent();\n\n\t\t\t// Hide the panel if:\n\t\t\t//\n\t\t\t// * the selection went out of the EXISTING link element. E.g. user moved the caret out\n\t\t\t//   of the link,\n\t\t\t// * the selection went to a different parent when creating a NEW link. E.g. someone\n\t\t\t//   else modified the document.\n\t\t\t// * the selection has expanded (e.g. displaying link actions then pressing SHIFT+Right arrow).\n\t\t\t//\n\t\t\t// Note: #_getSelectedLinkElement will return a link for a non-collapsed selection only\n\t\t\t// when fully selected.\n\t\t\tif ( ( prevSelectedLink && !selectedLink ) ||\n\t\t\t\t( !prevSelectedLink && selectionParent !== prevSelectionParent ) ) {\n\t\t\t\tthis._hideUI();\n\t\t\t}\n\t\t\t// Update the position of the panel when:\n\t\t\t//  * link panel is in the visible stack\n\t\t\t//  * the selection remains in the original link element,\n\t\t\t//  * there was no link element in the first place, i.e. creating a new link\n\t\t\telse if ( this._isUIVisible ) {\n\t\t\t\t// If still in a link element, simply update the position of the balloon.\n\t\t\t\t// If there was no link (e.g. inserting one), the balloon must be moved\n\t\t\t\t// to the new position in the editing view (a new native DOM range).\n\t\t\t\tthis._balloon.updatePosition( this._getBalloonPositionData() );\n\t\t\t}\n\n\t\t\tprevSelectedLink = selectedLink;\n\t\t\tprevSelectionParent = selectionParent;\n\t\t};\n\n\t\tfunction getSelectionParent() {\n\t\t\treturn viewDocument.selection.focus.getAncestors()\n\t\t\t\t.reverse()\n\t\t\t\t.find( node => node.is( 'element' ) );\n\t\t}\n\n\t\tthis.listenTo( editor.ui, 'update', update );\n\t\tthis.listenTo( this._balloon, 'change:visibleView', update );\n\t}\n\n\t/**\n\t * Returns `true` when {@link #formView} is in the {@link #_balloon}.\n\t *\n\t * @readonly\n\t * @protected\n\t * @type {Boolean}\n\t */\n\tget _isFormInPanel() {\n\t\treturn this._balloon.hasView( this.formView );\n\t}\n\n\t/**\n\t * Returns `true` when {@link #actionsView} is in the {@link #_balloon}.\n\t *\n\t * @readonly\n\t * @protected\n\t * @type {Boolean}\n\t */\n\tget _areActionsInPanel() {\n\t\treturn this._balloon.hasView( this.actionsView );\n\t}\n\n\t/**\n\t * Returns `true` when {@link #actionsView} is in the {@link #_balloon} and it is\n\t * currently visible.\n\t *\n\t * @readonly\n\t * @protected\n\t * @type {Boolean}\n\t */\n\tget _areActionsVisible() {\n\t\treturn this._balloon.visibleView === this.actionsView;\n\t}\n\n\t/**\n\t * Returns `true` when {@link #actionsView} or {@link #formView} is in the {@link #_balloon}.\n\t *\n\t * @readonly\n\t * @protected\n\t * @type {Boolean}\n\t */\n\tget _isUIInPanel() {\n\t\treturn this._isFormInPanel || this._areActionsInPanel;\n\t}\n\n\t/**\n\t * Returns `true` when {@link #actionsView} or {@link #formView} is in the {@link #_balloon} and it is\n\t * currently visible.\n\t *\n\t * @readonly\n\t * @protected\n\t * @type {Boolean}\n\t */\n\tget _isUIVisible() {\n\t\tconst visibleView = this._balloon.visibleView;\n\n\t\treturn visibleView == this.formView || this._areActionsVisible;\n\t}\n\n\t/**\n\t * Returns positioning options for the {@link #_balloon}. They control the way the balloon is attached\n\t * to the target element or selection.\n\t *\n\t * If the selection is collapsed and inside a link element, the panel will be attached to the\n\t * entire link element. Otherwise, it will be attached to the selection.\n\t *\n\t * @private\n\t * @returns {module:utils/dom/position~Options}\n\t */\n\t_getBalloonPositionData() {\n\t\tconst view = this.editor.editing.view;\n\t\tconst model = this.editor.model;\n\t\tconst viewDocument = view.document;\n\t\tlet target = null;\n\n\t\tif ( model.markers.has( VISUAL_SELECTION_MARKER_NAME ) ) {\n\t\t\t// There are cases when we highlight selection using a marker (#7705, #4721).\n\t\t\tconst markerViewElements = Array.from( this.editor.editing.mapper.markerNameToElements( VISUAL_SELECTION_MARKER_NAME ) );\n\t\t\tconst newRange = view.createRange(\n\t\t\t\tview.createPositionBefore( markerViewElements[ 0 ] ),\n\t\t\t\tview.createPositionAfter( markerViewElements[ markerViewElements.length - 1 ] )\n\t\t\t);\n\n\t\t\ttarget = view.domConverter.viewRangeToDom( newRange );\n\t\t} else {\n\t\t\tconst targetLink = this._getSelectedLinkElement();\n\t\t\tconst range = viewDocument.selection.getFirstRange();\n\n\t\t\ttarget = targetLink ?\n\t\t\t\t// When selection is inside link element, then attach panel to this element.\n\t\t\t\tview.domConverter.mapViewToDom( targetLink ) :\n\t\t\t\t// Otherwise attach panel to the selection.\n\t\t\t\tview.domConverter.viewRangeToDom( range );\n\t\t}\n\n\t\treturn { target };\n\t}\n\n\t/**\n\t * Returns the link {@link module:engine/view/attributeelement~AttributeElement} under\n\t * the {@link module:engine/view/document~Document editing view's} selection or `null`\n\t * if there is none.\n\t *\n\t * **Note**: For a non–collapsed selection, the link element is only returned when **fully**\n\t * selected and the **only** element within the selection boundaries.\n\t *\n\t * @private\n\t * @returns {module:engine/view/attributeelement~AttributeElement|null}\n\t */\n\t_getSelectedLinkElement() {\n\t\tconst view = this.editor.editing.view;\n\t\tconst selection = view.document.selection;\n\n\t\tif ( selection.isCollapsed ) {\n\t\t\treturn findLinkElementAncestor( selection.getFirstPosition() );\n\t\t} else {\n\t\t\t// The range for fully selected link is usually anchored in adjacent text nodes.\n\t\t\t// Trim it to get closer to the actual link element.\n\t\t\tconst range = selection.getFirstRange().getTrimmed();\n\t\t\tconst startLink = findLinkElementAncestor( range.start );\n\t\t\tconst endLink = findLinkElementAncestor( range.end );\n\n\t\t\tif ( !startLink || startLink != endLink ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Check if the link element is fully selected.\n\t\t\tif ( view.createRangeIn( startLink ).getTrimmed().isEqual( range ) ) {\n\t\t\t\treturn startLink;\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Displays a fake visual selection when the contextual balloon is displayed.\n\t *\n\t * This adds a 'link-ui' marker into the document that is rendered as a highlight on selected text fragment.\n\t *\n\t * @private\n\t */\n\t_showFakeVisualSelection() {\n\t\tconst model = this.editor.model;\n\n\t\tmodel.change( writer => {\n\t\t\tconst range = model.document.selection.getFirstRange();\n\n\t\t\tif ( model.markers.has( VISUAL_SELECTION_MARKER_NAME ) ) {\n\t\t\t\twriter.updateMarker( VISUAL_SELECTION_MARKER_NAME, { range } );\n\t\t\t} else {\n\t\t\t\tif ( range.start.isAtEnd ) {\n\t\t\t\t\tconst focus = model.document.selection.focus;\n\t\t\t\t\tconst nextValidRange = getNextValidRange( range, focus, writer );\n\n\t\t\t\t\twriter.addMarker( VISUAL_SELECTION_MARKER_NAME, {\n\t\t\t\t\t\tusingOperation: false,\n\t\t\t\t\t\taffectsData: false,\n\t\t\t\t\t\trange: nextValidRange\n\t\t\t\t\t} );\n\t\t\t\t} else {\n\t\t\t\t\twriter.addMarker( VISUAL_SELECTION_MARKER_NAME, {\n\t\t\t\t\t\tusingOperation: false,\n\t\t\t\t\t\taffectsData: false,\n\t\t\t\t\t\trange\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Hides the fake visual selection created in {@link #_showFakeVisualSelection}.\n\t *\n\t * @private\n\t */\n\t_hideFakeVisualSelection() {\n\t\tconst model = this.editor.model;\n\n\t\tif ( model.markers.has( VISUAL_SELECTION_MARKER_NAME ) ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\twriter.removeMarker( VISUAL_SELECTION_MARKER_NAME );\n\t\t\t} );\n\t\t}\n\t}\n}\n\n// Returns a link element if there's one among the ancestors of the provided `Position`.\n//\n// @private\n// @param {module:engine/view/position~Position} View position to analyze.\n// @returns {module:engine/view/attributeelement~AttributeElement|null} Link element at the position or null.\nfunction findLinkElementAncestor( position ) {\n\treturn position.getAncestors().find( ancestor => isLinkElement( ancestor ) );\n}\n\n// Returns next valid range for the fake visual selection marker.\n//\n// @private\n// @param {module:engine/model/range~Range} range Current range.\n// @param {module:engine/model/position~Position} focus Selection focus.\n// @param {module:engine/model/writer~Writer} writer Writer.\n// @returns {module:engine/model/range~Range} New valid range for the fake visual selection marker.\nfunction getNextValidRange( range, focus, writer ) {\n\tconst nextStartPath = [ range.start.path[ 0 ] + 1, 0 ];\n\tconst nextStartPosition = writer.createPositionFromPath( range.start.root, nextStartPath, 'toNext' );\n\tconst nextRange = writer.createRange( nextStartPosition, range.end );\n\n\t// Block creating a potential next valid range over the current range end.\n\tif ( nextRange.start.path[ 0 ] > range.end.path[ 0 ] ) {\n\t\treturn writer.createRange( focus );\n\t}\n\n\tif ( nextStartPosition.isAtStart && nextStartPosition.isAtEnd ) {\n\t\treturn getNextValidRange( nextRange, focus, writer );\n\t}\n\n\treturn nextRange;\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M11.077 15l.991-1.416a.75.75 0 1 1 1.229.86l-1.148 1.64a.748.748 0 0 1-.217.206 5.251 5.251 0 0 1-8.503-5.955.741.741 0 0 1 .12-.274l1.147-1.639a.75.75 0 1 1 1.228.86L4.933 10.7l.006.003a3.75 3.75 0 0 0 6.132 4.294l.006.004zm5.494-5.335a.748.748 0 0 1-.12.274l-1.147 1.639a.75.75 0 1 1-1.228-.86l.86-1.23a3.75 3.75 0 0 0-6.144-4.301l-.86 1.229a.75.75 0 0 1-1.229-.86l1.148-1.64a.748.748 0 0 1 .217-.206 5.251 5.251 0 0 1 8.503 5.955zm-4.563-2.532a.75.75 0 0 1 .184 1.045l-3.155 4.505a.75.75 0 1 1-1.229-.86l3.155-4.506a.75.75 0 0 1 1.045-.184z\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/utils/getlasttextline\n */\n\n/**\n * Returns the last text line from the given range.\n *\n * \"The last text line\" is understood as text (from one or more text nodes) which is limited either by a parent block\n * or by inline elements (e.g. `<softBreak>`).\n *\n *\t\tconst rangeToCheck = model.createRange(\n *\t\t\tmodel.createPositionAt( paragraph, 0 ),\n *\t\t\tmodel.createPositionAt( paragraph, 'end' )\n *\t\t);\n *\n *\t\tconst { text, range } = getLastTextLine( rangeToCheck, model );\n *\n * For model below, the returned `text` will be \"Foo bar baz\" and `range` will be set on whole `<paragraph>` content:\n *\n *\t\t<paragraph>Foo bar baz<paragraph>\n *\n * However, in below case, `text` will be set to \"baz\" and `range` will be set only on \"baz\".\n *\n *\t\t<paragraph>Foo<softBreak></softBreak>bar<softBreak></softBreak>baz<paragraph>\n *\n * @protected\n * @param {module:engine/model/range~Range} range\n * @param {module:engine/model/model~Model} model\n * @returns {module:typing/utils/getlasttextline~LastTextLineData}\n */\nexport default function getLastTextLine( range, model ) {\n\tlet start = range.start;\n\n\tconst text = Array.from( range.getItems() ).reduce( ( rangeText, node ) => {\n\t\t// Trim text to a last occurrence of an inline element and update range start.\n\t\tif ( !( node.is( '$text' ) || node.is( '$textProxy' ) ) ) {\n\t\t\tstart = model.createPositionAfter( node );\n\n\t\t\treturn '';\n\t\t}\n\n\t\treturn rangeText + node.data;\n\t}, '' );\n\n\treturn { text, range: model.createRange( start, range.end ) };\n}\n\n/**\n * The value returned by {@link module:typing/utils/getlasttextline~getLastTextLine}.\n *\n * @typedef {Object} module:typing/utils/getlasttextline~LastTextLineData\n *\n * @property {String} text The text from the text nodes in the last text line.\n * @property {module:engine/model/range~Range} range The range set on the text nodes in the last text line.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/textwatcher\n */\n\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport getLastTextLine from './utils/getlasttextline';\n\n/**\n * The text watcher feature.\n *\n * Fires the {@link module:typing/textwatcher~TextWatcher#event:matched:data `matched:data`},\n * {@link module:typing/textwatcher~TextWatcher#event:matched:selection `matched:selection`} and\n * {@link module:typing/textwatcher~TextWatcher#event:unmatched `unmatched`} events on typing or selection changes.\n *\n * @private\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class TextWatcher {\n\t/**\n\t * Creates a text watcher instance.\n\t *\n\t * @param {module:engine/model/model~Model} model\n\t * @param {Function} testCallback See {@link module:typing/textwatcher~TextWatcher#testCallback}.\n\t */\n\tconstructor( model, testCallback ) {\n\t\t/**\n\t\t * The editor's model.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/model~Model}\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * The function used to match the text.\n\t\t *\n\t\t * The test callback can return 3 values:\n\t\t *\n\t\t * * `false` if there is no match,\n\t\t * * `true` if there is a match,\n\t\t * * an object if there is a match and we want to pass some additional information to the {@link #event:matched:data} event.\n\t\t *\n\t\t * @member {Function} #testCallback\n\t\t * @returns {Object} testResult\n\t\t */\n\t\tthis.testCallback = testCallback;\n\n\t\t/**\n\t\t * Whether there is a match currently.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis.hasMatch = false;\n\n\t\t/**\n\t\t * Flag indicating whether the `TextWatcher` instance is enabled or disabled.\n\t\t * A disabled TextWatcher will not evaluate text.\n\t\t *\n\t\t * To disable TextWatcher:\n\t\t *\n\t\t *\t\tconst watcher = new TextWatcher( editor.model, testCallback );\n\t\t *\n\t\t *\t\t// After this a testCallback will not be called.\n\t\t *\t\twatcher.isEnabled = false;\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isEnabled\n\t\t */\n\t\tthis.set( 'isEnabled', true );\n\n\t\t// Toggle text watching on isEnabled state change.\n\t\tthis.on( 'change:isEnabled', () => {\n\t\t\tif ( this.isEnabled ) {\n\t\t\t\tthis._startListening();\n\t\t\t} else {\n\t\t\t\tthis.stopListening( model.document.selection );\n\t\t\t\tthis.stopListening( model.document );\n\t\t\t}\n\t\t} );\n\n\t\tthis._startListening();\n\t}\n\n\t/**\n\t * Starts listening to the editor for typing and selection events.\n\t *\n\t * @private\n\t */\n\t_startListening() {\n\t\tconst model = this.model;\n\t\tconst document = model.document;\n\n\t\tthis.listenTo( document.selection, 'change:range', ( evt, { directChange } ) => {\n\t\t\t// Indirect changes (i.e. when the user types or external changes are applied) are handled in the document's change event.\n\t\t\tif ( !directChange ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Act only on collapsed selection.\n\t\t\tif ( !document.selection.isCollapsed ) {\n\t\t\t\tif ( this.hasMatch ) {\n\t\t\t\t\tthis.fire( 'unmatched' );\n\t\t\t\t\tthis.hasMatch = false;\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._evaluateTextBeforeSelection( 'selection' );\n\t\t} );\n\n\t\tthis.listenTo( document, 'change:data', ( evt, batch ) => {\n\t\t\tif ( batch.type == 'transparent' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._evaluateTextBeforeSelection( 'data', { batch } );\n\t\t} );\n\t}\n\n\t/**\n\t * Checks the editor content for matched text.\n\t *\n\t * @fires matched:data\n\t * @fires matched:selection\n\t * @fires unmatched\n\t *\n\t * @private\n\t * @param {'data'|'selection'} suffix A suffix used for generating the event name.\n\t * @param {Object} data Data object for event.\n\t */\n\t_evaluateTextBeforeSelection( suffix, data = {} ) {\n\t\tconst model = this.model;\n\t\tconst document = model.document;\n\t\tconst selection = document.selection;\n\n\t\tconst rangeBeforeSelection = model.createRange( model.createPositionAt( selection.focus.parent, 0 ), selection.focus );\n\n\t\tconst { text, range } = getLastTextLine( rangeBeforeSelection, model );\n\n\t\tconst testResult = this.testCallback( text );\n\n\t\tif ( !testResult && this.hasMatch ) {\n\t\t\tthis.fire( 'unmatched' );\n\t\t}\n\n\t\tthis.hasMatch = !!testResult;\n\n\t\tif ( testResult ) {\n\t\t\tconst eventData = Object.assign( data, { text, range } );\n\n\t\t\t// If the test callback returns an object with additional data, assign the data as well.\n\t\t\tif ( typeof testResult == 'object' ) {\n\t\t\t\tObject.assign( eventData, testResult );\n\t\t\t}\n\n\t\t\tthis.fire( `matched:${ suffix }`, eventData );\n\t\t}\n\t}\n}\n\nmix( TextWatcher, ObservableMixin );\n\n/**\n * Fired whenever the text watcher found a match for data changes.\n *\n * @event matched:data\n * @param {Object} data Event data.\n * @param {String} data.text The full text before selection to which the regexp was applied.\n * @param {module:engine/model/range~Range} data.range The range representing the position of the `data.text`.\n * @param {Object} [data.testResult] The additional data returned from the {@link module:typing/textwatcher~TextWatcher#testCallback}.\n */\n\n/**\n * Fired whenever the text watcher found a match for selection changes.\n *\n * @event matched:selection\n * @param {Object} data Event data.\n * @param {String} data.text The full text before selection.\n * @param {module:engine/model/range~Range} data.range The range representing the position of the `data.text`.\n * @param {Object} [data.testResult] The additional data returned from the {@link module:typing/textwatcher~TextWatcher#testCallback}.\n */\n\n/**\n * Fired whenever the text does not match anymore. Fired only when the text watcher found a match.\n *\n * @event unmatched\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module link/autolink\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport TextWatcher from '@ckeditor/ckeditor5-typing/src/textwatcher';\nimport getLastTextLine from '@ckeditor/ckeditor5-typing/src/utils/getlasttextline';\nimport { addLinkProtocolIfApplicable } from './utils';\n\nconst MIN_LINK_LENGTH_WITH_SPACE_AT_END = 4; // Ie: \"t.co \" (length 5).\n\n// This was a tweak from https://gist.github.com/dperini/729294.\nconst URL_REG_EXP = new RegExp(\n\t// Group 1: Line start or after a space.\n\t'(^|\\\\s)' +\n\t// Group 2: Detected URL (or e-mail).\n\t'(' +\n\t\t// Protocol identifier or short syntax \"//\"\n\t\t// a. Full form http://user@foo.bar.baz:8080/foo/bar.html#baz?foo=bar\n\t\t'(' +\n\t\t\t'(?:(?:(?:https?|ftp):)?\\\\/\\\\/)' +\n\t\t\t// BasicAuth using user:pass (optional)\n\t\t\t'(?:\\\\S+(?::\\\\S*)?@)?' +\n\t\t\t'(?:' +\n\t\t\t\t// Host & domain names.\n\t\t\t\t'(?![-_])(?:[-\\\\w\\\\u00a1-\\\\uffff]{0,63}[^-_]\\\\.)+' +\n\t\t\t\t// TLD identifier name.\n\t\t\t\t'(?:[a-z\\\\u00a1-\\\\uffff]{2,})' +\n\t\t\t')' +\n\t\t\t// port number (optional)\n\t\t\t'(?::\\\\d{2,5})?' +\n\t\t\t// resource path (optional)\n\t\t\t'(?:[/?#]\\\\S*)?' +\n\t\t')' +\n\t\t'|' +\n\t\t// b. Short form (either www.example.com or example@example.com)\n\t\t'(' +\n\t\t\t'(www.|(\\\\S+@))' +\n\t\t\t// Host & domain names.\n\t\t\t'((?![-_])(?:[-\\\\w\\\\u00a1-\\\\uffff]{0,63}[^-_]\\\\.))+' +\n\t// TLD identifier name.\n\t'(?:[a-z\\\\u00a1-\\\\uffff]{2,})' +\n\t')' +\n\t')$', 'i' );\n\nconst URL_GROUP_IN_MATCH = 2;\n\n/**\n * The autolink plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class AutoLink extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'AutoLink';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\n\t\tselection.on( 'change:range', () => {\n\t\t\t// Disable plugin when selection is inside a code block.\n\t\t\tthis.isEnabled = !selection.anchor.parent.is( 'element', 'codeBlock' );\n\t\t} );\n\n\t\tthis._enableTypingHandling();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tthis._enableEnterHandling();\n\t\tthis._enableShiftEnterHandling();\n\t}\n\n\t/**\n\t * Enables autolinking on typing.\n\t *\n\t * @private\n\t */\n\t_enableTypingHandling() {\n\t\tconst editor = this.editor;\n\n\t\tconst watcher = new TextWatcher( editor.model, text => {\n\t\t\t// 1. Detect <kbd>Space</kbd> after a text with a potential link.\n\t\t\tif ( !isSingleSpaceAtTheEnd( text ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// 2. Check text before last typed <kbd>Space</kbd>.\n\t\t\tconst url = getUrlAtTextEnd( text.substr( 0, text.length - 1 ) );\n\n\t\t\tif ( url ) {\n\t\t\t\treturn { url };\n\t\t\t}\n\t\t} );\n\n\t\tconst input = editor.plugins.get( 'Input' );\n\n\t\twatcher.on( 'matched:data', ( evt, data ) => {\n\t\t\tconst { batch, range, url } = data;\n\n\t\t\tif ( !input.isInput( batch ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst linkEnd = range.end.getShiftedBy( -1 ); // Executed after a space character.\n\t\t\tconst linkStart = linkEnd.getShiftedBy( -url.length );\n\n\t\t\tconst linkRange = editor.model.createRange( linkStart, linkEnd );\n\n\t\t\tthis._applyAutoLink( url, linkRange );\n\t\t} );\n\n\t\twatcher.bind( 'isEnabled' ).to( this );\n\t}\n\n\t/**\n\t * Enables autolinking on the <kbd>Enter</kbd> key.\n\t *\n\t * @private\n\t */\n\t_enableEnterHandling() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst enterCommand = editor.commands.get( 'enter' );\n\n\t\tif ( !enterCommand ) {\n\t\t\treturn;\n\t\t}\n\n\t\tenterCommand.on( 'execute', () => {\n\t\t\tconst position = model.document.selection.getFirstPosition();\n\n\t\t\tif ( !position.parent.previousSibling ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst rangeToCheck = model.createRangeIn( position.parent.previousSibling );\n\n\t\t\tthis._checkAndApplyAutoLinkOnRange( rangeToCheck );\n\t\t} );\n\t}\n\n\t/**\n\t * Enables autolinking on the <kbd>Shift</kbd>+<kbd>Enter</kbd> keyboard shortcut.\n\t *\n\t * @private\n\t */\n\t_enableShiftEnterHandling() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\n\t\tconst shiftEnterCommand = editor.commands.get( 'shiftEnter' );\n\n\t\tif ( !shiftEnterCommand ) {\n\t\t\treturn;\n\t\t}\n\n\t\tshiftEnterCommand.on( 'execute', () => {\n\t\t\tconst position = model.document.selection.getFirstPosition();\n\n\t\t\tconst rangeToCheck = model.createRange(\n\t\t\t\tmodel.createPositionAt( position.parent, 0 ),\n\t\t\t\tposition.getShiftedBy( -1 )\n\t\t\t);\n\n\t\t\tthis._checkAndApplyAutoLinkOnRange( rangeToCheck );\n\t\t} );\n\t}\n\n\t/**\n\t * Checks if the passed range contains a linkable text.\n\t *\n\t * @param {module:engine/model/range~Range} rangeToCheck\n\t * @private\n\t */\n\t_checkAndApplyAutoLinkOnRange( rangeToCheck ) {\n\t\tconst model = this.editor.model;\n\t\tconst { text, range } = getLastTextLine( rangeToCheck, model );\n\n\t\tconst url = getUrlAtTextEnd( text );\n\n\t\tif ( url ) {\n\t\t\tconst linkRange = model.createRange(\n\t\t\t\trange.end.getShiftedBy( -url.length ),\n\t\t\t\trange.end\n\t\t\t);\n\n\t\t\tthis._applyAutoLink( url, linkRange );\n\t\t}\n\t}\n\n\t/**\n\t * Applies a link on a given range.\n\t *\n\t * @param {String} url The URL to link.\n\t * @param {module:engine/model/range~Range} range The text range to apply the link attribute to.\n\t * @private\n\t */\n\t_applyAutoLink( link, range ) {\n\t\tconst model = this.editor.model;\n\n\t\tif ( !this.isEnabled || !isLinkAllowedOnRange( range, model ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Enqueue change to make undo step.\n\t\tmodel.enqueueChange( writer => {\n\t\t\tconst defaultProtocol = this.editor.config.get( 'link.defaultProtocol' );\n\t\t\tconst parsedUrl = addLinkProtocolIfApplicable( link, defaultProtocol );\n\t\t\twriter.setAttribute( 'linkHref', parsedUrl, range );\n\t\t} );\n\t}\n}\n\n// Check if text should be evaluated by the plugin in order to reduce number of RegExp checks on whole text.\nfunction isSingleSpaceAtTheEnd( text ) {\n\treturn text.length > MIN_LINK_LENGTH_WITH_SPACE_AT_END && text[ text.length - 1 ] === ' ' && text[ text.length - 2 ] !== ' ';\n}\n\nfunction getUrlAtTextEnd( text ) {\n\tconst match = URL_REG_EXP.exec( text );\n\n\treturn match ? match[ URL_GROUP_IN_MATCH ] : null;\n}\n\nfunction isLinkAllowedOnRange( range, model ) {\n\treturn model.schema.checkAttributeInSelection( model.createSelection( range ), 'linkHref' );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module list/listcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport first from '@ckeditor/ckeditor5-utils/src/first';\n\n/**\n * The list command. It is used by the {@link module:list/list~List list feature}.\n *\n * @extends module:core/command~Command\n */\nexport default class ListCommand extends Command {\n\t/**\n\t * Creates an instance of the command.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t * @param {'numbered'|'bulleted'} type List type that will be handled by this command.\n\t */\n\tconstructor( editor, type ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The type of the list created by the command.\n\t\t *\n\t\t * @readonly\n\t\t * @member {'numbered'|'bulleted'|'todo'}\n\t\t */\n\t\tthis.type = type;\n\n\t\t/**\n\t\t * A flag indicating whether the command is active, which means that the selection starts in a list of the same type.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #value\n\t\t */\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.value = this._getValue();\n\t\tthis.isEnabled = this._checkEnabled();\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @protected\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\t\tconst blocks = Array.from( document.selection.getSelectedBlocks() )\n\t\t\t.filter( block => checkCanBecomeListItem( block, model.schema ) );\n\n\t\t// Whether we are turning off some items.\n\t\tconst turnOff = this.value === true;\n\t\t// If we are turning off items, we are going to rename them to paragraphs.\n\n\t\tmodel.change( writer => {\n\t\t\t// If part of a list got turned off, we need to handle (outdent) all of sub-items of the last turned-off item.\n\t\t\t// To be sure that model is all the time in a good state, we first fix items below turned-off item.\n\t\t\tif ( turnOff ) {\n\t\t\t\t// Start from the model item that is just after the last turned-off item.\n\t\t\t\tlet next = blocks[ blocks.length - 1 ].nextSibling;\n\t\t\t\tlet currentIndent = Number.POSITIVE_INFINITY;\n\t\t\t\tlet changes = [];\n\n\t\t\t\t// Correct indent of all items after the last turned off item.\n\t\t\t\t// Rules that should be followed:\n\t\t\t\t// 1. All direct sub-items of turned-off item should become indent 0, because the first item after it\n\t\t\t\t//    will be the first item of a new list. Other items are at the same level, so should have same 0 index.\n\t\t\t\t// 2. All items with indent lower than indent of turned-off item should become indent 0, because they\n\t\t\t\t//    should not end up as a child of any of list items that they were not children of before.\n\t\t\t\t// 3. All other items should have their indent changed relatively to it's parent.\n\t\t\t\t//\n\t\t\t\t// For example:\n\t\t\t\t// 1  * --------\n\t\t\t\t// 2     * --------\n\t\t\t\t// 3        * --------\t\t\t<-- this is turned off.\n\t\t\t\t// 4           * --------\t\t<-- this has to become indent = 0, because it will be first item on a new list.\n\t\t\t\t// 5              * --------\t<-- this should be still be a child of item above, so indent = 1.\n\t\t\t\t// 6        * --------\t\t\t<-- this has to become indent = 0, because it should not be a child of any of items above.\n\t\t\t\t// 7           * --------\t\t<-- this should be still be a child of item above, so indent = 1.\n\t\t\t\t// 8     * --------\t\t\t\t<-- this has to become indent = 0.\n\t\t\t\t// 9        * --------\t\t\t<-- this should still be a child of item above, so indent = 1.\n\t\t\t\t// 10          * --------\t\t<-- this should still be a child of item above, so indent = 2.\n\t\t\t\t// 11          * --------\t\t<-- this should still be at the same level as item above, so indent = 2.\n\t\t\t\t// 12 * --------\t\t\t\t<-- this and all below are left unchanged.\n\t\t\t\t// 13    * --------\n\t\t\t\t// 14       * --------\n\t\t\t\t//\n\t\t\t\t// After turning off 3 the list becomes:\n\t\t\t\t//\n\t\t\t\t// 1  * --------\n\t\t\t\t// 2     * --------\n\t\t\t\t//\n\t\t\t\t// 3  --------\n\t\t\t\t//\n\t\t\t\t// 4  * --------\n\t\t\t\t// 5     * --------\n\t\t\t\t// 6  * --------\n\t\t\t\t// 7     * --------\n\t\t\t\t// 8  * --------\n\t\t\t\t// 9     * --------\n\t\t\t\t// 10       * --------\n\t\t\t\t// 11       * --------\n\t\t\t\t// 12 * --------\n\t\t\t\t// 13    * --------\n\t\t\t\t// 14       * --------\n\t\t\t\t//\n\t\t\t\t// Thanks to this algorithm no lists are mismatched and no items get unexpected children/parent, while\n\t\t\t\t// those parent-child connection which are possible to maintain are still maintained. It's worth noting\n\t\t\t\t// that this is the same effect that we would be get by multiple use of outdent command. However doing\n\t\t\t\t// it like this is much more efficient because it's less operation (less memory usage, easier OT) and\n\t\t\t\t// less conversion (faster).\n\t\t\t\twhile ( next && next.name == 'listItem' && next.getAttribute( 'listIndent' ) !== 0 ) {\n\t\t\t\t\t// Check each next list item, as long as its indent is bigger than 0.\n\t\t\t\t\t// If the indent is 0 we are not going to change anything anyway.\n\t\t\t\t\tconst indent = next.getAttribute( 'listIndent' );\n\n\t\t\t\t\t// We check if that's item indent is lower as current relative indent.\n\t\t\t\t\tif ( indent < currentIndent ) {\n\t\t\t\t\t\t// If it is, current relative indent becomes that indent.\n\t\t\t\t\t\tcurrentIndent = indent;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Fix indent relatively to current relative indent.\n\t\t\t\t\t// Note, that if we just changed the current relative indent, the newIndent will be equal to 0.\n\t\t\t\t\tconst newIndent = indent - currentIndent;\n\n\t\t\t\t\t// Save the entry in changes array. We do not apply it at the moment, because we will need to\n\t\t\t\t\t// reverse the changes so the last item is changed first.\n\t\t\t\t\t// This is to keep model in correct state all the time.\n\t\t\t\t\tchanges.push( { element: next, listIndent: newIndent } );\n\n\t\t\t\t\t// Find next item.\n\t\t\t\t\tnext = next.nextSibling;\n\t\t\t\t}\n\n\t\t\t\tchanges = changes.reverse();\n\n\t\t\t\tfor ( const item of changes ) {\n\t\t\t\t\twriter.setAttribute( 'listIndent', item.listIndent, item.element );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we are turning on, we might change some items that are already `listItem`s but with different type.\n\t\t\t// Changing one nested list item to other type should also trigger changing all its siblings so the\n\t\t\t// whole nested list is of the same type.\n\t\t\t// Example (assume changing to numbered list):\n\t\t\t// * ------\t\t\t\t<-- do not fix, top level item\n\t\t\t//   * ------\t\t\t<-- fix, because latter list item of this item's list is changed\n\t\t\t//      * ------\t\t<-- do not fix, item is not affected (different list)\n\t\t\t//   * ------\t\t\t<-- fix, because latter list item of this item's list is changed\n\t\t\t//      * ------\t\t<-- fix, because latter list item of this item's list is changed\n\t\t\t//      * ---[--\t\t<-- already in selection\n\t\t\t//   * ------\t\t\t<-- already in selection\n\t\t\t//   * ------\t\t\t<-- already in selection\n\t\t\t// * ------\t\t\t\t<-- already in selection, but does not cause other list items to change because is top-level\n\t\t\t//   * ---]--\t\t\t<-- already in selection\n\t\t\t//   * ------\t\t\t<-- fix, because preceding list item of this item's list is changed\n\t\t\t//      * ------\t\t<-- do not fix, item is not affected (different list)\n\t\t\t// * ------\t\t\t\t<-- do not fix, top level item\n\t\t\tif ( !turnOff ) {\n\t\t\t\t// Find lowest indent among selected items. This will be indicator what is the indent of\n\t\t\t\t// top-most list affected by the command.\n\t\t\t\tlet lowestIndent = Number.POSITIVE_INFINITY;\n\n\t\t\t\tfor ( const item of blocks ) {\n\t\t\t\t\tif ( item.is( 'element', 'listItem' ) && item.getAttribute( 'listIndent' ) < lowestIndent ) {\n\t\t\t\t\t\tlowestIndent = item.getAttribute( 'listIndent' );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Do not execute the fix for top-level lists.\n\t\t\t\tlowestIndent = lowestIndent === 0 ? 1 : lowestIndent;\n\n\t\t\t\t// Fix types of list items that are \"before\" the selected blocks.\n\t\t\t\t_fixType( blocks, true, lowestIndent );\n\n\t\t\t\t// Fix types of list items that are \"after\" the selected blocks.\n\t\t\t\t_fixType( blocks, false, lowestIndent );\n\t\t\t}\n\n\t\t\t// Phew! Now it will be easier :).\n\t\t\t// For each block element that was in the selection, we will either: turn it to list item,\n\t\t\t// turn it to paragraph, or change it's type. Or leave it as it is.\n\t\t\t// Do it in reverse as there might be multiple blocks (same as with changing indents).\n\t\t\tfor ( const element of blocks.reverse() ) {\n\t\t\t\tif ( turnOff && element.name == 'listItem' ) {\n\t\t\t\t\t// We are turning off and the element is a `listItem` - it should be converted to `paragraph`.\n\t\t\t\t\t// List item specific attributes are removed by post fixer.\n\t\t\t\t\twriter.rename( element, 'paragraph' );\n\t\t\t\t} else if ( !turnOff && element.name != 'listItem' ) {\n\t\t\t\t\t// We are turning on and the element is not a `listItem` - it should be converted to `listItem`.\n\t\t\t\t\t// The order of operations is important to keep model in correct state.\n\t\t\t\t\twriter.setAttributes( { listType: this.type, listIndent: 0 }, element );\n\t\t\t\t\twriter.rename( element, 'listItem' );\n\t\t\t\t} else if ( !turnOff && element.name == 'listItem' && element.getAttribute( 'listType' ) != this.type ) {\n\t\t\t\t\t// We are turning on and the element is a `listItem` but has different type - change it's type and\n\t\t\t\t\t// type of it's all siblings that have same indent.\n\t\t\t\t\twriter.setAttribute( 'listType', this.type, element );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Event fired by the {@link #execute} method.\n\t\t\t *\n\t\t\t * It allows to execute an action after executing the {@link ~ListCommand#execute} method, for example adjusting\n\t\t\t * attributes of changed blocks.\n\t\t\t *\n\t\t\t * @protected\n\t\t\t * @event _executeCleanup\n\t\t\t */\n\t\t\tthis.fire( '_executeCleanup', blocks );\n\t\t} );\n\t}\n\n\t/**\n\t * Checks the command's {@link #value}.\n\t *\n\t * @private\n\t * @returns {Boolean} The current value.\n\t */\n\t_getValue() {\n\t\t// Check whether closest `listItem` ancestor of the position has a correct type.\n\t\tconst listItem = first( this.editor.model.document.selection.getSelectedBlocks() );\n\n\t\treturn !!listItem && listItem.is( 'element', 'listItem' ) && listItem.getAttribute( 'listType' ) == this.type;\n\t}\n\n\t/**\n\t * Checks whether the command can be enabled in the current context.\n\t *\n\t * @private\n\t * @returns {Boolean} Whether the command should be enabled.\n\t */\n\t_checkEnabled() {\n\t\t// If command value is true it means that we are in list item, so the command should be enabled.\n\t\tif ( this.value ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst selection = this.editor.model.document.selection;\n\t\tconst schema = this.editor.model.schema;\n\n\t\tconst firstBlock = first( selection.getSelectedBlocks() );\n\n\t\tif ( !firstBlock ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Otherwise, check if list item can be inserted at the position start.\n\t\treturn checkCanBecomeListItem( firstBlock, schema );\n\t}\n}\n\n// Helper function used when one or more list item have their type changed. Fixes type of other list items\n// that are affected by the change (are in same lists) but are not directly in selection. The function got extracted\n// not to duplicated code, as same fix has to be performed before and after selection.\n//\n// @param {Array.<module:engine/model/node~Node>} blocks Blocks that are in selection.\n// @param {Boolean} isBackward Specified whether fix will be applied for blocks before first selected block (`true`)\n// or blocks after last selected block (`false`).\n// @param {Number} lowestIndent Lowest indent among selected blocks.\nfunction _fixType( blocks, isBackward, lowestIndent ) {\n\t// We need to check previous sibling of first changed item and next siblings of last changed item.\n\tconst startingItem = isBackward ? blocks[ 0 ] : blocks[ blocks.length - 1 ];\n\n\tif ( startingItem.is( 'element', 'listItem' ) ) {\n\t\tlet item = startingItem[ isBackward ? 'previousSibling' : 'nextSibling' ];\n\t\t// During processing items, keeps the lowest indent of already processed items.\n\t\t// This saves us from changing too many items.\n\t\t// Following example is for going forward as it is easier to read, however same applies to going backward.\n\t\t// * ------\n\t\t//   * ------\n\t\t//     * --[---\n\t\t//   * ------\t\t<-- `lowestIndent` should be 1\n\t\t//     * --]---\t\t<-- `startingItem`, `currentIndent` = 2, `lowestIndent` == 1\n\t\t//     * ------\t\t<-- should be fixed, `indent` == 2 == `currentIndent`\n\t\t//   * ------\t\t<-- should be fixed, set `currentIndent` to 1, `indent` == 1 == `currentIndent`\n\t\t//     * ------\t\t<-- should not be fixed, item is in different list, `indent` = 2, `indent` != `currentIndent`\n\t\t//   * ------\t\t<-- should be fixed, `indent` == 1 == `currentIndent`\n\t\t// * ------\t\t\t<-- break loop (`indent` < `lowestIndent`)\n\t\tlet currentIndent = startingItem.getAttribute( 'listIndent' );\n\n\t\t// Look back until a list item with indent lower than reference `lowestIndent`.\n\t\t// That would be the parent of nested sublist which contains item having `lowestIndent`.\n\t\twhile ( item && item.is( 'element', 'listItem' ) && item.getAttribute( 'listIndent' ) >= lowestIndent ) {\n\t\t\tif ( currentIndent > item.getAttribute( 'listIndent' ) ) {\n\t\t\t\tcurrentIndent = item.getAttribute( 'listIndent' );\n\t\t\t}\n\n\t\t\t// Found an item that is in the same nested sublist.\n\t\t\tif ( item.getAttribute( 'listIndent' ) == currentIndent ) {\n\t\t\t\t// Just add the item to selected blocks like it was selected by the user.\n\t\t\t\tblocks[ isBackward ? 'unshift' : 'push' ]( item );\n\t\t\t}\n\n\t\t\titem = item[ isBackward ? 'previousSibling' : 'nextSibling' ];\n\t\t}\n\t}\n}\n\n// Checks whether the given block can be replaced by a listItem.\n//\n// @private\n// @param {module:engine/model/element~Element} block A block to be tested.\n// @param {module:engine/model/schema~Schema} schema The schema of the document.\n// @returns {Boolean}\nfunction checkCanBecomeListItem( block, schema ) {\n\treturn schema.checkChild( block.parent, 'listItem' ) && !schema.isObject( block );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module list/indentcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport first from '@ckeditor/ckeditor5-utils/src/first';\n\n/**\n * The list indent command. It is used by the {@link module:list/list~List list feature}.\n *\n * @extends module:core/command~Command\n */\nexport default class IndentCommand extends Command {\n\t/**\n\t * Creates an instance of the command.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t * @param {'forward'|'backward'} indentDirection The direction of indent. If it is equal to `backward`, the command\n\t * will outdent a list item.\n\t */\n\tconstructor( editor, indentDirection ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * Determines by how much the command will change the list item's indent attribute.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @member {Number}\n\t\t */\n\t\tthis._indentBy = indentDirection == 'forward' ? 1 : -1;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.isEnabled = this._checkEnabled();\n\t}\n\n\t/**\n\t * Indents or outdents (depending on the {@link #constructor}'s `indentDirection` parameter) selected list items.\n\t *\n\t * @fires execute\n\t * @fires _executeCleanup\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tlet itemsToChange = Array.from( doc.selection.getSelectedBlocks() );\n\n\t\tmodel.change( writer => {\n\t\t\tconst lastItem = itemsToChange[ itemsToChange.length - 1 ];\n\n\t\t\t// Indenting a list item should also indent all the items that are already sub-items of indented item.\n\t\t\tlet next = lastItem.nextSibling;\n\n\t\t\t// Check all items after last indented item, as long as their indent is bigger than indent of that item.\n\t\t\twhile ( next && next.name == 'listItem' && next.getAttribute( 'listIndent' ) > lastItem.getAttribute( 'listIndent' ) ) {\n\t\t\t\titemsToChange.push( next );\n\n\t\t\t\tnext = next.nextSibling;\n\t\t\t}\n\n\t\t\t// We need to be sure to keep model in correct state after each small change, because converters\n\t\t\t// bases on that state and assumes that model is correct.\n\t\t\t// Because of that, if the command outdents items, we will outdent them starting from the last item, as\n\t\t\t// it is safer.\n\t\t\tif ( this._indentBy < 0 ) {\n\t\t\t\titemsToChange = itemsToChange.reverse();\n\t\t\t}\n\n\t\t\tfor ( const item of itemsToChange ) {\n\t\t\t\tconst indent = item.getAttribute( 'listIndent' ) + this._indentBy;\n\n\t\t\t\t// If indent is lower than 0, it means that the item got outdented when it was not indented.\n\t\t\t\t// This means that we need to convert that list item to paragraph.\n\t\t\t\tif ( indent < 0 ) {\n\t\t\t\t\t// To keep the model as correct as possible, first rename listItem, then remove attributes,\n\t\t\t\t\t// as listItem without attributes is very incorrect and will cause problems in converters.\n\t\t\t\t\t// No need to remove attributes, will be removed by post fixer.\n\t\t\t\t\twriter.rename( item, 'paragraph' );\n\t\t\t\t}\n\t\t\t\t// If indent is >= 0, change the attribute value.\n\t\t\t\telse {\n\t\t\t\t\twriter.setAttribute( 'listIndent', indent, item );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Event fired by the {@link #execute} method.\n\t\t\t *\n\t\t\t * It allows to execute an action after executing the {@link ~IndentCommand#execute} method, for example adjusting\n\t\t\t * attributes of changed list items.\n\t\t\t *\n\t\t\t * @protected\n\t\t\t * @event _executeCleanup\n\t\t\t */\n\t\t\tthis.fire( '_executeCleanup', itemsToChange );\n\t\t} );\n\t}\n\n\t/**\n\t * Checks whether the command can be enabled in the current context.\n\t *\n\t * @private\n\t * @returns {Boolean} Whether the command should be enabled.\n\t */\n\t_checkEnabled() {\n\t\t// Check whether any of position's ancestor is a list item.\n\t\tconst listItem = first( this.editor.model.document.selection.getSelectedBlocks() );\n\n\t\t// If selection is not in a list item, the command is disabled.\n\t\tif ( !listItem || !listItem.is( 'element', 'listItem' ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( this._indentBy > 0 ) {\n\t\t\t// Cannot indent first item in it's list. Check if before `listItem` is a list item that is in same list.\n\t\t\t// To be in the same list, the item has to have same attributes and cannot be \"split\" by an item with lower indent.\n\t\t\tconst indent = listItem.getAttribute( 'listIndent' );\n\t\t\tconst type = listItem.getAttribute( 'listType' );\n\n\t\t\tlet prev = listItem.previousSibling;\n\n\t\t\twhile ( prev && prev.is( 'element', 'listItem' ) && prev.getAttribute( 'listIndent' ) >= indent ) {\n\t\t\t\tif ( prev.getAttribute( 'listIndent' ) == indent ) {\n\t\t\t\t\t// The item is on the same level.\n\t\t\t\t\t// If it has same type, it means that we found a preceding sibling from the same list.\n\t\t\t\t\t// If it does not have same type, it means that `listItem` is on different list (this can happen only\n\t\t\t\t\t// on top level lists, though).\n\t\t\t\t\treturn prev.getAttribute( 'listType' ) == type;\n\t\t\t\t}\n\n\t\t\t\tprev = prev.previousSibling;\n\t\t\t}\n\n\t\t\t// Could not find similar list item, this means that `listItem` is first in its list.\n\t\t\treturn false;\n\t\t}\n\n\t\t// If we are outdenting it is enough to be in list item. Every list item can always be outdented.\n\t\treturn true;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module list/utils\n */\n\nimport { getFillerOffset } from '@ckeditor/ckeditor5-engine/src/view/containerelement';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport TreeWalker from '@ckeditor/ckeditor5-engine/src/model/treewalker';\n\n/**\n * Creates a list item {@link module:engine/view/containerelement~ContainerElement}.\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer The writer instance.\n * @returns {module:engine/view/containerelement~ContainerElement}\n */\nexport function createViewListItemElement( writer ) {\n\tconst viewItem = writer.createContainerElement( 'li' );\n\n\tviewItem.getFillerOffset = getListItemFillerOffset;\n\n\treturn viewItem;\n}\n\n/**\n * Helper function that creates a `<ul><li></li></ul>` or (`<ol>`) structure out of the given `modelItem` model `listItem` element.\n * Then, it binds the created view list item (`<li>`) with the model `listItem` element.\n * The function then returns the created view list item (`<li>`).\n *\n * @param {module:engine/model/item~Item} modelItem Model list item.\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion interface.\n * @returns {module:engine/view/containerelement~ContainerElement} View list element.\n */\nexport function generateLiInUl( modelItem, conversionApi ) {\n\tconst mapper = conversionApi.mapper;\n\tconst viewWriter = conversionApi.writer;\n\tconst listType = modelItem.getAttribute( 'listType' ) == 'numbered' ? 'ol' : 'ul';\n\tconst viewItem = createViewListItemElement( viewWriter );\n\n\tconst viewList = viewWriter.createContainerElement( listType, null );\n\n\tviewWriter.insert( viewWriter.createPositionAt( viewList, 0 ), viewItem );\n\n\tmapper.bindElements( modelItem, viewItem );\n\n\treturn viewItem;\n}\n\n/**\n * Helper function that inserts a view list at a correct place and merges it with its siblings.\n * It takes a model list item element (`modelItem`) and a corresponding view list item element (`injectedItem`). The view list item\n * should be in a view list element (`<ul>` or `<ol>`) and should be its only child.\n * See comments below to better understand the algorithm.\n *\n * @param {module:engine/view/item~Item} modelItem Model list item.\n * @param {module:engine/view/containerelement~ContainerElement} injectedItem\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion interface.\n * @param {module:engine/model/model~Model} model The model instance.\n */\nexport function injectViewList( modelItem, injectedItem, conversionApi, model ) {\n\tconst injectedList = injectedItem.parent;\n\tconst mapper = conversionApi.mapper;\n\tconst viewWriter = conversionApi.writer;\n\n\t// The position where the view list will be inserted.\n\tlet insertPosition = mapper.toViewPosition( model.createPositionBefore( modelItem ) );\n\n\t// 1. Find the previous list item that has the same or smaller indent. Basically we are looking for the first model item\n\t// that is a \"parent\" or \"sibling\" of the injected model item.\n\t// If there is no such list item, it means that the injected list item is the first item in \"its list\".\n\tconst refItem = getSiblingListItem( modelItem.previousSibling, {\n\t\tsameIndent: true,\n\t\tsmallerIndent: true,\n\t\tlistIndent: modelItem.getAttribute( 'listIndent' )\n\t} );\n\tconst prevItem = modelItem.previousSibling;\n\n\tif ( refItem && refItem.getAttribute( 'listIndent' ) == modelItem.getAttribute( 'listIndent' ) ) {\n\t\t// There is a list item with the same indent - we found the same-level sibling.\n\t\t// Break the list after it. The inserted view item will be added in the broken space.\n\t\tconst viewItem = mapper.toViewElement( refItem );\n\t\tinsertPosition = viewWriter.breakContainer( viewWriter.createPositionAfter( viewItem ) );\n\t} else {\n\t\t// There is no list item with the same indent. Check the previous model item.\n\t\tif ( prevItem && prevItem.name == 'listItem' ) {\n\t\t\t// If it is a list item, it has to have a lower indent.\n\t\t\t// It means that the inserted item should be added to it as its nested item.\n\t\t\tinsertPosition = mapper.toViewPosition( model.createPositionAt( prevItem, 'end' ) );\n\n\t\t\t// There could be some not mapped elements (eg. span in to-do list) but we need to insert\n\t\t\t// a nested list directly inside the li element.\n\t\t\tconst mappedViewAncestor = mapper.findMappedViewAncestor( insertPosition );\n\t\t\tconst nestedList = findNestedList( mappedViewAncestor );\n\n\t\t\t// If there already is some nested list, then use it's position.\n\t\t\tif ( nestedList ) {\n\t\t\t\tinsertPosition = viewWriter.createPositionBefore( nestedList );\n\t\t\t} else {\n\t\t\t\t// Else just put new list on the end of list item content.\n\t\t\t\tinsertPosition = viewWriter.createPositionAt( mappedViewAncestor, 'end' );\n\t\t\t}\n\t\t} else {\n\t\t\t// The previous item is not a list item (or does not exist at all).\n\t\t\t// Just map the position and insert the view item at the mapped position.\n\t\t\tinsertPosition = mapper.toViewPosition( model.createPositionBefore( modelItem ) );\n\t\t}\n\t}\n\n\tinsertPosition = positionAfterUiElements( insertPosition );\n\n\t// Insert the view item.\n\tviewWriter.insert( insertPosition, injectedList );\n\n\t// 2. Handle possible children of the injected model item.\n\tif ( prevItem && prevItem.name == 'listItem' ) {\n\t\tconst prevView = mapper.toViewElement( prevItem );\n\n\t\tconst walkerBoundaries = viewWriter.createRange( viewWriter.createPositionAt( prevView, 0 ), insertPosition );\n\t\tconst walker = walkerBoundaries.getWalker( { ignoreElementEnd: true } );\n\n\t\tfor ( const value of walker ) {\n\t\t\tif ( value.item.is( 'element', 'li' ) ) {\n\t\t\t\tconst breakPosition = viewWriter.breakContainer( viewWriter.createPositionBefore( value.item ) );\n\t\t\t\tconst viewList = value.item.parent;\n\n\t\t\t\tconst targetPosition = viewWriter.createPositionAt( injectedItem, 'end' );\n\t\t\t\tmergeViewLists( viewWriter, targetPosition.nodeBefore, targetPosition.nodeAfter );\n\t\t\t\tviewWriter.move( viewWriter.createRangeOn( viewList ), targetPosition );\n\n\t\t\t\twalker.position = breakPosition;\n\t\t\t}\n\t\t}\n\t} else {\n\t\tconst nextViewList = injectedList.nextSibling;\n\n\t\tif ( nextViewList && ( nextViewList.is( 'element', 'ul' ) || nextViewList.is( 'element', 'ol' ) ) ) {\n\t\t\tlet lastSubChild = null;\n\n\t\t\tfor ( const child of nextViewList.getChildren() ) {\n\t\t\t\tconst modelChild = mapper.toModelElement( child );\n\n\t\t\t\tif ( modelChild && modelChild.getAttribute( 'listIndent' ) > modelItem.getAttribute( 'listIndent' ) ) {\n\t\t\t\t\tlastSubChild = child;\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( lastSubChild ) {\n\t\t\t\tviewWriter.breakContainer( viewWriter.createPositionAfter( lastSubChild ) );\n\t\t\t\tviewWriter.move( viewWriter.createRangeOn( lastSubChild.parent ), viewWriter.createPositionAt( injectedItem, 'end' ) );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Merge the inserted view list with its possible neighbor lists.\n\tmergeViewLists( viewWriter, injectedList, injectedList.nextSibling );\n\tmergeViewLists( viewWriter, injectedList.previousSibling, injectedList );\n}\n\n/**\n * Helper function that takes two parameters that are expected to be view list elements, and merges them.\n * The merge happens only if both parameters are list elements of the same type (the same element name and the same class attributes).\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter The writer instance.\n * @param {module:engine/view/item~Item} firstList The first element to compare.\n * @param {module:engine/view/item~Item} secondList The second element to compare.\n * @returns {module:engine/view/position~Position|null} The position after merge or `null` when there was no merge.\n */\nexport function mergeViewLists( viewWriter, firstList, secondList ) {\n\t// Check if two lists are going to be merged.\n\tif ( !firstList || !secondList || ( firstList.name != 'ul' && firstList.name != 'ol' ) ) {\n\t\treturn null;\n\t}\n\n\t// Both parameters are list elements, so compare types now.\n\tif ( firstList.name != secondList.name || firstList.getAttribute( 'class' ) !== secondList.getAttribute( 'class' ) ) {\n\t\treturn null;\n\t}\n\n\treturn viewWriter.mergeContainers( viewWriter.createPositionAfter( firstList ) );\n}\n\n/**\n * Helper function that for a given `view.Position`, returns a `view.Position` that is after all `view.UIElement`s that\n * are after the given position.\n *\n * For example:\n * `<container:p>foo^<ui:span></ui:span><ui:span></ui:span>bar</container:p>`\n * For position ^, the position before \"bar\" will be returned.\n *\n * @param {module:engine/view/position~Position} viewPosition\n * @returns {module:engine/view/position~Position}\n */\nexport function positionAfterUiElements( viewPosition ) {\n\treturn viewPosition.getLastMatchingPosition( value => value.item.is( 'uiElement' ) );\n}\n\n/**\n * Helper function that searches for a previous list item sibling of a given model item that meets the given criteria\n * passed by the options object.\n *\n * @param {module:engine/model/item~Item} modelItem\n * @param {Object} options Search criteria.\n * @param {Boolean} [options.sameIndent=false] Whether the sought sibling should have the same indentation.\n * @param {Boolean} [options.smallerIndent=false] Whether the sought sibling should have a smaller indentation.\n * @param {Number} [options.listIndent] The reference indentation.\n * @param {'forward'|'backward'} [options.direction='backward'] Walking direction.\n * @returns {module:engine/model/item~Item|null}\n */\nexport function getSiblingListItem( modelItem, options ) {\n\tconst sameIndent = !!options.sameIndent;\n\tconst smallerIndent = !!options.smallerIndent;\n\tconst indent = options.listIndent;\n\n\tlet item = modelItem;\n\n\twhile ( item && item.name == 'listItem' ) {\n\t\tconst itemIndent = item.getAttribute( 'listIndent' );\n\n\t\tif ( ( sameIndent && indent == itemIndent ) || ( smallerIndent && indent > itemIndent ) ) {\n\t\t\treturn item;\n\t\t}\n\n\t\tif ( options.direction === 'forward' ) {\n\t\t\titem = item.nextSibling;\n\t\t} else {\n\t\t\titem = item.previousSibling;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Helper method for creating a UI button and linking it with an appropriate command.\n *\n * @private\n * @param {module:core/editor/editor~Editor} editor The editor instance to which the UI component will be added.\n * @param {String} commandName The name of the command.\n * @param {Object} label The button label.\n * @param {String} icon The source of the icon.\n */\nexport function createUIComponent( editor, commandName, label, icon ) {\n\teditor.ui.componentFactory.add( commandName, locale => {\n\t\tconst command = editor.commands.get( commandName );\n\t\tconst buttonView = new ButtonView( locale );\n\n\t\tbuttonView.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true,\n\t\t\tisToggleable: true\n\t\t} );\n\n\t\t// Bind button model to command.\n\t\tbuttonView.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );\n\n\t\t// Execute command.\n\t\tbuttonView.on( 'execute', () => {\n\t\t\teditor.execute( commandName );\n\t\t\teditor.editing.view.focus();\n\t\t} );\n\n\t\treturn buttonView;\n\t} );\n}\n\n/**\n * Returns a first list view element that is direct child of the given view element.\n *\n * @param {module:engine/view/element~Element} viewElement\n * @return {module:engine/view/element~Element|null}\n */\nexport function findNestedList( viewElement ) {\n\tfor ( const node of viewElement.getChildren() ) {\n\t\tif ( node.name == 'ul' || node.name == 'ol' ) {\n\t\t\treturn node;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Returns an array with all `listItem` elements that represents the same list.\n *\n * It means that values for `listIndent`, `listType`, and `listStyle` for all items are equal.\n *\n * @param {module:engine/model/position~Position} position Starting position.\n * @param {'forward'|'backward'} direction Walking direction.\n * @returns {Array.<module:engine/model/element~Element>}\n */\nexport function getSiblingNodes( position, direction ) {\n\tconst items = [];\n\tconst listItem = position.parent;\n\tconst walkerOptions = {\n\t\tignoreElementEnd: true,\n\t\tstartPosition: position,\n\t\tshallow: true,\n\t\tdirection\n\t};\n\tconst limitIndent = listItem.getAttribute( 'listIndent' );\n\tconst nodes = [ ...new TreeWalker( walkerOptions ) ]\n\t\t.filter( value => value.item.is( 'element' ) )\n\t\t.map( value => value.item );\n\n\tfor ( const element of nodes ) {\n\t\t// If found something else than `listItem`, we're out of the list scope.\n\t\tif ( !element.is( 'element', 'listItem' ) ) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// If current parsed item has lower indent that element that the element that was a starting point,\n\t\t// it means we left a nested list. Abort searching items.\n\t\t//\n\t\t// ■ List item 1.       [listIndent=0]\n\t\t//     ○ List item 2.[] [listIndent=1], limitIndent = 1,\n\t\t//     ○ List item 3.   [listIndent=1]\n\t\t// ■ List item 4.       [listIndent=0]\n\t\t//\n\t\t// Abort searching when leave nested list.\n\t\tif ( element.getAttribute( 'listIndent' ) < limitIndent ) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// ■ List item 1.[]     [listIndent=0] limitIndent = 0,\n\t\t//     ○ List item 2.   [listIndent=1]\n\t\t//     ○ List item 3.   [listIndent=1]\n\t\t// ■ List item 4.       [listIndent=0]\n\t\t//\n\t\t// Ignore nested lists.\n\t\tif ( element.getAttribute( 'listIndent' ) > limitIndent ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// ■ List item 1.[]  [listType=bulleted]\n\t\t// 1. List item 2.   [listType=numbered]\n\t\t// 2.List item 3.    [listType=numbered]\n\t\t//\n\t\t// Abort searching when found a different kind of a list.\n\t\tif ( element.getAttribute( 'listType' ) !== listItem.getAttribute( 'listType' ) ) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// ■ List item 1.[]  [listType=bulleted]\n\t\t// ■ List item 2.    [listType=bulleted]\n\t\t// ○ List item 3.    [listType=bulleted]\n\t\t// ○ List item 4.    [listType=bulleted]\n\t\t//\n\t\t// Abort searching when found a different list style.\n\t\tif ( element.getAttribute( 'listStyle' ) !== listItem.getAttribute( 'listStyle' ) ) {\n\t\t\tbreak;\n\t\t}\n\n\t\tif ( direction === 'backward' ) {\n\t\t\titems.unshift( element );\n\t\t} else {\n\t\t\titems.push( element );\n\t\t}\n\t}\n\n\treturn items;\n}\n\n// Implementation of getFillerOffset for view list item element.\n//\n// @returns {Number|null} Block filler offset or `null` if block filler is not needed.\nfunction getListItemFillerOffset() {\n\tconst hasOnlyLists = !this.isEmpty && ( this.getChild( 0 ).name == 'ul' || this.getChild( 0 ).name == 'ol' );\n\n\tif ( this.isEmpty || hasOnlyLists ) {\n\t\treturn 0;\n\t}\n\n\treturn getFillerOffset.call( this );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module list/converters\n */\n\nimport {\n\tgenerateLiInUl,\n\tinjectViewList,\n\tmergeViewLists,\n\tgetSiblingListItem,\n\tpositionAfterUiElements\n} from './utils';\nimport TreeWalker from '@ckeditor/ckeditor5-engine/src/model/treewalker';\n\n/**\n * A model-to-view converter for the `listItem` model element insertion.\n *\n * It creates a `<ul><li></li><ul>` (or `<ol>`) view structure out of a `listItem` model element, inserts it at the correct\n * position, and merges the list with surrounding lists (if available).\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert\n * @param {module:engine/model/model~Model} model Model instance.\n * @returns {Function} Returns a conversion callback.\n */\nexport function modelViewInsertion( model ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst consumable = conversionApi.consumable;\n\n\t\tif ( !consumable.test( data.item, 'insert' ) ||\n\t\t\t!consumable.test( data.item, 'attribute:listType' ) ||\n\t\t\t!consumable.test( data.item, 'attribute:listIndent' )\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tconsumable.consume( data.item, 'insert' );\n\t\tconsumable.consume( data.item, 'attribute:listType' );\n\t\tconsumable.consume( data.item, 'attribute:listIndent' );\n\n\t\tconst modelItem = data.item;\n\t\tconst viewItem = generateLiInUl( modelItem, conversionApi );\n\n\t\tinjectViewList( modelItem, viewItem, conversionApi, model );\n\t};\n}\n\n/**\n * A model-to-view converter for the `listItem` model element removal.\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:remove\n * @param {module:engine/model/model~Model} model Model instance.\n * @returns {Function} Returns a conversion callback.\n */\nexport function modelViewRemove( model ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst viewPosition = conversionApi.mapper.toViewPosition( data.position );\n\t\tconst viewStart = viewPosition.getLastMatchingPosition( value => !value.item.is( 'element', 'li' ) );\n\t\tconst viewItem = viewStart.nodeAfter;\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\t// 1. Break the container after and before the list item.\n\t\t// This will create a view list with one view list item - the one to remove.\n\t\tviewWriter.breakContainer( viewWriter.createPositionBefore( viewItem ) );\n\t\tviewWriter.breakContainer( viewWriter.createPositionAfter( viewItem ) );\n\n\t\t// 2. Remove the list with the item to remove.\n\t\tconst viewList = viewItem.parent;\n\t\tconst viewListPrev = viewList.previousSibling;\n\t\tconst removeRange = viewWriter.createRangeOn( viewList );\n\t\tconst removed = viewWriter.remove( removeRange );\n\n\t\t// 3. Merge the whole created by breaking and removing the list.\n\t\tif ( viewListPrev && viewListPrev.nextSibling ) {\n\t\t\tmergeViewLists( viewWriter, viewListPrev, viewListPrev.nextSibling );\n\t\t}\n\n\t\t// 4. Bring back nested list that was in the removed <li>.\n\t\tconst modelItem = conversionApi.mapper.toModelElement( viewItem );\n\n\t\thoistNestedLists( modelItem.getAttribute( 'listIndent' ) + 1, data.position, removeRange.start, viewItem, conversionApi, model );\n\n\t\t// 5. Unbind removed view item and all children.\n\t\tfor ( const child of viewWriter.createRangeIn( removed ).getItems() ) {\n\t\t\tconversionApi.mapper.unbindViewElement( child );\n\t\t}\n\n\t\tevt.stop();\n\t};\n}\n\n/**\n * A model-to-view converter for the `type` attribute change on the `listItem` model element.\n *\n * This change means that the `<li>` element parent changes from `<ul>` to `<ol>` (or vice versa). This is accomplished\n * by breaking view elements and changing their name. The next {@link module:list/converters~modelViewMergeAfterChangeType}\n * converter will attempt to merge split nodes.\n *\n * Splitting this conversion into 2 steps makes it possible to add an additional conversion in the middle.\n * Check {@link module:list/todolistconverters~modelViewChangeType} to see an example of it.\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data Additional information about the change.\n * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface.\n */\nexport function modelViewChangeType( evt, data, conversionApi ) {\n\tif ( !conversionApi.consumable.consume( data.item, 'attribute:listType' ) ) {\n\t\treturn;\n\t}\n\n\tconst viewItem = conversionApi.mapper.toViewElement( data.item );\n\tconst viewWriter = conversionApi.writer;\n\n\t// Break the container after and before the list item.\n\t// This will create a view list with one view list item -- the one that changed type.\n\tviewWriter.breakContainer( viewWriter.createPositionBefore( viewItem ) );\n\tviewWriter.breakContainer( viewWriter.createPositionAfter( viewItem ) );\n\n\t// Change name of the view list that holds the changed view item.\n\t// We cannot just change name property, because that would not render properly.\n\tconst viewList = viewItem.parent;\n\tconst listName = data.attributeNewValue == 'numbered' ? 'ol' : 'ul';\n\n\tviewWriter.rename( listName, viewList );\n}\n\n/**\n * A model-to-view converter that attempts to merge nodes split by {@link module:list/converters~modelViewChangeType}.\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data Additional information about the change.\n * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface.\n */\nexport function modelViewMergeAfterChangeType( evt, data, conversionApi ) {\n\tconst viewItem = conversionApi.mapper.toViewElement( data.item );\n\tconst viewList = viewItem.parent;\n\tconst viewWriter = conversionApi.writer;\n\n\t// Merge the changed view list with other lists, if possible.\n\tmergeViewLists( viewWriter, viewList, viewList.nextSibling );\n\tmergeViewLists( viewWriter, viewList.previousSibling, viewList );\n\n\t// Consumable insertion of children inside the item. They are already handled by re-building the item in view.\n\tfor ( const child of data.item.getChildren() ) {\n\t\tconversionApi.consumable.consume( child, 'insert' );\n\t}\n}\n\n/**\n * A model-to-view converter for the `listIndent` attribute change on the `listItem` model element.\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute\n * @param {module:engine/model/model~Model} model Model instance.\n * @returns {Function} Returns a conversion callback.\n */\nexport function modelViewChangeIndent( model ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !conversionApi.consumable.consume( data.item, 'attribute:listIndent' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewItem = conversionApi.mapper.toViewElement( data.item );\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\t// 1. Break the container after and before the list item.\n\t\t// This will create a view list with one view list item -- the one that changed type.\n\t\tviewWriter.breakContainer( viewWriter.createPositionBefore( viewItem ) );\n\t\tviewWriter.breakContainer( viewWriter.createPositionAfter( viewItem ) );\n\n\t\t// 2. Extract view list with changed view list item and merge \"hole\" possibly created by breaking and removing elements.\n\t\tconst viewList = viewItem.parent;\n\t\tconst viewListPrev = viewList.previousSibling;\n\t\tconst removeRange = viewWriter.createRangeOn( viewList );\n\t\tviewWriter.remove( removeRange );\n\n\t\tif ( viewListPrev && viewListPrev.nextSibling ) {\n\t\t\tmergeViewLists( viewWriter, viewListPrev, viewListPrev.nextSibling );\n\t\t}\n\n\t\t// 3. Bring back nested list that was in the removed <li>.\n\t\thoistNestedLists( data.attributeOldValue + 1, data.range.start, removeRange.start, viewItem, conversionApi, model );\n\n\t\t// 4. Inject view list like it is newly inserted.\n\t\tinjectViewList( data.item, viewItem, conversionApi, model );\n\n\t\t// 5. Consume insertion of children inside the item. They are already handled by re-building the item in view.\n\t\tfor ( const child of data.item.getChildren() ) {\n\t\t\tconversionApi.consumable.consume( child, 'insert' );\n\t\t}\n\t};\n}\n\n/**\n * A special model-to-view converter introduced by the {@link module:list/list~List list feature}. This converter is fired for\n * insert change of every model item, and should be fired before the actual converter. The converter checks whether the inserted\n * model item is a non-`listItem` element. If it is, and it is inserted inside a view list, the converter breaks the\n * list so the model element is inserted to the view parent element corresponding to its model parent element.\n *\n * The converter prevents such situations:\n *\n *\t\t// Model:                        // View:\n *\t\t<listItem>foo</listItem>         <ul>\n *\t\t<listItem>bar</listItem>             <li>foo</li>\n *\t\t                                     <li>bar</li>\n *\t\t                                 </ul>\n *\n *\t\t// After change:                 // Correct view guaranteed by this converter:\n *\t\t<listItem>foo</listItem>         <ul><li>foo</li></ul><p>xxx</p><ul><li>bar</li></ul>\n *\t\t<paragraph>xxx</paragraph>       // Instead of this wrong view state:\n *\t\t<listItem>bar</listItem>         <ul><li>foo</li><p>xxx</p><li>bar</li></ul>\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data Additional information about the change.\n * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface.\n */\nexport function modelViewSplitOnInsert( evt, data, conversionApi ) {\n\tif ( data.item.name != 'listItem' ) {\n\t\tlet viewPosition = conversionApi.mapper.toViewPosition( data.range.start );\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst lists = [];\n\n\t\t// Break multiple ULs/OLs if there are.\n\t\t//\n\t\t// Imagine following list:\n\t\t//\n\t\t// 1 --------\n\t\t//   1.1 --------\n\t\t//     1.1.1 --------\n\t\t//     1.1.2 --------\n\t\t//     1.1.3 --------\n\t\t//       1.1.3.1 --------\n\t\t//   1.2 --------\n\t\t//     1.2.1 --------\n\t\t// 2 --------\n\t\t//\n\t\t// Insert paragraph after item 1.1.1:\n\t\t//\n\t\t// 1 --------\n\t\t//   1.1 --------\n\t\t//     1.1.1 --------\n\t\t//\n\t\t// Lorem ipsum.\n\t\t//\n\t\t//     1.1.2 --------\n\t\t//     1.1.3 --------\n\t\t//       1.1.3.1 --------\n\t\t//   1.2 --------\n\t\t//     1.2.1 --------\n\t\t// 2 --------\n\t\t//\n\t\t// In this case 1.1.2 has to become beginning of a new list.\n\t\t// We need to break list before 1.1.2 (obvious), then we need to break list also before 1.2.\n\t\t// Then we need to move those broken pieces one after another and merge:\n\t\t//\n\t\t// 1 --------\n\t\t//   1.1 --------\n\t\t//     1.1.1 --------\n\t\t//\n\t\t// Lorem ipsum.\n\t\t//\n\t\t// 1.1.2 --------\n\t\t//   1.1.3 --------\n\t\t//     1.1.3.1 --------\n\t\t// 1.2 --------\n\t\t//   1.2.1 --------\n\t\t// 2 --------\n\t\t//\n\t\twhile ( viewPosition.parent.name == 'ul' || viewPosition.parent.name == 'ol' ) {\n\t\t\tviewPosition = viewWriter.breakContainer( viewPosition );\n\n\t\t\tif ( viewPosition.parent.name != 'li' ) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Remove lists that are after inserted element.\n\t\t\t// They will be brought back later, below the inserted element.\n\t\t\tconst removeStart = viewPosition;\n\t\t\tconst removeEnd = viewWriter.createPositionAt( viewPosition.parent, 'end' );\n\n\t\t\t// Don't remove if there is nothing to remove.\n\t\t\tif ( !removeStart.isEqual( removeEnd ) ) {\n\t\t\t\tconst removed = viewWriter.remove( viewWriter.createRange( removeStart, removeEnd ) );\n\t\t\t\tlists.push( removed );\n\t\t\t}\n\n\t\t\tviewPosition = viewWriter.createPositionAfter( viewPosition.parent );\n\t\t}\n\n\t\t// Bring back removed lists.\n\t\tif ( lists.length > 0 ) {\n\t\t\tfor ( let i = 0; i < lists.length; i++ ) {\n\t\t\t\tconst previousList = viewPosition.nodeBefore;\n\t\t\t\tconst insertedRange = viewWriter.insert( viewPosition, lists[ i ] );\n\t\t\t\tviewPosition = insertedRange.end;\n\n\t\t\t\t// Don't merge first list! We want a split in that place (this is why this converter is introduced).\n\t\t\t\tif ( i > 0 ) {\n\t\t\t\t\tconst mergePos = mergeViewLists( viewWriter, previousList, previousList.nextSibling );\n\n\t\t\t\t\t// If `mergePos` is in `previousList` it means that the lists got merged.\n\t\t\t\t\t// In this case, we need to fix insert position.\n\t\t\t\t\tif ( mergePos && mergePos.parent == previousList ) {\n\t\t\t\t\t\tviewPosition.offset--;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Merge last inserted list with element after it.\n\t\t\tmergeViewLists( viewWriter, viewPosition.nodeBefore, viewPosition.nodeAfter );\n\t\t}\n\t}\n}\n\n/**\n * A special model-to-view converter introduced by the {@link module:list/list~List list feature}. This converter takes care of\n * merging view lists after something is removed or moved from near them.\n *\n * Example:\n *\n *\t\t// Model:                        // View:\n *\t\t<listItem>foo</listItem>         <ul><li>foo</li></ul>\n *\t\t<paragraph>xxx</paragraph>       <p>xxx</p>\n *\t\t<listItem>bar</listItem>         <ul><li>bar</li></ul>\n *\n *\t\t// After change:                 // Correct view guaranteed by this converter:\n *\t\t<listItem>foo</listItem>         <ul>\n *\t\t<listItem>bar</listItem>             <li>foo</li>\n *\t\t                                     <li>bar</li>\n *\t\t                                 </ul>\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:remove\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data Additional information about the change.\n * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface.\n */\nexport function modelViewMergeAfter( evt, data, conversionApi ) {\n\tconst viewPosition = conversionApi.mapper.toViewPosition( data.position );\n\tconst viewItemPrev = viewPosition.nodeBefore;\n\tconst viewItemNext = viewPosition.nodeAfter;\n\n\t// Merge lists if something (remove, move) was done from inside of list.\n\t// Merging will be done only if both items are view lists of the same type.\n\t// The check is done inside the helper function.\n\tmergeViewLists( conversionApi.writer, viewItemPrev, viewItemNext );\n}\n\n/**\n * A view-to-model converter that converts the `<li>` view elements into the `listItem` model elements.\n *\n * To set correct values of the `listType` and `listIndent` attributes the converter:\n * * checks `<li>`'s parent,\n * * stores and increases the `conversionApi.store.indent` value when `<li>`'s sub-items are converted.\n *\n * @see module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data An object containing conversion input and a placeholder for conversion output and possibly other values.\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion interface to be used by the callback.\n */\nexport function viewModelConverter( evt, data, conversionApi ) {\n\tif ( conversionApi.consumable.consume( data.viewItem, { name: true } ) ) {\n\t\tconst writer = conversionApi.writer;\n\n\t\t// 1. Create `listItem` model element.\n\t\tconst listItem = writer.createElement( 'listItem' );\n\n\t\t// 2. Handle `listItem` model element attributes.\n\t\tconst indent = getIndent( data.viewItem );\n\n\t\twriter.setAttribute( 'listIndent', indent, listItem );\n\n\t\t// Set 'bulleted' as default. If this item is pasted into a context,\n\t\tconst type = data.viewItem.parent && data.viewItem.parent.name == 'ol' ? 'numbered' : 'bulleted';\n\t\twriter.setAttribute( 'listType', type, listItem );\n\n\t\tif ( !conversionApi.safeInsert( listItem, data.modelCursor ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst nextPosition = viewToModelListItemChildrenConverter( listItem, data.viewItem.getChildren(), conversionApi );\n\n\t\t// Result range starts before the first item and ends after the last.\n\t\tdata.modelRange = writer.createRange( data.modelCursor, nextPosition );\n\n\t\tconversionApi.updateConversionResult( listItem, data );\n\t}\n}\n\n/**\n * A view-to-model converter for the `<ul>` and `<ol>` view elements that cleans the input view of garbage.\n * This is mostly to clean whitespaces from between the `<li>` view elements inside the view list element, however, also\n * incorrect data can be cleared if the view was incorrect.\n *\n * @see module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data An object containing conversion input and a placeholder for conversion output and possibly other values.\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion interface to be used by the callback.\n */\nexport function cleanList( evt, data, conversionApi ) {\n\tif ( conversionApi.consumable.test( data.viewItem, { name: true } ) ) {\n\t\t// Caching children because when we start removing them iterating fails.\n\t\tconst children = Array.from( data.viewItem.getChildren() );\n\n\t\tfor ( const child of children ) {\n\t\t\tconst isWrongElement = !( child.is( 'element', 'li' ) || isList( child ) );\n\n\t\t\tif ( isWrongElement ) {\n\t\t\t\tchild._remove();\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * A view-to-model converter for the `<li>` elements that cleans whitespace formatting from the input view.\n *\n * @see module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data An object containing conversion input and a placeholder for conversion output and possibly other values.\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion interface to be used by the callback.\n */\nexport function cleanListItem( evt, data, conversionApi ) {\n\tif ( conversionApi.consumable.test( data.viewItem, { name: true } ) ) {\n\t\tif ( data.viewItem.childCount === 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst children = [ ...data.viewItem.getChildren() ];\n\n\t\tlet foundList = false;\n\t\tlet firstNode = true;\n\n\t\tfor ( const child of children ) {\n\t\t\tif ( foundList && !isList( child ) ) {\n\t\t\t\tchild._remove();\n\t\t\t}\n\n\t\t\tif ( child.is( '$text' ) ) {\n\t\t\t\t// If this is the first node and it's a text node, left-trim it.\n\t\t\t\tif ( firstNode ) {\n\t\t\t\t\tchild._data = child.data.replace( /^\\s+/, '' );\n\t\t\t\t}\n\n\t\t\t\t// If this is the last text node before <ul> or <ol>, right-trim it.\n\t\t\t\tif ( !child.nextSibling || isList( child.nextSibling ) ) {\n\t\t\t\t\tchild._data = child.data.replace( /\\s+$/, '' );\n\t\t\t\t}\n\t\t\t} else if ( isList( child ) ) {\n\t\t\t\t// If this is a <ul> or <ol>, do not process it, just mark that we already visited list element.\n\t\t\t\tfoundList = true;\n\t\t\t}\n\n\t\t\tfirstNode = false;\n\t\t}\n\t}\n}\n\n/**\n * Returns a callback for model position to view position mapping for {@link module:engine/conversion/mapper~Mapper}. The callback fixes\n * positions between the `listItem` elements that would be incorrectly mapped because of how list items are represented in the model\n * and in the view.\n *\n * @see module:engine/conversion/mapper~Mapper#event:modelToViewPosition\n * @param {module:engine/view/view~View} view A view instance.\n * @returns {Function}\n */\nexport function modelToViewPosition( view ) {\n\treturn ( evt, data ) => {\n\t\tif ( data.isPhantom ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst modelItem = data.modelPosition.nodeBefore;\n\n\t\tif ( modelItem && modelItem.is( 'element', 'listItem' ) ) {\n\t\t\tconst viewItem = data.mapper.toViewElement( modelItem );\n\t\t\tconst topmostViewList = viewItem.getAncestors().find( isList );\n\t\t\tconst walker = view.createPositionAt( viewItem, 0 ).getWalker();\n\n\t\t\tfor ( const value of walker ) {\n\t\t\t\tif ( value.type == 'elementStart' && value.item.is( 'element', 'li' ) ) {\n\t\t\t\t\tdata.viewPosition = value.previousPosition;\n\n\t\t\t\t\tbreak;\n\t\t\t\t} else if ( value.type == 'elementEnd' && value.item == topmostViewList ) {\n\t\t\t\t\tdata.viewPosition = value.nextPosition;\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n/**\n * The callback for view position to model position mapping for {@link module:engine/conversion/mapper~Mapper}. The callback fixes\n * positions between the `<li>` elements that would be incorrectly mapped because of how list items are represented in the model\n * and in the view.\n *\n * @see module:engine/conversion/mapper~Mapper#event:viewToModelPosition\n * @param {module:engine/model/model~Model} model Model instance.\n * @returns {Function} Returns a conversion callback.\n */\nexport function viewToModelPosition( model ) {\n\treturn ( evt, data ) => {\n\t\tconst viewPos = data.viewPosition;\n\t\tconst viewParent = viewPos.parent;\n\t\tconst mapper = data.mapper;\n\n\t\tif ( viewParent.name == 'ul' || viewParent.name == 'ol' ) {\n\t\t\t// Position is directly in <ul> or <ol>.\n\t\t\tif ( !viewPos.isAtEnd ) {\n\t\t\t\t// If position is not at the end, it must be before <li>.\n\t\t\t\t// Get that <li>, map it to `listItem` and set model position before that `listItem`.\n\t\t\t\tconst modelNode = mapper.toModelElement( viewPos.nodeAfter );\n\n\t\t\t\tdata.modelPosition = model.createPositionBefore( modelNode );\n\t\t\t} else {\n\t\t\t\t// Position is at the end of <ul> or <ol>, so there is no <li> after it to be mapped.\n\t\t\t\t// There is <li> before the position, but we cannot just map it to `listItem` and set model position after it,\n\t\t\t\t// because that <li> may contain nested items.\n\t\t\t\t// We will check \"model length\" of that <li>, in other words - how many `listItem`s are in that <li>.\n\t\t\t\tconst modelNode = mapper.toModelElement( viewPos.nodeBefore );\n\t\t\t\tconst modelLength = mapper.getModelLength( viewPos.nodeBefore );\n\n\t\t\t\t// Then we get model position before mapped `listItem` and shift it accordingly.\n\t\t\t\tdata.modelPosition = model.createPositionBefore( modelNode ).getShiftedBy( modelLength );\n\t\t\t}\n\n\t\t\tevt.stop();\n\t\t} else if (\n\t\t\tviewParent.name == 'li' &&\n\t\t\tviewPos.nodeBefore &&\n\t\t\t( viewPos.nodeBefore.name == 'ul' || viewPos.nodeBefore.name == 'ol' )\n\t\t) {\n\t\t\t// In most cases when view position is in <li> it is in text and this is a correct position.\n\t\t\t// However, if position is after <ul> or <ol> we have to fix it -- because in model <ul>/<ol> are not in the `listItem`.\n\t\t\tconst modelNode = mapper.toModelElement( viewParent );\n\n\t\t\t// Check all <ul>s and <ol>s that are in the <li> but before mapped position.\n\t\t\t// Get model length of those elements and then add it to the offset of `listItem` mapped to the original <li>.\n\t\t\tlet modelLength = 1; // Starts from 1 because the original <li> has to be counted in too.\n\t\t\tlet viewList = viewPos.nodeBefore;\n\n\t\t\twhile ( viewList && isList( viewList ) ) {\n\t\t\t\tmodelLength += mapper.getModelLength( viewList );\n\n\t\t\t\tviewList = viewList.previousSibling;\n\t\t\t}\n\n\t\t\tdata.modelPosition = model.createPositionBefore( modelNode ).getShiftedBy( modelLength );\n\n\t\t\tevt.stop();\n\t\t}\n\t};\n}\n\n/**\n * Post-fixer that reacts to changes on document and fixes incorrect model states.\n *\n * In the example below, there is a correct list structure.\n * Then the middle element is removed so the list structure will become incorrect:\n *\n *\t\t<listItem listType=\"bulleted\" listIndent=0>Item 1</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=1>Item 2</listItem>   <--- this is removed.\n *\t\t<listItem listType=\"bulleted\" listIndent=2>Item 3</listItem>\n *\n * The list structure after the middle element is removed:\n *\n * \t\t<listItem listType=\"bulleted\" listIndent=0>Item 1</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=2>Item 3</listItem>\n *\n * Should become:\n *\n *\t\t<listItem listType=\"bulleted\" listIndent=0>Item 1</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=1>Item 3</listItem>   <--- note that indent got post-fixed.\n *\n * @param {module:engine/model/model~Model} model The data model.\n * @param {module:engine/model/writer~Writer} writer The writer to do changes with.\n * @returns {Boolean} `true` if any change has been applied, `false` otherwise.\n */\nexport function modelChangePostFixer( model, writer ) {\n\tconst changes = model.document.differ.getChanges();\n\tconst itemToListHead = new Map();\n\n\tlet applied = false;\n\n\tfor ( const entry of changes ) {\n\t\tif ( entry.type == 'insert' && entry.name == 'listItem' ) {\n\t\t\t_addListToFix( entry.position );\n\t\t} else if ( entry.type == 'insert' && entry.name != 'listItem' ) {\n\t\t\tif ( entry.name != '$text' ) {\n\t\t\t\t// In case of renamed element.\n\t\t\t\tconst item = entry.position.nodeAfter;\n\n\t\t\t\tif ( item.hasAttribute( 'listIndent' ) ) {\n\t\t\t\t\twriter.removeAttribute( 'listIndent', item );\n\n\t\t\t\t\tapplied = true;\n\t\t\t\t}\n\n\t\t\t\tif ( item.hasAttribute( 'listType' ) ) {\n\t\t\t\t\twriter.removeAttribute( 'listType', item );\n\n\t\t\t\t\tapplied = true;\n\t\t\t\t}\n\n\t\t\t\tif ( item.hasAttribute( 'listStyle' ) ) {\n\t\t\t\t\twriter.removeAttribute( 'listStyle', item );\n\n\t\t\t\t\tapplied = true;\n\t\t\t\t}\n\n\t\t\t\tfor ( const innerItem of Array.from( model.createRangeIn( item ) ).filter( e => e.item.is( 'element', 'listItem' ) ) ) {\n\t\t\t\t\t_addListToFix( innerItem.previousPosition );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst posAfter = entry.position.getShiftedBy( entry.length );\n\n\t\t\t_addListToFix( posAfter );\n\t\t} else if ( entry.type == 'remove' && entry.name == 'listItem' ) {\n\t\t\t_addListToFix( entry.position );\n\t\t} else if ( entry.type == 'attribute' && entry.attributeKey == 'listIndent' ) {\n\t\t\t_addListToFix( entry.range.start );\n\t\t} else if ( entry.type == 'attribute' && entry.attributeKey == 'listType' ) {\n\t\t\t_addListToFix( entry.range.start );\n\t\t}\n\t}\n\n\tfor ( const listHead of itemToListHead.values() ) {\n\t\t_fixListIndents( listHead );\n\t\t_fixListTypes( listHead );\n\t}\n\n\treturn applied;\n\n\tfunction _addListToFix( position ) {\n\t\tconst previousNode = position.nodeBefore;\n\n\t\tif ( !previousNode || !previousNode.is( 'element', 'listItem' ) ) {\n\t\t\tconst item = position.nodeAfter;\n\n\t\t\tif ( item && item.is( 'element', 'listItem' ) ) {\n\t\t\t\titemToListHead.set( item, item );\n\t\t\t}\n\t\t} else {\n\t\t\tlet listHead = previousNode;\n\n\t\t\tif ( itemToListHead.has( listHead ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor (\n\t\t\t\t// Cache previousSibling and reuse for performance reasons. See #6581.\n\t\t\t\tlet previousSibling = listHead.previousSibling;\n\t\t\t\tpreviousSibling && previousSibling.is( 'element', 'listItem' );\n\t\t\t\tpreviousSibling = listHead.previousSibling\n\t\t\t) {\n\t\t\t\tlistHead = previousSibling;\n\n\t\t\t\tif ( itemToListHead.has( listHead ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\titemToListHead.set( previousNode, listHead );\n\t\t}\n\t}\n\n\tfunction _fixListIndents( item ) {\n\t\tlet maxIndent = 0;\n\t\tlet fixBy = null;\n\n\t\twhile ( item && item.is( 'element', 'listItem' ) ) {\n\t\t\tconst itemIndent = item.getAttribute( 'listIndent' );\n\n\t\t\tif ( itemIndent > maxIndent ) {\n\t\t\t\tlet newIndent;\n\n\t\t\t\tif ( fixBy === null ) {\n\t\t\t\t\tfixBy = itemIndent - maxIndent;\n\t\t\t\t\tnewIndent = maxIndent;\n\t\t\t\t} else {\n\t\t\t\t\tif ( fixBy > itemIndent ) {\n\t\t\t\t\t\tfixBy = itemIndent;\n\t\t\t\t\t}\n\n\t\t\t\t\tnewIndent = itemIndent - fixBy;\n\t\t\t\t}\n\n\t\t\t\twriter.setAttribute( 'listIndent', newIndent, item );\n\n\t\t\t\tapplied = true;\n\t\t\t} else {\n\t\t\t\tfixBy = null;\n\t\t\t\tmaxIndent = item.getAttribute( 'listIndent' ) + 1;\n\t\t\t}\n\n\t\t\titem = item.nextSibling;\n\t\t}\n\t}\n\n\tfunction _fixListTypes( item ) {\n\t\tlet typesStack = [];\n\t\tlet prev = null;\n\n\t\twhile ( item && item.is( 'element', 'listItem' ) ) {\n\t\t\tconst itemIndent = item.getAttribute( 'listIndent' );\n\n\t\t\tif ( prev && prev.getAttribute( 'listIndent' ) > itemIndent ) {\n\t\t\t\ttypesStack = typesStack.slice( 0, itemIndent + 1 );\n\t\t\t}\n\n\t\t\tif ( itemIndent != 0 ) {\n\t\t\t\tif ( typesStack[ itemIndent ] ) {\n\t\t\t\t\tconst type = typesStack[ itemIndent ];\n\n\t\t\t\t\tif ( item.getAttribute( 'listType' ) != type ) {\n\t\t\t\t\t\twriter.setAttribute( 'listType', type, item );\n\n\t\t\t\t\t\tapplied = true;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttypesStack[ itemIndent ] = item.getAttribute( 'listType' );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprev = item;\n\t\t\titem = item.nextSibling;\n\t\t}\n\t}\n}\n\n/**\n * A fixer for pasted content that includes list items.\n *\n * It fixes indentation of pasted list items so the pasted items match correctly to the context they are pasted into.\n *\n * Example:\n *\n *\t\t<listItem listType=\"bulleted\" listIndent=0>A</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=1>B^</listItem>\n *\t\t// At ^ paste:  <listItem listType=\"bulleted\" listIndent=4>X</listItem>\n *\t\t//              <listItem listType=\"bulleted\" listIndent=5>Y</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=2>C</listItem>\n *\n * Should become:\n *\n *\t\t<listItem listType=\"bulleted\" listIndent=0>A</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=1>BX</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=2>Y/listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=2>C</listItem>\n *\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Array} args Arguments of {@link module:engine/model/model~Model#insertContent}.\n */\nexport function modelIndentPasteFixer( evt, [ content, selectable ] ) {\n\t// Check whether inserted content starts from a `listItem`. If it does not, it means that there are some other\n\t// elements before it and there is no need to fix indents, because even if we insert that content into a list,\n\t// that list will be broken.\n\t// Note: we also need to handle singular elements because inserting item with indent 0 into 0,1,[],2\n\t// would create incorrect model.\n\tlet item = content.is( 'documentFragment' ) ? content.getChild( 0 ) : content;\n\n\tlet selection;\n\n\tif ( !selectable ) {\n\t\tselection = this.document.selection;\n\t} else {\n\t\tselection = this.createSelection( selectable );\n\t}\n\n\tif ( item && item.is( 'element', 'listItem' ) ) {\n\t\t// Get a reference list item. Inserted list items will be fixed according to that item.\n\t\tconst pos = selection.getFirstPosition();\n\t\tlet refItem = null;\n\n\t\tif ( pos.parent.is( 'element', 'listItem' ) ) {\n\t\t\trefItem = pos.parent;\n\t\t} else if ( pos.nodeBefore && pos.nodeBefore.is( 'element', 'listItem' ) ) {\n\t\t\trefItem = pos.nodeBefore;\n\t\t}\n\n\t\t// If there is `refItem` it means that we do insert list items into an existing list.\n\t\tif ( refItem ) {\n\t\t\t// First list item in `data` has indent equal to 0 (it is a first list item). It should have indent equal\n\t\t\t// to the indent of reference item. We have to fix the first item and all of it's children and following siblings.\n\t\t\t// Indent of all those items has to be adjusted to reference item.\n\t\t\tconst indentChange = refItem.getAttribute( 'listIndent' );\n\n\t\t\t// Fix only if there is anything to fix.\n\t\t\tif ( indentChange > 0 ) {\n\t\t\t\t// Adjust indent of all \"first\" list items in inserted data.\n\t\t\t\twhile ( item && item.is( 'element', 'listItem' ) ) {\n\t\t\t\t\titem._setAttribute( 'listIndent', item.getAttribute( 'listIndent' ) + indentChange );\n\n\t\t\t\t\titem = item.nextSibling;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Helper function that converts children of a given `<li>` view element into corresponding model elements.\n// The function maintains proper order of elements if model `listItem` is split during the conversion\n// due to block children conversion.\n//\n// @param {module:engine/model/element~Element} listItemModel List item model element to which converted children will be inserted.\n// @param {Iterable.<module:engine/view/node~Node>} viewChildren View elements which will be converted.\n// @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion interface to be used by the callback.\n// @returns {module:engine/model/position~Position} Position on which next elements should be inserted after children conversion.\nfunction viewToModelListItemChildrenConverter( listItemModel, viewChildren, conversionApi ) {\n\tconst { writer, schema } = conversionApi;\n\n\t// A position after the last inserted `listItem`.\n\tlet nextPosition = writer.createPositionAfter( listItemModel );\n\n\t// Check all children of the converted `<li>`. At this point we assume there are no \"whitespace\" view text nodes\n\t// in view list, between view list items. This should be handled by `<ul>` and `<ol>` converters.\n\tfor ( const child of viewChildren ) {\n\t\tif ( child.name == 'ul' || child.name == 'ol' ) {\n\t\t\t// If the children is a list, we will insert its conversion result after currently handled `listItem`.\n\t\t\t// Then, next insertion position will be set after all the new list items (and maybe other elements if\n\t\t\t// something split list item).\n\t\t\t//\n\t\t\t// If this is a list, we expect that some `listItem`s and possibly other blocks will be inserted, however `.modelCursor`\n\t\t\t// should be set after last `listItem` (or block). This is why it feels safe to use it as `nextPosition`\n\t\t\tnextPosition = conversionApi.convertItem( child, nextPosition ).modelCursor;\n\t\t} else {\n\t\t\t// If this is not a list, try inserting content at the end of the currently handled `listItem`.\n\t\t\tconst result = conversionApi.convertItem( child, writer.createPositionAt( listItemModel, 'end' ) );\n\n\t\t\t// It may end up that the current `listItem` becomes split (if that content cannot be inside `listItem`). For example:\n\t\t\t//\n\t\t\t// <li><p>Foo</p></li>\n\t\t\t//\n\t\t\t// will be converted to:\n\t\t\t//\n\t\t\t// <listItem></listItem><paragraph>Foo</paragraph><listItem></listItem>\n\t\t\t//\n\t\t\tconst convertedChild = result.modelRange.start.nodeAfter;\n\t\t\tconst wasSplit = convertedChild && convertedChild.is( 'element' ) && !schema.checkChild( listItemModel, convertedChild.name );\n\n\t\t\tif ( wasSplit ) {\n\t\t\t\t// As `lastListItem` got split, we need to update it to the second part of the split `listItem` element.\n\t\t\t\t//\n\t\t\t\t// `modelCursor` should be set to a position where the conversion should continue. There are multiple possible scenarios\n\t\t\t\t// that may happen. Usually, `modelCursor` (marked as `#` below) would point to the second list item after conversion:\n\t\t\t\t//\n\t\t\t\t//\t\t`<li><p>Foo</p></li>` -> `<listItem></listItem><paragraph>Foo</paragraph><listItem>#</listItem>`\n\t\t\t\t//\n\t\t\t\t// However, in some cases, like auto-paragraphing, the position is placed at the end of the block element:\n\t\t\t\t//\n\t\t\t\t//\t\t`<li><div>Foo</div></li>` -> `<listItem></listItem><paragraph>Foo#</paragraph><listItem></listItem>`\n\t\t\t\t//\n\t\t\t\t// or after an element if another element broken auto-paragraphed element:\n\t\t\t\t//\n\t\t\t\t//\t\t`<li><div><h2>Foo</h2></div></li>` -> `<listItem></listItem><heading1>Foo</heading1>#<listItem></listItem>`\n\t\t\t\t//\n\t\t\t\t// We need to check for such cases and use proper list item and position based on it.\n\t\t\t\t//\n\t\t\t\tif ( result.modelCursor.parent.is( 'element', 'listItem' ) ) {\n\t\t\t\t\t// (1).\n\t\t\t\t\tlistItemModel = result.modelCursor.parent;\n\t\t\t\t} else {\n\t\t\t\t\t// (2), (3).\n\t\t\t\t\tlistItemModel = findNextListItem( result.modelCursor );\n\t\t\t\t}\n\n\t\t\t\tnextPosition = writer.createPositionAfter( listItemModel );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nextPosition;\n}\n\n// Helper function that seeks for a next list item starting from given `startPosition`.\nfunction findNextListItem( startPosition ) {\n\tconst treeWalker = new TreeWalker( { startPosition } );\n\n\tlet value;\n\n\tdo {\n\t\tvalue = treeWalker.next();\n\t} while ( !value.value.item.is( 'element', 'listItem' ) );\n\n\treturn value.value.item;\n}\n\n// Helper function that takes all children of given `viewRemovedItem` and moves them in a correct place, according\n// to other given parameters.\nfunction hoistNestedLists( nextIndent, modelRemoveStartPosition, viewRemoveStartPosition, viewRemovedItem, conversionApi, model ) {\n\t// Find correct previous model list item element.\n\t// The element has to have either same or smaller indent than given reference indent.\n\t// This will be the model element which will get nested items (if it has smaller indent) or sibling items (if it has same indent).\n\t// Keep in mind that such element might not be found, if removed item was the first item.\n\tconst prevModelItem = getSiblingListItem( modelRemoveStartPosition.nodeBefore, {\n\t\tsameIndent: true,\n\t\tsmallerIndent: true,\n\t\tlistIndent: nextIndent,\n\t\tfoo: 'b'\n\t} );\n\n\tconst mapper = conversionApi.mapper;\n\tconst viewWriter = conversionApi.writer;\n\n\t// Indent of found element or `null` if the element has not been found.\n\tconst prevIndent = prevModelItem ? prevModelItem.getAttribute( 'listIndent' ) : null;\n\n\tlet insertPosition;\n\n\tif ( !prevModelItem ) {\n\t\t// If element has not been found, simply insert lists at the position where the removed item was:\n\t\t//\n\t\t// Lorem ipsum.\n\t\t// 1 --------           <--- this is removed, no previous list item, put nested items in place of removed item.\n\t\t//   1.1 --------       <--- this is reference indent.\n\t\t//     1.1.1 --------\n\t\t//     1.1.2 --------\n\t\t//   1.2 --------\n\t\t//\n\t\t// Becomes:\n\t\t//\n\t\t// Lorem ipsum.\n\t\t// 1.1 --------\n\t\t//   1.1.1 --------\n\t\t//   1.1.2 --------\n\t\t// 1.2 --------\n\t\tinsertPosition = viewRemoveStartPosition;\n\t} else if ( prevIndent == nextIndent ) {\n\t\t// If element has been found and has same indent as reference indent it means that nested items should\n\t\t// become siblings of found element:\n\t\t//\n\t\t// 1 --------\n\t\t//   1.1 --------\n\t\t//   1.2 --------       <--- this is `prevModelItem`.\n\t\t// 2 --------           <--- this is removed, previous list item has indent same as reference indent.\n\t\t//   2.1 --------       <--- this is reference indent, this and 2.2 should become siblings of 1.2.\n\t\t//   2.2 --------\n\t\t//\n\t\t// Becomes:\n\t\t//\n\t\t// 1 --------\n\t\t//   1.1 --------\n\t\t//   1.2 --------\n\t\t//   2.1 --------\n\t\t//   2.2 --------\n\t\tconst prevViewList = mapper.toViewElement( prevModelItem ).parent;\n\t\tinsertPosition = viewWriter.createPositionAfter( prevViewList );\n\t} else {\n\t\t// If element has been found and has smaller indent as reference indent it means that nested items\n\t\t// should become nested items of found item:\n\t\t//\n\t\t// 1 --------           <--- this is `prevModelItem`.\n\t\t//   1.1 --------       <--- this is removed, previous list item has indent smaller than reference indent.\n\t\t//     1.1.1 --------   <--- this is reference indent, this and 1.1.1 should become nested items of 1.\n\t\t//     1.1.2 --------\n\t\t//   1.2 --------\n\t\t//\n\t\t// Becomes:\n\t\t//\n\t\t// 1 --------\n\t\t//   1.1.1 --------\n\t\t//   1.1.2 --------\n\t\t//   1.2 --------\n\t\t//\n\t\t// Note: in this case 1.1.1 have indent 2 while 1 have indent 0. In model that should not be possible,\n\t\t// because following item may have indent bigger only by one. But this is fixed by postfixer.\n\t\tconst modelPosition = model.createPositionAt( prevModelItem, 'end' );\n\t\tinsertPosition = mapper.toViewPosition( modelPosition );\n\t}\n\n\tinsertPosition = positionAfterUiElements( insertPosition );\n\n\t// Handle multiple lists. This happens if list item has nested numbered and bulleted lists. Following lists\n\t// are inserted after the first list (no need to recalculate insertion position for them).\n\tfor ( const child of [ ...viewRemovedItem.getChildren() ] ) {\n\t\tif ( isList( child ) ) {\n\t\t\tinsertPosition = viewWriter.move( viewWriter.createRangeOn( child ), insertPosition ).end;\n\n\t\t\tmergeViewLists( viewWriter, child, child.nextSibling );\n\t\t\tmergeViewLists( viewWriter, child.previousSibling, child );\n\t\t}\n\t}\n}\n\n// Checks if view element is a list type (ul or ol).\n//\n// @param {module:engine/view/element~Element} viewElement\n// @returns {Boolean}\nfunction isList( viewElement ) {\n\treturn viewElement.is( 'element', 'ol' ) || viewElement.is( 'element', 'ul' );\n}\n\n// Calculates the indent value for a list item. Handles HTML compliant and non-compliant lists.\n//\n// Also, fixes non HTML compliant lists indents:\n//\n//\t\tbefore:                                     fixed list:\n//\t\tOL                                          OL\n//\t\t|-> LI (parent LIs: 0)                      |-> LI     (indent: 0)\n//\t\t    |-> OL                                  |-> OL\n//\t\t        |-> OL                                  |\n//\t\t        |   |-> OL                              |\n//\t\t        |       |-> OL                          |\n//\t\t        |           |-> LI (parent LIs: 1)      |-> LI (indent: 1)\n//\t\t        |-> LI (parent LIs: 1)                  |-> LI (indent: 1)\n//\n//\t\tbefore:                                     fixed list:\n//\t\tOL                                          OL\n//\t\t|-> OL                                      |\n//\t\t    |-> OL                                  |\n//\t\t         |-> OL                             |\n//\t\t             |-> LI (parent LIs: 0)         |-> LI        (indent: 0)\n//\n//\t\tbefore:                                     fixed list:\n//\t\tOL                                          OL\n//\t\t|-> LI (parent LIs: 0)                      |-> LI         (indent: 0)\n//\t\t|-> OL                                          |-> OL\n//\t\t    |-> LI (parent LIs: 0)                          |-> LI (indent: 1)\n//\n// @param {module:engine/view/element~Element} listItem\n// @param {Object} conversionStore\n// @returns {Number}\nfunction getIndent( listItem ) {\n\tlet indent = 0;\n\n\tlet parent = listItem.parent;\n\n\twhile ( parent ) {\n\t\t// Each LI in the tree will result in an increased indent for HTML compliant lists.\n\t\tif ( parent.is( 'element', 'li' ) ) {\n\t\t\tindent++;\n\t\t} else {\n\t\t\t// If however the list is nested in other list we should check previous sibling of any of the list elements...\n\t\t\tconst previousSibling = parent.previousSibling;\n\n\t\t\t// ...because the we might need increase its indent:\n\t\t\t//\t\tbefore:                           fixed list:\n\t\t\t//\t\tOL                                OL\n\t\t\t//\t\t|-> LI (parent LIs: 0)            |-> LI         (indent: 0)\n\t\t\t//\t\t|-> OL                                |-> OL\n\t\t\t//\t\t    |-> LI (parent LIs: 0)                |-> LI (indent: 1)\n\t\t\tif ( previousSibling && previousSibling.is( 'element', 'li' ) ) {\n\t\t\t\tindent++;\n\t\t\t}\n\t\t}\n\n\t\tparent = parent.parent;\n\t}\n\n\treturn indent;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module list/listediting\n */\n\nimport ListCommand from './listcommand';\nimport IndentCommand from './indentcommand';\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';\n\nimport {\n\tcleanList,\n\tcleanListItem,\n\tmodelViewInsertion,\n\tmodelViewChangeType,\n\tmodelViewMergeAfterChangeType,\n\tmodelViewMergeAfter,\n\tmodelViewRemove,\n\tmodelViewSplitOnInsert,\n\tmodelViewChangeIndent,\n\tmodelChangePostFixer,\n\tmodelIndentPasteFixer,\n\tviewModelConverter,\n\tmodelToViewPosition,\n\tviewToModelPosition\n} from './converters';\n\n/**\n * The engine of the list feature. It handles creating, editing and removing lists and list items.\n *\n * It registers the `'numberedList'`, `'bulletedList'`, `'indentList'` and `'outdentList'` commands.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ListEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ListEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ Paragraph ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Schema.\n\t\t// Note: in case `$block` will ever be allowed in `listItem`, keep in mind that this feature\n\t\t// uses `Selection#getSelectedBlocks()` without any additional processing to obtain all selected list items.\n\t\t// If there are blocks allowed inside list item, algorithms using `getSelectedBlocks()` will have to be modified.\n\t\teditor.model.schema.register( 'listItem', {\n\t\t\tinheritAllFrom: '$block',\n\t\t\tallowAttributes: [ 'listType', 'listIndent' ]\n\t\t} );\n\n\t\t// Converters.\n\t\tconst data = editor.data;\n\t\tconst editing = editor.editing;\n\n\t\teditor.model.document.registerPostFixer( writer => modelChangePostFixer( editor.model, writer ) );\n\n\t\tediting.mapper.registerViewToModelLength( 'li', getViewListItemLength );\n\t\tdata.mapper.registerViewToModelLength( 'li', getViewListItemLength );\n\n\t\tediting.mapper.on( 'modelToViewPosition', modelToViewPosition( editing.view ) );\n\t\tediting.mapper.on( 'viewToModelPosition', viewToModelPosition( editor.model ) );\n\t\tdata.mapper.on( 'modelToViewPosition', modelToViewPosition( editing.view ) );\n\n\t\teditor.conversion.for( 'editingDowncast' )\n\t\t\t.add( dispatcher => {\n\t\t\t\tdispatcher.on( 'insert', modelViewSplitOnInsert, { priority: 'high' } );\n\t\t\t\tdispatcher.on( 'insert:listItem', modelViewInsertion( editor.model ) );\n\t\t\t\tdispatcher.on( 'attribute:listType:listItem', modelViewChangeType, { priority: 'high' } );\n\t\t\t\tdispatcher.on( 'attribute:listType:listItem', modelViewMergeAfterChangeType, { priority: 'low' } );\n\t\t\t\tdispatcher.on( 'attribute:listIndent:listItem', modelViewChangeIndent( editor.model ) );\n\t\t\t\tdispatcher.on( 'remove:listItem', modelViewRemove( editor.model ) );\n\t\t\t\tdispatcher.on( 'remove', modelViewMergeAfter, { priority: 'low' } );\n\t\t\t} );\n\n\t\teditor.conversion.for( 'dataDowncast' )\n\t\t\t.add( dispatcher => {\n\t\t\t\tdispatcher.on( 'insert', modelViewSplitOnInsert, { priority: 'high' } );\n\t\t\t\tdispatcher.on( 'insert:listItem', modelViewInsertion( editor.model ) );\n\t\t\t} );\n\n\t\teditor.conversion.for( 'upcast' )\n\t\t\t.add( dispatcher => {\n\t\t\t\tdispatcher.on( 'element:ul', cleanList, { priority: 'high' } );\n\t\t\t\tdispatcher.on( 'element:ol', cleanList, { priority: 'high' } );\n\t\t\t\tdispatcher.on( 'element:li', cleanListItem, { priority: 'high' } );\n\t\t\t\tdispatcher.on( 'element:li', viewModelConverter );\n\t\t\t} );\n\n\t\t// Fix indentation of pasted items.\n\t\teditor.model.on( 'insertContent', modelIndentPasteFixer, { priority: 'high' } );\n\n\t\t// Register commands for numbered and bulleted list.\n\t\teditor.commands.add( 'numberedList', new ListCommand( editor, 'numbered' ) );\n\t\teditor.commands.add( 'bulletedList', new ListCommand( editor, 'bulleted' ) );\n\n\t\t// Register commands for indenting.\n\t\teditor.commands.add( 'indentList', new IndentCommand( editor, 'forward' ) );\n\t\teditor.commands.add( 'outdentList', new IndentCommand( editor, 'backward' ) );\n\n\t\tconst viewDocument = editing.view.document;\n\n\t\t// Overwrite default Enter key behavior.\n\t\t// If Enter key is pressed with selection collapsed in empty list item, outdent it instead of breaking it.\n\t\tthis.listenTo( viewDocument, 'enter', ( evt, data ) => {\n\t\t\tconst doc = this.editor.model.document;\n\t\t\tconst positionParent = doc.selection.getLastPosition().parent;\n\n\t\t\tif ( doc.selection.isCollapsed && positionParent.name == 'listItem' && positionParent.isEmpty ) {\n\t\t\t\tthis.editor.execute( 'outdentList' );\n\n\t\t\t\tdata.preventDefault();\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t} );\n\n\t\t// Overwrite default Backspace key behavior.\n\t\t// If Backspace key is pressed with selection collapsed on first position in first list item, outdent it. #83\n\t\tthis.listenTo( viewDocument, 'delete', ( evt, data ) => {\n\t\t\t// Check conditions from those that require less computations like those immediately available.\n\t\t\tif ( data.direction !== 'backward' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst selection = this.editor.model.document.selection;\n\n\t\t\tif ( !selection.isCollapsed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst firstPosition = selection.getFirstPosition();\n\n\t\t\tif ( !firstPosition.isAtStart ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst positionParent = firstPosition.parent;\n\n\t\t\tif ( positionParent.name !== 'listItem' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst previousIsAListItem = positionParent.previousSibling && positionParent.previousSibling.name === 'listItem';\n\n\t\t\tif ( previousIsAListItem ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.editor.execute( 'outdentList' );\n\n\t\t\tdata.preventDefault();\n\t\t\tevt.stop();\n\t\t}, { priority: 'high' } );\n\n\t\tconst getCommandExecuter = commandName => {\n\t\t\treturn ( data, cancel ) => {\n\t\t\t\tconst command = this.editor.commands.get( commandName );\n\n\t\t\t\tif ( command.isEnabled ) {\n\t\t\t\t\tthis.editor.execute( commandName );\n\t\t\t\t\tcancel();\n\t\t\t\t}\n\t\t\t};\n\t\t};\n\n\t\teditor.keystrokes.set( 'Tab', getCommandExecuter( 'indentList' ) );\n\t\teditor.keystrokes.set( 'Shift+Tab', getCommandExecuter( 'outdentList' ) );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tconst commands = this.editor.commands;\n\n\t\tconst indent = commands.get( 'indent' );\n\t\tconst outdent = commands.get( 'outdent' );\n\n\t\tif ( indent ) {\n\t\t\tindent.registerChildCommand( commands.get( 'indentList' ) );\n\t\t}\n\n\t\tif ( outdent ) {\n\t\t\toutdent.registerChildCommand( commands.get( 'outdentList' ) );\n\t\t}\n\t}\n}\n\nfunction getViewListItemLength( element ) {\n\tlet length = 1;\n\n\tfor ( const child of element.getChildren() ) {\n\t\tif ( child.name == 'ul' || child.name == 'ol' ) {\n\t\t\tfor ( const item of child.getChildren() ) {\n\t\t\t\tlength += getViewListItemLength( item );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn length;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module list/listui\n */\n\nimport { createUIComponent } from './utils';\n\nimport numberedListIcon from '../theme/icons/numberedlist.svg';\nimport bulletedListIcon from '../theme/icons/bulletedlist.svg';\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\n/**\n * The list UI feature. It introduces the `'numberedList'` and `'bulletedList'` buttons that\n * allow to convert paragraphs to and from list items and indent or outdent them.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ListUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst t = this.editor.t;\n\n\t\t// Create two buttons and link them with numberedList and bulletedList commands.\n\t\tcreateUIComponent( this.editor, 'numberedList', t( 'Numbered List' ), numberedListIcon );\n\t\tcreateUIComponent( this.editor, 'bulletedList', t( 'Bulleted List' ), bulletedListIcon );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M7 5.75c0 .414.336.75.75.75h9.5a.75.75 0 1 0 0-1.5h-9.5a.75.75 0 0 0-.75.75zM3.5 3v5H2V3.7H1v-1h2.5V3zM.343 17.857l2.59-3.257H2.92a.6.6 0 1 0-1.04 0H.302a2 2 0 1 1 3.995 0h-.001c-.048.405-.16.734-.333.988-.175.254-.59.692-1.244 1.312H4.3v1h-4l.043-.043zM7 14.75a.75.75 0 0 1 .75-.75h9.5a.75.75 0 1 1 0 1.5h-9.5a.75.75 0 0 1-.75-.75z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M7 5.75c0 .414.336.75.75.75h9.5a.75.75 0 1 0 0-1.5h-9.5a.75.75 0 0 0-.75.75zm-6 0C1 4.784 1.777 4 2.75 4c.966 0 1.75.777 1.75 1.75 0 .966-.777 1.75-1.75 1.75C1.784 7.5 1 6.723 1 5.75zm6 9c0 .414.336.75.75.75h9.5a.75.75 0 1 0 0-1.5h-9.5a.75.75 0 0 0-.75.75zm-6 0c0-.966.777-1.75 1.75-1.75.966 0 1.75.777 1.75 1.75 0 .966-.777 1.75-1.75 1.75-.966 0-1.75-.777-1.75-1.75z\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module media-embed/converters\n */\n\n/**\n * Returns a function that converts the model \"url\" attribute to the view representation.\n *\n * Depending on the configuration, the view representation can be \"semantic\" (for the data pipeline):\n *\n *\t\t<figure class=\"media\">\n *\t\t\t<oembed url=\"foo\"></oembed>\n *\t\t</figure>\n *\n * or \"non-semantic\" (for the editing view pipeline):\n *\n *\t\t<figure class=\"media\">\n *\t\t\t<div data-oembed-url=\"foo\">[ non-semantic media preview for \"foo\" ]</div>\n *\t\t</figure>\n *\n * **Note:** Changing the model \"url\" attribute replaces the entire content of the\n * `<figure>` in the view.\n *\n * @param {module:media-embed/mediaregistry~MediaRegistry} registry The registry providing\n * the media and their content.\n * @param {Object} options\n * @param {String} [options.renderMediaPreview] When `true`, the converter will create the view in the non-semantic form.\n * @param {String} [options.renderForEditingView] When `true`, the converter will create a view specific for the\n * editing pipeline (e.g. including CSS classes, content placeholders).\n * @returns {Function}\n */\nexport function modelToViewUrlAttributeConverter( registry, options ) {\n\treturn dispatcher => {\n\t\tdispatcher.on( 'attribute:url:media', converter );\n\t};\n\n\tfunction converter( evt, data, conversionApi ) {\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst url = data.attributeNewValue;\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst figure = conversionApi.mapper.toViewElement( data.item );\n\t\tconst mediaContentElement = [ ...figure.getChildren() ]\n\t\t\t.find( child => child.getCustomProperty( 'media-content' ) );\n\n\t\t// TODO: removing the wrapper and creating it from scratch is a hack. We can do better than that.\n\t\tviewWriter.remove( mediaContentElement );\n\n\t\tconst mediaViewElement = registry.getMediaViewElement( viewWriter, url, options );\n\n\t\tviewWriter.insert( viewWriter.createPositionAt( figure, 0 ), mediaViewElement );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module media-embed/utils\n */\n\nimport { isWidget, toWidget } from '@ckeditor/ckeditor5-widget/src/utils';\n\n/**\n * Converts a given {@link module:engine/view/element~Element} to a media embed widget:\n * * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to recognize the media widget element.\n * * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator.\n *\n * @param {module:engine/view/element~Element} viewElement\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer An instance of the view writer.\n * @param {String} label The element's label.\n * @returns {module:engine/view/element~Element}\n */\nexport function toMediaWidget( viewElement, writer, label ) {\n\twriter.setCustomProperty( 'media', true, viewElement );\n\n\treturn toWidget( viewElement, writer, { label } );\n}\n\n/**\n * Returns a media widget editing view element if one is selected.\n *\n * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} selection\n * @returns {module:engine/view/element~Element|null}\n */\nexport function getSelectedMediaViewWidget( selection ) {\n\tconst viewElement = selection.getSelectedElement();\n\n\tif ( viewElement && isMediaWidget( viewElement ) ) {\n\t\treturn viewElement;\n\t}\n\n\treturn null;\n}\n\n/**\n * Checks if a given view element is a media widget.\n *\n * @param {module:engine/view/element~Element} viewElement\n * @returns {Boolean}\n */\nexport function isMediaWidget( viewElement ) {\n\treturn !!viewElement.getCustomProperty( 'media' ) && isWidget( viewElement );\n}\n\n/**\n * Creates a view element representing the media. Either a \"semantic\" one for the data pipeline:\n *\n *\t\t<figure class=\"media\">\n *\t\t\t<oembed url=\"foo\"></oembed>\n *\t\t</figure>\n *\n * or a \"non-semantic\" (for the editing view pipeline):\n *\n *\t\t<figure class=\"media\">\n *\t\t\t<div data-oembed-url=\"foo\">[ non-semantic media preview for \"foo\" ]</div>\n *\t\t</figure>\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {module:media-embed/mediaregistry~MediaRegistry} registry\n * @param {String} url\n * @param {Object} options\n * @param {String} [options.useSemanticWrapper]\n * @param {String} [options.renderForEditingView]\n * @returns {module:engine/view/containerelement~ContainerElement}\n */\nexport function createMediaFigureElement( writer, registry, url, options ) {\n\tconst figure = writer.createContainerElement( 'figure', { class: 'media' } );\n\n\twriter.insert( writer.createPositionAt( figure, 0 ), registry.getMediaViewElement( writer, url, options ) );\n\n\treturn figure;\n}\n\n/**\n * Returns a selected media element in the model, if any.\n *\n * @param {module:engine/model/selection~Selection} selection\n * @returns {module:engine/model/element~Element|null}\n */\nexport function getSelectedMediaModelWidget( selection ) {\n\tconst selectedElement = selection.getSelectedElement();\n\n\tif ( selectedElement && selectedElement.is( 'element', 'media' ) ) {\n\t\treturn selectedElement;\n\t}\n\n\treturn null;\n}\n\n/**\n * Creates a media element and inserts it into the model.\n *\n * **Note**: This method will use {@link module:engine/model/model~Model#insertContent `model.insertContent()`} logic of inserting content\n * if no `insertPosition` is passed.\n *\n * @param {module:engine/model/model~Model} model\n * @param {String} url An URL of an embeddable media.\n * @param {module:engine/model/position~Position} [insertPosition] Position to insert the media. If not specified,\n * the default behavior of {@link module:engine/model/model~Model#insertContent `model.insertContent()`} will\n * be applied.\n */\nexport function insertMedia( model, url, insertPosition ) {\n\tmodel.change( writer => {\n\t\tconst mediaElement = writer.createElement( 'media', { url } );\n\n\t\tmodel.insertContent( mediaElement, insertPosition );\n\n\t\twriter.setSelection( mediaElement, 'on' );\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module media-embed/mediaembedcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { findOptimalInsertionPosition } from '@ckeditor/ckeditor5-widget/src/utils';\nimport { getSelectedMediaModelWidget, insertMedia } from './utils';\n\n/**\n * The insert media command.\n *\n * The command is registered by the {@link module:media-embed/mediaembedediting~MediaEmbedEditing} as `'mediaEmbed'`.\n *\n * To insert media at the current selection, execute the command and specify the URL:\n *\n *\t\teditor.execute( 'mediaEmbed', 'http://url.to.the/media' );\n *\n * @extends module:core/command~Command\n */\nexport default class MediaEmbedCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst schema = model.schema;\n\t\tconst insertPosition = findOptimalInsertionPosition( selection, model );\n\t\tconst selectedMedia = getSelectedMediaModelWidget( selection );\n\n\t\tlet parent = insertPosition.parent;\n\n\t\t// The model.insertContent() will remove empty parent (unless it is a $root or a limit).\n\t\tif ( parent.isEmpty && !model.schema.isLimit( parent ) ) {\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\tthis.value = selectedMedia ? selectedMedia.getAttribute( 'url' ) : null;\n\t\tthis.isEnabled = schema.checkChild( parent, 'media' );\n\t}\n\n\t/**\n\t * Executes the command, which either:\n\t *\n\t * * updates the URL of the selected media,\n\t * * inserts the new media into the editor and puts the selection around it.\n\t *\n\t * @fires execute\n\t * @param {String} url The URL of the media.\n\t */\n\texecute( url ) {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst selectedMedia = getSelectedMediaModelWidget( selection );\n\n\t\tif ( selectedMedia ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\twriter.setAttribute( 'url', url, selectedMedia );\n\t\t\t} );\n\t\t} else {\n\t\t\tconst insertPosition = findOptimalInsertionPosition( selection, model );\n\n\t\t\tinsertMedia( model, url, insertPosition );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module media-embed/mediaregistry\n */\n\nimport mediaPlaceholderIcon from '../theme/icons/media-placeholder.svg';\nimport TooltipView from '@ckeditor/ckeditor5-ui/src/tooltip/tooltipview';\nimport IconView from '@ckeditor/ckeditor5-ui/src/icon/iconview';\nimport Template from '@ckeditor/ckeditor5-ui/src/template';\nimport { logWarning } from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport toArray from '@ckeditor/ckeditor5-utils/src/toarray';\n\nconst mediaPlaceholderIconViewBox = '0 0 64 42';\n\n/**\n * A bridge between the raw media content provider definitions and the editor view content.\n *\n * It helps translating media URLs to corresponding {@link module:engine/view/element~Element view elements}.\n *\n * Mostly used by the {@link module:media-embed/mediaembedediting~MediaEmbedEditing} plugin.\n */\nexport default class MediaRegistry {\n\t/**\n\t * Creates an instance of the {@link module:media-embed/mediaregistry~MediaRegistry} class.\n\t *\n\t * @param {module:utils/locale~Locale} locale The localization services instance.\n\t * @param {module:media-embed/mediaembed~MediaEmbedConfig} config The configuration of the media embed feature.\n\t */\n\tconstructor( locale, config ) {\n\t\tconst providers = config.providers;\n\t\tconst extraProviders = config.extraProviders || [];\n\t\tconst removedProviders = new Set( config.removeProviders );\n\t\tconst providerDefinitions = providers\n\t\t\t.concat( extraProviders )\n\t\t\t.filter( provider => {\n\t\t\t\tconst name = provider.name;\n\n\t\t\t\tif ( !name ) {\n\t\t\t\t\t/**\n\t\t\t\t\t * One of the providers (or extra providers) specified in the media embed configuration\n\t\t\t\t\t * has no name and will not be used by the editor. In order to get this media\n\t\t\t\t\t * provider working, double check your editor configuration.\n\t\t\t\t\t *\n\t\t\t\t\t * @error media-embed-no-provider-name\n\t\t\t\t\t */\n\t\t\t\t\tlogWarning( 'media-embed-no-provider-name', { provider } );\n\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\treturn !removedProviders.has( name );\n\t\t\t} );\n\n\t\t/**\n\t\t * The {@link module:utils/locale~Locale} instance.\n\t\t *\n\t\t * @member {module:utils/locale~Locale}\n\t\t */\n\t\tthis.locale = locale;\n\n\t\t/**\n\t\t * The media provider definitions available for the registry. Usually corresponding with the\n\t\t * {@link module:media-embed/mediaembed~MediaEmbedConfig media configuration}.\n\t\t *\n\t\t * @member {Array}\n\t\t */\n\t\tthis.providerDefinitions = providerDefinitions;\n\t}\n\n\t/**\n\t * Checks whether the passed URL is representing a certain media type allowed in the editor.\n\t *\n\t * @param {String} url The URL to be checked\n\t * @returns {Boolean}\n\t */\n\thasMedia( url ) {\n\t\treturn !!this._getMedia( url );\n\t}\n\n\t/**\n\t * For the given media URL string and options, it returns the {@link module:engine/view/element~Element view element}\n\t * representing that media.\n\t *\n\t * **Note:** If no URL is specified, an empty view element is returned.\n\t *\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer used to produce a view element.\n\t * @param {String} url The URL to be translated into a view element.\n\t * @param {Object} options\n\t * @param {String} [options.renderMediaPreview]\n\t * @param {String} [options.renderForEditingView]\n\t * @returns {module:engine/view/element~Element}\n\t */\n\tgetMediaViewElement( writer, url, options ) {\n\t\treturn this._getMedia( url ).getViewElement( writer, options );\n\t}\n\n\t/**\n\t * Returns a `Media` instance for the given URL.\n\t *\n\t * @protected\n\t * @param {String} url The URL of the media.\n\t * @returns {module:media-embed/mediaregistry~Media|null} The `Media` instance or `null` when there is none.\n\t */\n\t_getMedia( url ) {\n\t\tif ( !url ) {\n\t\t\treturn new Media( this.locale );\n\t\t}\n\n\t\turl = url.trim();\n\n\t\tfor ( const definition of this.providerDefinitions ) {\n\t\t\tconst previewRenderer = definition.html;\n\t\t\tconst pattern = toArray( definition.url );\n\n\t\t\tfor ( const subPattern of pattern ) {\n\t\t\t\tconst match = this._getUrlMatches( url, subPattern );\n\n\t\t\t\tif ( match ) {\n\t\t\t\t\treturn new Media( this.locale, url, match, previewRenderer );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Tries to match `url` to `pattern`.\n\t *\n\t * @private\n\t * @param {String} url The URL of the media.\n\t * @param {RegExp} pattern The pattern that should accept the media URL.\n\t * @returns {Array|null}\n\t */\n\t_getUrlMatches( url, pattern ) {\n\t\t// 1. Try to match without stripping the protocol and \"www\" subdomain.\n\t\tlet match = url.match( pattern );\n\n\t\tif ( match ) {\n\t\t\treturn match;\n\t\t}\n\n\t\t// 2. Try to match after stripping the protocol.\n\t\tlet rawUrl = url.replace( /^https?:\\/\\//, '' );\n\t\tmatch = rawUrl.match( pattern );\n\n\t\tif ( match ) {\n\t\t\treturn match;\n\t\t}\n\n\t\t// 3. Try to match after stripping the \"www\" subdomain.\n\t\trawUrl = rawUrl.replace( /^www\\./, '' );\n\t\tmatch = rawUrl.match( pattern );\n\n\t\tif ( match ) {\n\t\t\treturn match;\n\t\t}\n\n\t\treturn null;\n\t}\n}\n\n/**\n * Represents media defined by the provider configuration.\n *\n * It can be rendered to the {@link module:engine/view/element~Element view element} and used in the editing or data pipeline.\n *\n * @private\n */\nclass Media {\n\tconstructor( locale, url, match, previewRenderer ) {\n\t\t/**\n\t\t * The URL this Media instance represents.\n\t\t *\n\t\t * @member {String}\n\t\t */\n\t\tthis.url = this._getValidUrl( url );\n\n\t\t/**\n\t\t * Shorthand for {@link module:utils/locale~Locale#t}.\n\t\t *\n\t\t * @see module:utils/locale~Locale#t\n\t\t * @method\n\t\t */\n\t\tthis._t = locale.t;\n\n\t\t/**\n\t\t * The output of the `RegExp.match` which validated the {@link #url} of this media.\n\t\t *\n\t\t * @member {Object}\n\t\t */\n\t\tthis._match = match;\n\n\t\t/**\n\t\t * The function returning the HTML string preview of this media.\n\t\t *\n\t\t * @member {Function}\n\t\t */\n\t\tthis._previewRenderer = previewRenderer;\n\t}\n\n\t/**\n\t * Returns the view element representation of the media.\n\t *\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer used to produce a view element.\n\t * @param {Object} options\n\t * @param {String} [options.renderMediaPreview]\n\t * @param {String} [options.renderForEditingView]\n\t * @returns {module:engine/view/element~Element}\n\t */\n\tgetViewElement( writer, options ) {\n\t\tconst attributes = {};\n\t\tlet viewElement;\n\n\t\tif ( options.renderForEditingView || ( options.renderMediaPreview && this.url && this._previewRenderer ) ) {\n\t\t\tif ( this.url ) {\n\t\t\t\tattributes[ 'data-oembed-url' ] = this.url;\n\t\t\t}\n\n\t\t\tif ( options.renderForEditingView ) {\n\t\t\t\tattributes.class = 'ck-media__wrapper';\n\t\t\t}\n\n\t\t\tconst mediaHtml = this._getPreviewHtml( options );\n\n\t\t\tviewElement = writer.createRawElement( 'div', attributes, function( domElement ) {\n\t\t\t\tdomElement.innerHTML = mediaHtml;\n\t\t\t} );\n\t\t} else {\n\t\t\tif ( this.url ) {\n\t\t\t\tattributes.url = this.url;\n\t\t\t}\n\n\t\t\tviewElement = writer.createEmptyElement( 'oembed', attributes );\n\t\t}\n\n\t\twriter.setCustomProperty( 'media-content', true, viewElement );\n\n\t\treturn viewElement;\n\t}\n\n\t/**\n\t * Returns the HTML string of the media content preview.\n\t *\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer used to produce a view element.\n\t * @param {Object} options\n\t * @param {String} [options.renderForEditingView]\n\t * @returns {String}\n\t */\n\t_getPreviewHtml( options ) {\n\t\tif ( this._previewRenderer ) {\n\t\t\treturn this._previewRenderer( this._match );\n\t\t} else {\n\t\t\t// The placeholder only makes sense for editing view and media which have URLs.\n\t\t\t// Placeholder is never displayed in data and URL-less media have no content.\n\t\t\tif ( this.url && options.renderForEditingView ) {\n\t\t\t\treturn this._getPlaceholderHtml();\n\t\t\t}\n\n\t\t\treturn '';\n\t\t}\n\t}\n\n\t/**\n\t * Returns the placeholder HTML when the media has no content preview.\n\t *\n\t * @returns {String}\n\t */\n\t_getPlaceholderHtml() {\n\t\tconst tooltip = new TooltipView();\n\t\tconst icon = new IconView();\n\n\t\ttooltip.text = this._t( 'Open media in new tab' );\n\t\ticon.content = mediaPlaceholderIcon;\n\t\ticon.viewBox = mediaPlaceholderIconViewBox;\n\n\t\tconst placeholder = new Template( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck ck-reset_all ck-media__placeholder'\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: 'ck-media__placeholder__icon'\n\t\t\t\t\t},\n\t\t\t\t\tchildren: [ icon ]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttag: 'a',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: 'ck-media__placeholder__url',\n\t\t\t\t\t\ttarget: '_blank',\n\t\t\t\t\t\trel: 'noopener noreferrer',\n\t\t\t\t\t\thref: this.url\n\t\t\t\t\t},\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttag: 'span',\n\t\t\t\t\t\t\tattributes: {\n\t\t\t\t\t\t\t\tclass: 'ck-media__placeholder__url__text'\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tchildren: [ this.url ]\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttooltip\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t} ).render();\n\n\t\treturn placeholder.outerHTML;\n\t}\n\n\t/**\n\t * Returns the full URL to the specified media.\n\t *\n\t * @param {String} url The URL of the media.\n\t * @returns {String|null}\n\t */\n\t_getValidUrl( url ) {\n\t\tif ( !url ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( url.match( /^https?/ ) ) {\n\t\t\treturn url;\n\t\t}\n\n\t\treturn 'https://' + url;\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 64 42\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M47.426 17V3.713L63.102 0v19.389h-.001l.001.272c0 1.595-2.032 3.43-4.538 4.098-2.506.668-4.538-.083-4.538-1.678 0-1.594 2.032-3.43 4.538-4.098.914-.244 2.032-.565 2.888-.603V4.516L49.076 7.447v9.556A1.014 1.014 0 0 0 49 17h-1.574zM29.5 17h-8.343a7.073 7.073 0 1 0-4.657 4.06v3.781H3.3a2.803 2.803 0 0 1-2.8-2.804V8.63a2.803 2.803 0 0 1 2.8-2.805h4.082L8.58 2.768A1.994 1.994 0 0 1 10.435 1.5h8.985c.773 0 1.477.448 1.805 1.149l1.488 3.177H26.7c1.546 0 2.8 1.256 2.8 2.805V17zm-11.637 0H17.5a1 1 0 0 0-1 1v.05A4.244 4.244 0 1 1 17.863 17zm29.684 2c.97 0 .953-.048.953.889v20.743c0 .953.016.905-.953.905H19.453c-.97 0-.953.048-.953-.905V19.89c0-.937-.016-.889.97-.889h28.077zm-4.701 19.338V22.183H24.154v16.155h18.692zM20.6 21.375v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616V37.53H20.6zm24.233-16.155v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615V37.53h-1.615zM29.485 25.283a.4.4 0 0 1 .593-.35l9.05 4.977a.4.4 0 0 1 0 .701l-9.05 4.978a.4.4 0 0 1-.593-.35v-9.956z\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module media-embed/mediaembedediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport { modelToViewUrlAttributeConverter } from './converters';\nimport MediaEmbedCommand from './mediaembedcommand';\nimport MediaRegistry from './mediaregistry';\nimport { toMediaWidget, createMediaFigureElement } from './utils';\n\nimport '../theme/mediaembedediting.css';\n\n/**\n * The media embed editing feature.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class MediaEmbedEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'MediaEmbedEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( 'mediaEmbed', {\n\t\t\tproviders: [\n\t\t\t\t{\n\t\t\t\t\tname: 'dailymotion',\n\t\t\t\t\turl: /^dailymotion\\.com\\/video\\/(\\w+)/,\n\t\t\t\t\thtml: match => {\n\t\t\t\t\t\tconst id = match[ 1 ];\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t'<div style=\"position: relative; padding-bottom: 100%; height: 0; \">' +\n\t\t\t\t\t\t\t\t`<iframe src=\"https://www.dailymotion.com/embed/video/${ id }\" ` +\n\t\t\t\t\t\t\t\t\t'style=\"position: absolute; width: 100%; height: 100%; top: 0; left: 0;\" ' +\n\t\t\t\t\t\t\t\t\t'frameborder=\"0\" width=\"480\" height=\"270\" allowfullscreen allow=\"autoplay\">' +\n\t\t\t\t\t\t\t\t'</iframe>' +\n\t\t\t\t\t\t\t'</div>'\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t{\n\t\t\t\t\tname: 'spotify',\n\t\t\t\t\turl: [\n\t\t\t\t\t\t/^open\\.spotify\\.com\\/(artist\\/\\w+)/,\n\t\t\t\t\t\t/^open\\.spotify\\.com\\/(album\\/\\w+)/,\n\t\t\t\t\t\t/^open\\.spotify\\.com\\/(track\\/\\w+)/\n\t\t\t\t\t],\n\t\t\t\t\thtml: match => {\n\t\t\t\t\t\tconst id = match[ 1 ];\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t'<div style=\"position: relative; padding-bottom: 100%; height: 0; padding-bottom: 126%;\">' +\n\t\t\t\t\t\t\t\t`<iframe src=\"https://open.spotify.com/embed/${ id }\" ` +\n\t\t\t\t\t\t\t\t\t'style=\"position: absolute; width: 100%; height: 100%; top: 0; left: 0;\" ' +\n\t\t\t\t\t\t\t\t\t'frameborder=\"0\" allowtransparency=\"true\" allow=\"encrypted-media\">' +\n\t\t\t\t\t\t\t\t'</iframe>' +\n\t\t\t\t\t\t\t'</div>'\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t{\n\t\t\t\t\tname: 'youtube',\n\t\t\t\t\turl: [\n\t\t\t\t\t\t/^(?:m\\.)?youtube\\.com\\/watch\\?v=([\\w-]+)/,\n\t\t\t\t\t\t/^(?:m\\.)?youtube\\.com\\/v\\/([\\w-]+)/,\n\t\t\t\t\t\t/^youtube\\.com\\/embed\\/([\\w-]+)/,\n\t\t\t\t\t\t/^youtu\\.be\\/([\\w-]+)/\n\t\t\t\t\t],\n\t\t\t\t\thtml: match => {\n\t\t\t\t\t\tconst id = match[ 1 ];\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t'<div style=\"position: relative; padding-bottom: 100%; height: 0; padding-bottom: 56.2493%;\">' +\n\t\t\t\t\t\t\t\t`<iframe src=\"https://www.youtube.com/embed/${ id }\" ` +\n\t\t\t\t\t\t\t\t\t'style=\"position: absolute; width: 100%; height: 100%; top: 0; left: 0;\" ' +\n\t\t\t\t\t\t\t\t\t'frameborder=\"0\" allow=\"autoplay; encrypted-media\" allowfullscreen>' +\n\t\t\t\t\t\t\t\t'</iframe>' +\n\t\t\t\t\t\t\t'</div>'\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t{\n\t\t\t\t\tname: 'vimeo',\n\t\t\t\t\turl: [\n\t\t\t\t\t\t/^vimeo\\.com\\/(\\d+)/,\n\t\t\t\t\t\t/^vimeo\\.com\\/[^/]+\\/[^/]+\\/video\\/(\\d+)/,\n\t\t\t\t\t\t/^vimeo\\.com\\/album\\/[^/]+\\/video\\/(\\d+)/,\n\t\t\t\t\t\t/^vimeo\\.com\\/channels\\/[^/]+\\/(\\d+)/,\n\t\t\t\t\t\t/^vimeo\\.com\\/groups\\/[^/]+\\/videos\\/(\\d+)/,\n\t\t\t\t\t\t/^vimeo\\.com\\/ondemand\\/[^/]+\\/(\\d+)/,\n\t\t\t\t\t\t/^player\\.vimeo\\.com\\/video\\/(\\d+)/\n\t\t\t\t\t],\n\t\t\t\t\thtml: match => {\n\t\t\t\t\t\tconst id = match[ 1 ];\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t'<div style=\"position: relative; padding-bottom: 100%; height: 0; padding-bottom: 56.2493%;\">' +\n\t\t\t\t\t\t\t\t`<iframe src=\"https://player.vimeo.com/video/${ id }\" ` +\n\t\t\t\t\t\t\t\t\t'style=\"position: absolute; width: 100%; height: 100%; top: 0; left: 0;\" ' +\n\t\t\t\t\t\t\t\t\t'frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen>' +\n\t\t\t\t\t\t\t\t'</iframe>' +\n\t\t\t\t\t\t\t'</div>'\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t{\n\t\t\t\t\tname: 'instagram',\n\t\t\t\t\turl: /^instagram\\.com\\/p\\/(\\w+)/\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: 'twitter',\n\t\t\t\t\turl: /^twitter\\.com/\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: 'googleMaps',\n\t\t\t\t\turl: /^google\\.com\\/maps/\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: 'flickr',\n\t\t\t\t\turl: /^flickr\\.com/\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: 'facebook',\n\t\t\t\t\turl: /^facebook\\.com/\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\t/**\n\t\t * The media registry managing the media providers in the editor.\n\t\t *\n\t\t * @member {module:media-embed/mediaregistry~MediaRegistry} #registry\n\t\t */\n\t\tthis.registry = new MediaRegistry( editor.locale, editor.config.get( 'mediaEmbed' ) );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\t\tconst t = editor.t;\n\t\tconst conversion = editor.conversion;\n\t\tconst renderMediaPreview = editor.config.get( 'mediaEmbed.previewsInData' );\n\t\tconst registry = this.registry;\n\n\t\teditor.commands.add( 'mediaEmbed', new MediaEmbedCommand( editor ) );\n\n\t\t// Configure the schema.\n\t\tschema.register( 'media', {\n\t\t\tisObject: true,\n\t\t\tisBlock: true,\n\t\t\tallowWhere: '$block',\n\t\t\tallowAttributes: [ 'url' ]\n\t\t} );\n\n\t\t// Model -> Data\n\t\tconversion.for( 'dataDowncast' ).elementToElement( {\n\t\t\tmodel: 'media',\n\t\t\tview: ( modelElement, { writer } ) => {\n\t\t\t\tconst url = modelElement.getAttribute( 'url' );\n\n\t\t\t\treturn createMediaFigureElement( writer, registry, url, {\n\t\t\t\t\trenderMediaPreview: url && renderMediaPreview\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\t// Model -> Data (url -> data-oembed-url)\n\t\tconversion.for( 'dataDowncast' ).add(\n\t\t\tmodelToViewUrlAttributeConverter( registry, {\n\t\t\t\trenderMediaPreview\n\t\t\t} ) );\n\n\t\t// Model -> View (element)\n\t\tconversion.for( 'editingDowncast' ).elementToElement( {\n\t\t\tmodel: 'media',\n\t\t\tview: ( modelElement, { writer } ) => {\n\t\t\t\tconst url = modelElement.getAttribute( 'url' );\n\t\t\t\tconst figure = createMediaFigureElement( writer, registry, url, {\n\t\t\t\t\trenderForEditingView: true\n\t\t\t\t} );\n\n\t\t\t\treturn toMediaWidget( figure, writer, t( 'media widget' ) );\n\t\t\t}\n\t\t} );\n\n\t\t// Model -> View (url -> data-oembed-url)\n\t\tconversion.for( 'editingDowncast' ).add(\n\t\t\tmodelToViewUrlAttributeConverter( registry, {\n\t\t\t\trenderForEditingView: true\n\t\t\t} ) );\n\n\t\t// View -> Model (data-oembed-url -> url)\n\t\tconversion.for( 'upcast' )\n\t\t\t// Upcast semantic media.\n\t\t\t.elementToElement( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'oembed',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\turl: true\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tmodel: ( viewMedia, { writer } ) => {\n\t\t\t\t\tconst url = viewMedia.getAttribute( 'url' );\n\n\t\t\t\t\tif ( registry.hasMedia( url ) ) {\n\t\t\t\t\t\treturn writer.createElement( 'media', { url } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} )\n\t\t\t// Upcast non-semantic media.\n\t\t\t.elementToElement( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\t'data-oembed-url': true\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tmodel: ( viewMedia, { writer } ) => {\n\t\t\t\t\tconst url = viewMedia.getAttribute( 'data-oembed-url' );\n\n\t\t\t\t\tif ( registry.hasMedia( url ) ) {\n\t\t\t\t\t\treturn writer.createElement( 'media', { url } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module media-embed/automediaembed\n */\n\nimport MediaEmbedEditing from './mediaembedediting';\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';\nimport LiveRange from '@ckeditor/ckeditor5-engine/src/model/liverange';\nimport LivePosition from '@ckeditor/ckeditor5-engine/src/model/liveposition';\nimport Undo from '@ckeditor/ckeditor5-undo/src/undo';\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport { insertMedia } from './utils';\n\nconst URL_REGEXP = /^(?:http(s)?:\\/\\/)?[\\w.-]+(?:\\.[\\w.-]+)+[\\w\\-._~:/?#[\\]@!$&'()*+,;=%]+$/;\n\n/**\n * The auto-media embed plugin. It recognizes media links in the pasted content and embeds\n * them shortly after they are injected into the document.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class AutoMediaEmbed extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ Clipboard, Undo ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'AutoMediaEmbed';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The paste–to–embed `setTimeout` ID. Stored as a property to allow\n\t\t * cleaning of the timeout.\n\t\t *\n\t\t * @private\n\t\t * @member {Number} #_timeoutId\n\t\t */\n\t\tthis._timeoutId = null;\n\n\t\t/**\n\t\t * The position where the `<media>` element will be inserted after the timeout,\n\t\t * determined each time the new content is pasted into the document.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/liveposition~LivePosition} #_positionToInsert\n\t\t */\n\t\tthis._positionToInsert = null;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst modelDocument = editor.model.document;\n\n\t\t// We need to listen on `Clipboard#inputTransformation` because we need to save positions of selection.\n\t\t// After pasting, the content between those positions will be checked for a URL that could be transformed\n\t\t// into media.\n\t\tthis.listenTo( editor.plugins.get( Clipboard ), 'inputTransformation', () => {\n\t\t\tconst firstRange = modelDocument.selection.getFirstRange();\n\n\t\t\tconst leftLivePosition = LivePosition.fromPosition( firstRange.start );\n\t\t\tleftLivePosition.stickiness = 'toPrevious';\n\n\t\t\tconst rightLivePosition = LivePosition.fromPosition( firstRange.end );\n\t\t\trightLivePosition.stickiness = 'toNext';\n\n\t\t\tmodelDocument.once( 'change:data', () => {\n\t\t\t\tthis._embedMediaBetweenPositions( leftLivePosition, rightLivePosition );\n\n\t\t\t\tleftLivePosition.detach();\n\t\t\t\trightLivePosition.detach();\n\t\t\t}, { priority: 'high' } );\n\t\t} );\n\n\t\teditor.commands.get( 'undo' ).on( 'execute', () => {\n\t\t\tif ( this._timeoutId ) {\n\t\t\t\tglobal.window.clearTimeout( this._timeoutId );\n\t\t\t\tthis._positionToInsert.detach();\n\n\t\t\t\tthis._timeoutId = null;\n\t\t\t\tthis._positionToInsert = null;\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * Analyzes the part of the document between provided positions in search for a URL representing media.\n\t * When the URL is found, it is automatically converted into media.\n\t *\n\t * @protected\n\t * @param {module:engine/model/liveposition~LivePosition} leftPosition Left position of the selection.\n\t * @param {module:engine/model/liveposition~LivePosition} rightPosition Right position of the selection.\n\t */\n\t_embedMediaBetweenPositions( leftPosition, rightPosition ) {\n\t\tconst editor = this.editor;\n\t\tconst mediaRegistry = editor.plugins.get( MediaEmbedEditing ).registry;\n\t\t// TODO: Use marker instead of LiveRange & LivePositions.\n\t\tconst urlRange = new LiveRange( leftPosition, rightPosition );\n\t\tconst walker = urlRange.getWalker( { ignoreElementEnd: true } );\n\n\t\tlet url = '';\n\n\t\tfor ( const node of walker ) {\n\t\t\tif ( node.item.is( '$textProxy' ) ) {\n\t\t\t\turl += node.item.data;\n\t\t\t}\n\t\t}\n\n\t\turl = url.trim();\n\n\t\t// If the URL does not match to universal URL regexp, let's skip that.\n\t\tif ( !url.match( URL_REGEXP ) ) {\n\t\t\turlRange.detach();\n\n\t\t\treturn;\n\t\t}\n\n\t\t// If the URL represents a media, let's use it.\n\t\tif ( !mediaRegistry.hasMedia( url ) ) {\n\t\t\turlRange.detach();\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst mediaEmbedCommand = editor.commands.get( 'mediaEmbed' );\n\n\t\t// Do not anything if media element cannot be inserted at the current position (#47).\n\t\tif ( !mediaEmbedCommand.isEnabled ) {\n\t\t\turlRange.detach();\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Position won't be available in the `setTimeout` function so let's clone it.\n\t\tthis._positionToInsert = LivePosition.fromPosition( leftPosition );\n\n\t\t// This action mustn't be executed if undo was called between pasting and auto-embedding.\n\t\tthis._timeoutId = global.window.setTimeout( () => {\n\t\t\teditor.model.change( writer => {\n\t\t\t\tthis._timeoutId = null;\n\n\t\t\t\twriter.remove( urlRange );\n\t\t\t\turlRange.detach();\n\n\t\t\t\tlet insertionPosition;\n\n\t\t\t\t// Check if position where the media element should be inserted is still valid.\n\t\t\t\t// Otherwise leave it as undefined to use document.selection - default behavior of model.insertContent().\n\t\t\t\tif ( this._positionToInsert.root.rootName !== '$graveyard' ) {\n\t\t\t\t\tinsertionPosition = this._positionToInsert;\n\t\t\t\t}\n\n\t\t\t\tinsertMedia( editor.model, url, insertionPosition );\n\n\t\t\t\tthis._positionToInsert.detach();\n\t\t\t\tthis._positionToInsert = null;\n\t\t\t} );\n\t\t}, 100 );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module media-embed/ui/mediaformview\n */\n\nimport View from '@ckeditor/ckeditor5-ui/src/view';\nimport ViewCollection from '@ckeditor/ckeditor5-ui/src/viewcollection';\n\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\n\nimport LabeledFieldView from '@ckeditor/ckeditor5-ui/src/labeledfield/labeledfieldview';\nimport { createLabeledInputText } from '@ckeditor/ckeditor5-ui/src/labeledfield/utils';\n\nimport submitHandler from '@ckeditor/ckeditor5-ui/src/bindings/submithandler';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport FocusCycler from '@ckeditor/ckeditor5-ui/src/focuscycler';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\nimport injectCssTransitionDisabler from '@ckeditor/ckeditor5-ui/src/bindings/injectcsstransitiondisabler';\n\nimport checkIcon from '@ckeditor/ckeditor5-core/theme/icons/check.svg';\nimport cancelIcon from '@ckeditor/ckeditor5-core/theme/icons/cancel.svg';\nimport '../../theme/mediaform.css';\nimport '@ckeditor/ckeditor5-ui/theme/components/responsive-form/responsiveform.css';\n\n/**\n * The media form view controller class.\n *\n * See {@link module:media-embed/ui/mediaformview~MediaFormView}.\n *\n * @extends module:ui/view~View\n */\nexport default class MediaFormView extends View {\n\t/**\n\t * @param {Array.<Function>} validators Form validators used by {@link #isValid}.\n\t * @param {module:utils/locale~Locale} [locale] The localization services instance.\n\t */\n\tconstructor( validators, locale ) {\n\t\tsuper( locale );\n\n\t\tconst t = locale.t;\n\n\t\t/**\n\t\t * Tracks information about the DOM focus in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * The value of the URL input.\n\t\t *\n\t\t * @member {String} #mediaURLInputValue\n\t\t * @observable\n\t\t */\n\t\tthis.set( 'mediaURLInputValue', '' );\n\n\t\t/**\n\t\t * The URL input view.\n\t\t *\n\t\t * @member {module:ui/labeledfield/labeledfieldview~LabeledFieldView}\n\t\t */\n\t\tthis.urlInputView = this._createUrlInput();\n\n\t\t/**\n\t\t * The Save button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.saveButtonView = this._createButton( t( 'Save' ), checkIcon, 'ck-button-save' );\n\t\tthis.saveButtonView.type = 'submit';\n\t\tthis.saveButtonView.bind( 'isEnabled' ).to( this, 'mediaURLInputValue', value => !!value );\n\n\t\t/**\n\t\t * The Cancel button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.cancelButtonView = this._createButton( t( 'Cancel' ), cancelIcon, 'ck-button-cancel', 'cancel' );\n\n\t\t/**\n\t\t * A collection of views that can be focused in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis._focusables = new ViewCollection();\n\n\t\t/**\n\t\t * Helps cycling over {@link #_focusables} in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this._focusables,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate form fields backwards using the <kbd>Shift</kbd> + <kbd>Tab</kbd> keystroke.\n\t\t\t\tfocusPrevious: 'shift + tab',\n\n\t\t\t\t// Navigate form fields forwards using the <kbd>Tab</kbd> key.\n\t\t\t\tfocusNext: 'tab'\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * An array of form validators used by {@link #isValid}.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {Array.<Function>}\n\t\t */\n\t\tthis._validators = validators;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'form',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-media-form',\n\t\t\t\t\t'ck-responsive-form'\n\t\t\t\t],\n\n\t\t\t\ttabindex: '-1'\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\tthis.urlInputView,\n\t\t\t\tthis.saveButtonView,\n\t\t\t\tthis.cancelButtonView\n\t\t\t]\n\t\t} );\n\n\t\tinjectCssTransitionDisabler( this );\n\n\t\t/**\n\t\t * The default info text for the {@link #urlInputView}.\n\t\t *\n\t\t * @private\n\t\t * @member {String} #_urlInputViewInfoDefault\n\t\t */\n\n\t\t/**\n\t\t * The info text with an additional tip for the {@link #urlInputView},\n\t\t * displayed when the input has some value.\n\t\t *\n\t\t * @private\n\t\t * @member {String} #_urlInputViewInfoTip\n\t\t */\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tsubmitHandler( {\n\t\t\tview: this\n\t\t} );\n\n\t\tconst childViews = [\n\t\t\tthis.urlInputView,\n\t\t\tthis.saveButtonView,\n\t\t\tthis.cancelButtonView\n\t\t];\n\n\t\tchildViews.forEach( v => {\n\t\t\t// Register the view as focusable.\n\t\t\tthis._focusables.add( v );\n\n\t\t\t// Register the view in the focus tracker.\n\t\t\tthis.focusTracker.add( v.element );\n\t\t} );\n\n\t\t// Start listening for the keystrokes coming from #element.\n\t\tthis.keystrokes.listenTo( this.element );\n\n\t\tconst stopPropagation = data => data.stopPropagation();\n\n\t\t// Since the form is in the dropdown panel which is a child of the toolbar, the toolbar's\n\t\t// keystroke handler would take over the key management in the URL input. We need to prevent\n\t\t// this ASAP. Otherwise, the basic caret movement using the arrow keys will be impossible.\n\t\tthis.keystrokes.set( 'arrowright', stopPropagation );\n\t\tthis.keystrokes.set( 'arrowleft', stopPropagation );\n\t\tthis.keystrokes.set( 'arrowup', stopPropagation );\n\t\tthis.keystrokes.set( 'arrowdown', stopPropagation );\n\n\t\t// Intercept the `selectstart` event, which is blocked by default because of the default behavior\n\t\t// of the DropdownView#panelView.\n\t\t// TODO: blocking `selectstart` in the #panelView should be configurable per–drop–down instance.\n\t\tthis.listenTo( this.urlInputView.element, 'selectstart', ( evt, domEvt ) => {\n\t\t\tdomEvt.stopPropagation();\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * Focuses the fist {@link #_focusables} in the form.\n\t */\n\tfocus() {\n\t\tthis._focusCycler.focusFirst();\n\t}\n\n\t/**\n\t * The native DOM `value` of the {@link #urlInputView} element.\n\t *\n\t * **Note**: Do not confuse it with the {@link module:ui/inputtext/inputtextview~InputTextView#value}\n\t * which works one way only and may not represent the actual state of the component in the DOM.\n\t *\n\t * @type {String}\n\t */\n\tget url() {\n\t\treturn this.urlInputView.fieldView.element.value.trim();\n\t}\n\n\tset url( url ) {\n\t\tthis.urlInputView.fieldView.element.value = url.trim();\n\t}\n\n\t/**\n\t * Validates the form and returns `false` when some fields are invalid.\n\t *\n\t * @returns {Boolean}\n\t */\n\tisValid() {\n\t\tthis.resetFormStatus();\n\n\t\tfor ( const validator of this._validators ) {\n\t\t\tconst errorText = validator( this );\n\n\t\t\t// One error per field is enough.\n\t\t\tif ( errorText ) {\n\t\t\t\t// Apply updated error.\n\t\t\t\tthis.urlInputView.errorText = errorText;\n\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Cleans up the supplementary error and information text of the {@link #urlInputView}\n\t * bringing them back to the state when the form has been displayed for the first time.\n\t *\n\t * See {@link #isValid}.\n\t */\n\tresetFormStatus() {\n\t\tthis.urlInputView.errorText = null;\n\t\tthis.urlInputView.infoText = this._urlInputViewInfoDefault;\n\t}\n\n\t/**\n\t * Creates a labeled input view.\n\t *\n\t * @private\n\t * @returns {module:ui/labeledfield/labeledfieldview~LabeledFieldView} Labeled input view instance.\n\t */\n\t_createUrlInput() {\n\t\tconst t = this.locale.t;\n\n\t\tconst labeledInput = new LabeledFieldView( this.locale, createLabeledInputText );\n\t\tconst inputField = labeledInput.fieldView;\n\n\t\tthis._urlInputViewInfoDefault = t( 'Paste the media URL in the input.' );\n\t\tthis._urlInputViewInfoTip = t( 'Tip: Paste the URL into the content to embed faster.' );\n\n\t\tlabeledInput.label = t( 'Media URL' );\n\t\tlabeledInput.infoText = this._urlInputViewInfoDefault;\n\n\t\tinputField.on( 'input', () => {\n\t\t\t// Display the tip text only when there is some value. Otherwise fall back to the default info text.\n\t\t\tlabeledInput.infoText = inputField.element.value ? this._urlInputViewInfoTip : this._urlInputViewInfoDefault;\n\t\t\tthis.mediaURLInputValue = inputField.element.value.trim();\n\t\t} );\n\n\t\treturn labeledInput;\n\t}\n\n\t/**\n\t * Creates a button view.\n\t *\n\t * @private\n\t * @param {String} label The button label.\n\t * @param {String} icon The button icon.\n\t * @param {String} className The additional button CSS class name.\n\t * @param {String} [eventName] An event name that the `ButtonView#execute` event will be delegated to.\n\t * @returns {module:ui/button/buttonview~ButtonView} The button view instance.\n\t */\n\t_createButton( label, icon, className, eventName ) {\n\t\tconst button = new ButtonView( this.locale );\n\n\t\tbutton.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true\n\t\t} );\n\n\t\tbutton.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: className\n\t\t\t}\n\t\t} );\n\n\t\tif ( eventName ) {\n\t\t\tbutton.delegate( 'execute' ).to( this, eventName );\n\t\t}\n\n\t\treturn button;\n\t}\n}\n\n/**\n * Fired when the form view is submitted (when one of the children triggered the submit event),\n * e.g. click on {@link #saveButtonView}.\n *\n * @event submit\n */\n\n/**\n * Fired when the form view is canceled, e.g. by a click on {@link #cancelButtonView}.\n *\n * @event cancel\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module media-embed/mediaembedui\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport { createDropdown } from '@ckeditor/ckeditor5-ui/src/dropdown/utils';\nimport MediaFormView from './ui/mediaformview';\nimport MediaEmbedEditing from './mediaembedediting';\nimport mediaIcon from '../theme/icons/media.svg';\n\n/**\n * The media embed UI plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class MediaEmbedUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ MediaEmbedEditing ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'MediaEmbedUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst command = editor.commands.get( 'mediaEmbed' );\n\t\tconst registry = editor.plugins.get( MediaEmbedEditing ).registry;\n\n\t\teditor.ui.componentFactory.add( 'mediaEmbed', locale => {\n\t\t\tconst dropdown = createDropdown( locale );\n\n\t\t\tconst mediaForm = new MediaFormView( getFormValidators( editor.t, registry ), editor.locale );\n\n\t\t\tthis._setUpDropdown( dropdown, mediaForm, command, editor );\n\t\t\tthis._setUpForm( dropdown, mediaForm, command );\n\n\t\t\treturn dropdown;\n\t\t} );\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:ui/dropdown/dropdownview~DropdownView} dropdown\n\t * @param {module:ui/view~View} form\n\t * @param {module:media-embed/mediaembedcommand~MediaEmbedCommand} command\n\t */\n\t_setUpDropdown( dropdown, form, command ) {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\t\tconst button = dropdown.buttonView;\n\n\t\tdropdown.bind( 'isEnabled' ).to( command );\n\t\tdropdown.panelView.children.add( form );\n\n\t\tbutton.set( {\n\t\t\tlabel: t( 'Insert media' ),\n\t\t\ticon: mediaIcon,\n\t\t\ttooltip: true\n\t\t} );\n\n\t\t// Note: Use the low priority to make sure the following listener starts working after the\n\t\t// default action of the drop-down is executed (i.e. the panel showed up). Otherwise, the\n\t\t// invisible form/input cannot be focused/selected.\n\t\tbutton.on( 'open', () => {\n\t\t\tform.disableCssTransitions();\n\n\t\t\t// Make sure that each time the panel shows up, the URL field remains in sync with the value of\n\t\t\t// the command. If the user typed in the input, then canceled (`urlInputView#fieldView#value` stays\n\t\t\t// unaltered) and re-opened it without changing the value of the media command (e.g. because they\n\t\t\t// didn't change the selection), they would see the old value instead of the actual value of the\n\t\t\t// command.\n\t\t\tform.url = command.value || '';\n\t\t\tform.urlInputView.fieldView.select();\n\t\t\tform.focus();\n\t\t\tform.enableCssTransitions();\n\t\t}, { priority: 'low' } );\n\n\t\tdropdown.on( 'submit', () => {\n\t\t\tif ( form.isValid() ) {\n\t\t\t\teditor.execute( 'mediaEmbed', form.url );\n\t\t\t\tcloseUI();\n\t\t\t}\n\t\t} );\n\n\t\tdropdown.on( 'change:isOpen', () => form.resetFormStatus() );\n\t\tdropdown.on( 'cancel', () => closeUI() );\n\n\t\tfunction closeUI() {\n\t\t\teditor.editing.view.focus();\n\t\t\tdropdown.isOpen = false;\n\t\t}\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:ui/dropdown/dropdownview~DropdownView} dropdown\n\t * @param {module:ui/view~View} form\n\t * @param {module:media-embed/mediaembedcommand~MediaEmbedCommand} command\n\t */\n\t_setUpForm( dropdown, form, command ) {\n\t\tform.delegate( 'submit', 'cancel' ).to( dropdown );\n\t\tform.urlInputView.bind( 'value' ).to( command, 'value' );\n\n\t\t// Form elements should be read-only when corresponding commands are disabled.\n\t\tform.urlInputView.bind( 'isReadOnly' ).to( command, 'isEnabled', value => !value );\n\t}\n}\n\nfunction getFormValidators( t, registry ) {\n\treturn [\n\t\tform => {\n\t\t\tif ( !form.url.length ) {\n\t\t\t\treturn t( 'The URL must not be empty.' );\n\t\t\t}\n\t\t},\n\t\tform => {\n\t\t\tif ( !registry.hasMedia( form.url ) ) {\n\t\t\t\treturn t( 'This media URL is not supported.' );\n\t\t\t}\n\t\t}\n\t];\n}\n","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" viewBox=\\\"0 0 20 20\\\"><path d=\\\"M18.68 3.03c.6 0 .59-.03.59.55v12.84c0 .59.01.56-.59.56H1.29c-.6 0-.59.03-.59-.56V3.58c0-.58-.01-.55.6-.55h17.38zM15.77 15V5H4.2v10h11.57zM2 4v1h1V4H2zm0 2v1h1V6H2zm0 2v1h1V8H2zm0 2v1h1v-1H2zm0 2v1h1v-1H2zm0 2v1h1v-1H2zM17 4v1h1V4h-1zm0 2v1h1V6h-1zm0 2v1h1V8h-1zm0 2v1h1v-1h-1zm0 2v1h1v-1h-1zm0 2v1h1v-1h-1zM7.5 7.177a.4.4 0 0 1 .593-.351l5.133 2.824a.4.4 0 0 1 0 .7l-5.133 2.824a.4.4 0 0 1-.593-.35V7.176v.001z\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/filters/list\n */\n\nimport Matcher from '@ckeditor/ckeditor5-engine/src/view/matcher';\nimport UpcastWriter from '@ckeditor/ckeditor5-engine/src/view/upcastwriter';\n\n/**\n * Transforms Word specific list-like elements to the semantic HTML lists.\n *\n * Lists in Word are represented by block elements with special attributes like:\n *\n *\t\t<p class=MsoListParagraphCxSpFirst style='mso-list:l1 level1 lfo1'>...</p> // Paragraph based list.\n *\t\t<h1 style='mso-list:l0 level1 lfo1'>...</h1> // Heading 1 based list.\n *\n * @param {module:engine/view/documentfragment~DocumentFragment} documentFragment The view structure to be transformed.\n * @param {String} stylesString Styles from which list-like elements styling will be extracted.\n */\nexport function transformListItemLikeElementsIntoLists( documentFragment, stylesString ) {\n\tif ( !documentFragment.childCount ) {\n\t\treturn;\n\t}\n\n\tconst writer = new UpcastWriter( documentFragment.document );\n\tconst itemLikeElements = findAllItemLikeElements( documentFragment, writer );\n\n\tif ( !itemLikeElements.length ) {\n\t\treturn;\n\t}\n\n\tlet currentList = null;\n\tlet currentIndentation = 1;\n\n\titemLikeElements.forEach( ( itemLikeElement, i ) => {\n\t\tconst isDifferentList = isNewListNeeded( itemLikeElements[ i - 1 ], itemLikeElement );\n\t\tconst previousItemLikeElement = isDifferentList ? null : itemLikeElements[ i - 1 ];\n\t\tconst indentationDifference = getIndentationDifference( previousItemLikeElement, itemLikeElement );\n\n\t\tif ( isDifferentList ) {\n\t\t\tcurrentList = null;\n\t\t\tcurrentIndentation = 1;\n\t\t}\n\n\t\tif ( !currentList || indentationDifference !== 0 ) {\n\t\t\tconst listStyle = detectListStyle( itemLikeElement, stylesString );\n\n\t\t\tif ( !currentList ) {\n\t\t\t\tcurrentList = insertNewEmptyList( listStyle, itemLikeElement.element, writer );\n\t\t\t} else if ( itemLikeElement.indent > currentIndentation ) {\n\t\t\t\tconst lastListItem = currentList.getChild( currentList.childCount - 1 );\n\t\t\t\tconst lastListItemChild = lastListItem.getChild( lastListItem.childCount - 1 );\n\n\t\t\t\tcurrentList = insertNewEmptyList( listStyle, lastListItemChild, writer );\n\t\t\t\tcurrentIndentation += 1;\n\t\t\t} else if ( itemLikeElement.indent < currentIndentation ) {\n\t\t\t\tconst differentIndentation = currentIndentation - itemLikeElement.indent;\n\n\t\t\t\tcurrentList = findParentListAtLevel( currentList, differentIndentation );\n\t\t\t\tcurrentIndentation = parseInt( itemLikeElement.indent );\n\t\t\t}\n\n\t\t\tif ( itemLikeElement.indent <= currentIndentation ) {\n\t\t\t\tif ( !currentList.is( 'element', listStyle.type ) ) {\n\t\t\t\t\tcurrentList = writer.rename( listStyle.type, currentList );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst listItem = transformElementIntoListItem( itemLikeElement.element, writer );\n\n\t\twriter.appendChild( listItem, currentList );\n\t} );\n}\n\n/**\n * Removes paragraph wrapping content inside a list item.\n *\n * @param {module:engine/view/documentfragment~DocumentFragment} documentFragment\n * @param {module:engine/view/upcastwriter~UpcastWriter} writer\n */\nexport function unwrapParagraphInListItem( documentFragment, writer ) {\n\tfor ( const value of writer.createRangeIn( documentFragment ) ) {\n\t\tconst element = value.item;\n\n\t\tif ( element.is( 'element', 'li' ) ) {\n\t\t\t// Google Docs allows on single paragraph inside LI.\n\t\t\tconst firstChild = element.getChild( 0 );\n\n\t\t\tif ( firstChild && firstChild.is( 'element', 'p' ) ) {\n\t\t\t\twriter.unwrapElement( firstChild );\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Finds all list-like elements in a given document fragment.\n//\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment\n// in which to look for list-like nodes.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\n// @returns {Array.<Object>} Array of found list-like items. Each item is an object containing:\n//\n//\t\t* {module:engine/src/view/element~Element} element List-like element.\n//\t\t* {Number} id List item id parsed from `mso-list` style (see `getListItemData()` function).\n//\t\t* {Number} order List item creation order parsed from `mso-list` style (see `getListItemData()` function).\n//\t\t* {Number} indent List item indentation level parsed from `mso-list` style (see `getListItemData()` function).\nfunction findAllItemLikeElements( documentFragment, writer ) {\n\tconst range = writer.createRangeIn( documentFragment );\n\n\t// Matcher for finding list-like elements.\n\tconst itemLikeElementsMatcher = new Matcher( {\n\t\tname: /^p|h\\d+$/,\n\t\tstyles: {\n\t\t\t'mso-list': /.*/\n\t\t}\n\t} );\n\n\tconst itemLikeElements = [];\n\n\tfor ( const value of range ) {\n\t\tif ( value.type === 'elementStart' && itemLikeElementsMatcher.match( value.item ) ) {\n\t\t\tconst itemData = getListItemData( value.item );\n\n\t\t\titemLikeElements.push( {\n\t\t\t\telement: value.item,\n\t\t\t\tid: itemData.id,\n\t\t\t\torder: itemData.order,\n\t\t\t\tindent: itemData.indent\n\t\t\t} );\n\t\t}\n\t}\n\n\treturn itemLikeElements;\n}\n\n// Extracts list item style from the provided CSS.\n//\n// List item style is extracted from CSS stylesheet. Each list with its specific style attribute\n// value (`mso-list:l1 level1 lfo1`) has its dedicated properties in a CSS stylesheet defined with a selector like:\n//\n// \t\t@list l1:level1 { ... }\n//\n// It contains `mso-level-number-format` property which defines list numbering/bullet style. If this property\n// is not defined it means default `decimal` numbering.\n//\n// Here CSS string representation is used as `mso-level-number-format` property is an invalid CSS property\n// and will be removed during CSS parsing.\n//\n// @param {Object} listLikeItem List-like item for which list style will be searched for. Usually\n// a result of `findAllItemLikeElements()` function.\n// @param {String} stylesString CSS stylesheet.\n// @returns {Object} result\n// @returns {String} result.type List type, could be `ul` or `ol`.\n// @returns {String|null} result.style List style, for example: `decimal`, `lower-roman`, etc. It is extracted\n// directly from Word stylesheet and adjusted to represent proper values for the CSS `list-style-type` property.\n// If it cannot be adjusted, the `null` value is returned.\nfunction detectListStyle( listLikeItem, stylesString ) {\n\tconst listStyleRegexp = new RegExp( `@list l${ listLikeItem.id }:level${ listLikeItem.indent }\\\\s*({[^}]*)`, 'gi' );\n\tconst listStyleTypeRegex = /mso-level-number-format:([^;]*);/gi;\n\n\tconst listStyleMatch = listStyleRegexp.exec( stylesString );\n\n\tlet listStyleType = 'decimal'; // Decimal is default one.\n\tlet type = 'ol'; // <ol> is default list.\n\n\tif ( listStyleMatch && listStyleMatch[ 1 ] ) {\n\t\tconst listStyleTypeMatch = listStyleTypeRegex.exec( listStyleMatch[ 1 ] );\n\n\t\tif ( listStyleTypeMatch && listStyleTypeMatch[ 1 ] ) {\n\t\t\tlistStyleType = listStyleTypeMatch[ 1 ].trim();\n\t\t\ttype = listStyleType !== 'bullet' && listStyleType !== 'image' ? 'ol' : 'ul';\n\t\t}\n\n\t\t// Styles for the numbered lists are always defined in Word CSS stylesheet.\n\t\t// Unordered lists MAY contain a value for the Word CSS definition `mso-level-text` but sometimes\n\t\t// the tag is missing. And because of that, we cannot depend on that. We need to predict the list style value based on\n\t\t// the list style marker element.\n\t\tif ( listStyleType === 'bullet' ) {\n\t\t\tconst bulletedStyle = findBulletedListStyle( listLikeItem.element );\n\n\t\t\tif ( bulletedStyle ) {\n\t\t\t\tlistStyleType = bulletedStyle;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\ttype,\n\t\tstyle: mapListStyleDefinition( listStyleType )\n\t};\n}\n\n// Tries extract the `list-style-type` value based on the marker element for bulleted list.\n//\n// @param {module:engine/view/element~Element} element\n// @returns {module:engine/view/element~Element|null}\nfunction findBulletedListStyle( element ) {\n\tconst listMarkerElement = findListMarkerNode( element );\n\n\tif ( !listMarkerElement ) {\n\t\treturn null;\n\t}\n\n\tconst listMarker = listMarkerElement._data;\n\n\tif ( listMarker === 'o' ) {\n\t\treturn 'circle';\n\t} else if ( listMarker === '·' ) {\n\t\treturn 'disc';\n\t}\n\t// Word returns '§' instead of '■' for the square list style.\n\telse if ( listMarker === '§' ) {\n\t\treturn 'square';\n\t}\n\n\treturn null;\n}\n\n// Tries to find a text node that represents the marker element (list-style-type).\n//\n// @param {module:engine/view/element~Element} element\n// @returns {module:engine/view/text~Text|null}\nfunction findListMarkerNode( element ) {\n\t// If the first child is a text node, it is a value for the element.\n\tif ( element.getChild( 0 ).is( '$text' ) ) {\n\t\treturn null;\n\t}\n\n\tconst textNodeOrElement = element.getChild( 0 ).getChild( 0 );\n\n\tif ( textNodeOrElement.is( '$text' ) ) {\n\t\treturn textNodeOrElement;\n\t}\n\n\treturn textNodeOrElement.getChild( 0 );\n}\n\n// Parses the `list-style-type` value extracted directly from the Word CSS stylesheet and returns proper CSS definition.\n//\n// @param {String|null} value\n// @returns {String|null}\nfunction mapListStyleDefinition( value ) {\n\tswitch ( value ) {\n\t\tcase 'arabic-leading-zero':\n\t\t\treturn 'decimal-leading-zero';\n\t\tcase 'alpha-upper':\n\t\t\treturn 'upper-alpha';\n\t\tcase 'alpha-lower':\n\t\t\treturn 'lower-alpha';\n\t\tcase 'roman-upper':\n\t\t\treturn 'upper-roman';\n\t\tcase 'roman-lower':\n\t\t\treturn 'lower-roman';\n\t\tcase 'circle':\n\t\tcase 'disc':\n\t\tcase 'square':\n\t\t\treturn value;\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\n// Creates empty list of a given type and inserts it after a specified element.\n//\n// @param {Object} listStyle List style object which determines the type of newly created list.\n// Usually a result of `detectListStyle()` function.\n// @param {module:engine/view/element~Element} element Element after which list is inserted.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\n// @returns {module:engine/view/element~Element} Newly created list element.\n\nfunction insertNewEmptyList( listStyle, element, writer ) {\n\tconst parent = element.parent;\n\tconst list = writer.createElement( listStyle.type );\n\tconst position = parent.getChildIndex( element ) + 1;\n\n\twriter.insertChild( position, list, parent );\n\n\t// We do not support modifying the marker for particular list item.\n\t// Set the value for the `list-style-type` property directly to the list container.\n\tif ( listStyle.style ) {\n\t\twriter.setStyle( 'list-style-type', listStyle.style, list );\n\t}\n\n\treturn list;\n}\n\n// Transforms given element into a semantic list item. As the function operates on a provided\n// {module:engine/src/view/element~Element element} it will modify the view structure to which this element belongs.\n//\n// @param {module:engine/view/element~Element} element Element which will be transformed into list item.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\n// @returns {module:engine/view/element~Element} New element to which the given one was transformed. It is\n// inserted in place of the old element (the reference to the old element is lost due to renaming).\nfunction transformElementIntoListItem( element, writer ) {\n\tremoveBulletElement( element, writer );\n\n\treturn writer.rename( 'li', element );\n}\n\n// Extracts list item information from Word specific list-like element style:\n//\n//\t\t`style=\"mso-list:l1 level1 lfo1\"`\n//\n// where:\n//\n//\t\t* `l1` is a list id (however it does not mean this is a continuous list - see #43),\n//\t\t* `level1` is a list item indentation level,\n//\t\t* `lfo1` is a list insertion order in a document.\n//\n// @param {module:engine/view/element~Element} element Element from which style data is extracted.\n// @returns {Object} result\n// @returns {Number} result.id Parent list id.\n// @returns {Number} result.order List item creation order.\n// @returns {Number} result.indent List item indentation level.\nfunction getListItemData( element ) {\n\tconst data = {};\n\tconst listStyle = element.getStyle( 'mso-list' );\n\n\tif ( listStyle ) {\n\t\tconst idMatch = listStyle.match( /(^|\\s+)l(\\d+)/i );\n\t\tconst orderMatch = listStyle.match( /\\s*lfo(\\d+)/i );\n\t\tconst indentMatch = listStyle.match( /\\s*level(\\d+)/i );\n\n\t\tif ( idMatch && orderMatch && indentMatch ) {\n\t\t\tdata.id = idMatch[ 2 ];\n\t\t\tdata.order = orderMatch[ 1 ];\n\t\t\tdata.indent = indentMatch[ 1 ];\n\t\t}\n\t}\n\n\treturn data;\n}\n\n// Removes span with a numbering/bullet from a given element.\n//\n// @param {module:engine/view/element~Element} element\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\nfunction removeBulletElement( element, writer ) {\n\t// Matcher for finding `span` elements holding lists numbering/bullets.\n\tconst bulletMatcher = new Matcher( {\n\t\tname: 'span',\n\t\tstyles: {\n\t\t\t'mso-list': 'Ignore'\n\t\t}\n\t} );\n\n\tconst range = writer.createRangeIn( element );\n\n\tfor ( const value of range ) {\n\t\tif ( value.type === 'elementStart' && bulletMatcher.match( value.item ) ) {\n\t\t\twriter.remove( value.item );\n\t\t}\n\t}\n}\n\n// Whether previous and current item belongs to the same list. It is determined based on `item.id`\n// (extracted from `mso-list` style, see #getListItemData) and previous sibling of the current item.\n//\n// However, it's quite easy to change the `id` attribute for nested lists in Word. It will break the list feature while pasting.\n// Let's check also the `indent` attribute. If between those two elements, the difference is equal to 1, we can assume that\n// the `currentItem` is a beginning of the nested list because lists in CKEditor 5 always starts with the `indent=0` attribute.\n// See: https://github.com/ckeditor/ckeditor5/issues/7805.\n//\n// @param {Object} previousItem\n// @param {Object} currentItem\n// @returns {Boolean}\nfunction isNewListNeeded( previousItem, currentItem ) {\n\tif ( !previousItem ) {\n\t\treturn true;\n\t}\n\n\tif ( previousItem.id !== currentItem.id ) {\n\t\t// See: https://github.com/ckeditor/ckeditor5/issues/7805.\n\t\t//\n\t\t// * List item 1.\n\t\t//     - Nested list item 1.\n\t\tif ( currentItem.indent - previousItem.indent === 1 ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tconst previousSibling = currentItem.element.previousSibling;\n\n\tif ( !previousSibling ) {\n\t\treturn true;\n\t}\n\n\t// Even with the same id the list does not have to be continuous (#43).\n\treturn !isList( previousSibling );\n}\n\nfunction isList( element ) {\n\treturn element.is( 'element', 'ol' ) || element.is( 'element', 'ul' );\n}\n\n// Calculates the indentation difference between two given list items (based on indent attribute\n// extracted from `mso-list` style, see #getListItemData).\n//\n// @param {Object} previousItem\n// @param {Object} currentItem\n// @returns {Number}\nfunction getIndentationDifference( previousItem, currentItem ) {\n\treturn previousItem ? currentItem.indent - previousItem.indent : currentItem.indent - 1;\n}\n\n// Finds parent list element (ul/ol) of a given list element with indentation level lower by a given value.\n//\n// @param {module:engine/view/element~Element} listElement List element from which to start looking for a parent list.\n// @param {Number} indentationDifference Indentation difference between lists.\n// @returns {module:engine/view/element~Element} Found list element with indentation level lower by a given value.\nfunction findParentListAtLevel( listElement, indentationDifference ) {\n\tconst ancestors = listElement.getAncestors( { parentFirst: true } );\n\n\tlet parentList = null;\n\tlet levelChange = 0;\n\n\tfor ( const ancestor of ancestors ) {\n\t\tif ( ancestor.name === 'ul' || ancestor.name === 'ol' ) {\n\t\t\tlevelChange++;\n\t\t}\n\n\t\tif ( levelChange === indentationDifference ) {\n\t\t\tparentList = ancestor;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn parentList;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/normalizers/googledocsnormalizer\n */\n\nimport removeBoldWrapper from '../filters/removeboldwrapper';\nimport { unwrapParagraphInListItem } from '../filters/list';\nimport UpcastWriter from '@ckeditor/ckeditor5-engine/src/view/upcastwriter';\n\nconst googleDocsMatch = /id=(\"|')docs-internal-guid-[-0-9a-f]+(\"|')/i;\n\n/**\n * Normalizer for the content pasted from Google Docs.\n *\n * @implements module:paste-from-office/normalizer~Normalizer\n */\nexport default class GoogleDocsNormalizer {\n\t/**\n\t * Creates a new `GoogleDocsNormalizer` instance.\n\t *\n\t * @param {module:engine/view/document~Document} document View document.\n\t */\n\tconstructor( document ) {\n\t\t/**\n\t\t * @readonly\n\t\t * @type {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = document;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tisActive( htmlString ) {\n\t\treturn googleDocsMatch.test( htmlString );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute( data ) {\n\t\tconst writer = new UpcastWriter( this.document );\n\n\t\tremoveBoldWrapper( data.content, writer );\n\t\tunwrapParagraphInListItem( data.content, writer );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/filters/removeboldwrapper\n */\n\n/**\n * Removes `<b>` tag wrapper added by Google Docs to a copied content.\n *\n * @param {module:engine/view/documentfragment~DocumentFragment} documentFragment element `data.content` obtained from clipboard\n * @param {module:engine/view/upcastwriter~UpcastWriter} writer\n */\nexport default function removeBoldWrapper( documentFragment, writer ) {\n\tfor ( const child of documentFragment.getChildren() ) {\n\t\tif ( child.is( 'element', 'b' ) && child.getStyle( 'font-weight' ) === 'normal' ) {\n\t\t\tconst childIndex = documentFragment.getChildIndex( child );\n\n\t\t\twriter.remove( child );\n\t\t\twriter.insertChild( childIndex, child.getChildren(), documentFragment );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/filters/space\n */\n\n/**\n * Replaces last space preceding elements closing tag with `&nbsp;`. Such operation prevents spaces from being removed\n * during further DOM/View processing (see especially {@link module:engine/view/domconverter~DomConverter#_processDataFromDomText}).\n * This method also takes into account Word specific `<o:p></o:p>` empty tags.\n * Additionally multiline sequences of spaces and new lines between tags are removed (see #39 and #40).\n *\n * @param {String} htmlString HTML string in which spacing should be normalized.\n * @returns {String} Input HTML with spaces normalized.\n */\nexport function normalizeSpacing( htmlString ) {\n\t// Run normalizeSafariSpaceSpans() two times to cover nested spans.\n\treturn normalizeSafariSpaceSpans( normalizeSafariSpaceSpans( htmlString ) )\n\t\t// Remove all \\r\\n from \"spacerun spans\" so the last replace line doesn't strip all whitespaces.\n\t\t.replace( /(<span\\s+style=['\"]mso-spacerun:yes['\"]>[\\s]*?)[\\r\\n]+(\\s*<\\/span>)/g, '$1$2' )\n\t\t.replace( /<span\\s+style=['\"]mso-spacerun:yes['\"]><\\/span>/g, '' )\n\t\t.replace( / <\\//g, '\\u00A0</' )\n\t\t.replace( / <o:p><\\/o:p>/g, '\\u00A0<o:p></o:p>' )\n\t\t// Remove <o:p> block filler from empty paragraph. Safari uses \\u00A0 instead of &nbsp;.\n\t\t.replace( /<o:p>(&nbsp;|\\u00A0)<\\/o:p>/g, '' )\n\t\t// Remove all whitespaces when they contain any \\r or \\n.\n\t\t.replace( />(\\s*[\\r\\n]\\s*)</g, '><' );\n}\n\n/**\n * Normalizes spacing in special Word `spacerun spans` (`<span style='mso-spacerun:yes'>\\s+</span>`) by replacing\n * all spaces with `&nbsp; ` pairs. This prevents spaces from being removed during further DOM/View processing\n * (see especially {@link module:engine/view/domconverter~DomConverter#_processDataFromDomText}).\n *\n * @param {Document} htmlDocument Native `Document` object in which spacing should be normalized.\n */\nexport function normalizeSpacerunSpans( htmlDocument ) {\n\thtmlDocument.querySelectorAll( 'span[style*=spacerun]' ).forEach( el => {\n\t\tconst innerTextLength = el.innerText.length || 0;\n\n\t\tel.innerHTML = Array( innerTextLength + 1 ).join( '\\u00A0 ' ).substr( 0, innerTextLength );\n\t} );\n}\n\n// Normalizes specific spacing generated by Safari when content pasted from Word (`<span class=\"Apple-converted-space\"> </span>`)\n// by replacing all spaces sequences longer than 1 space with `&nbsp; ` pairs. This prevents spaces from being removed during\n// further DOM/View processing (see especially {@link module:engine/view/domconverter~DomConverter#_processDataFromDomText}).\n//\n// This function is similar to {@link module:clipboard/utils/normalizeclipboarddata normalizeClipboardData util} but uses\n// regular spaces / &nbsp; sequence for replacement.\n//\n// @param {String} htmlString HTML string in which spacing should be normalized\n// @returns {String} Input HTML with spaces normalized.\nfunction normalizeSafariSpaceSpans( htmlString ) {\n\treturn htmlString.replace( /<span(?: class=\"Apple-converted-space\"|)>(\\s+)<\\/span>/g, ( fullMatch, spaces ) => {\n\t\treturn spaces.length === 1 ? ' ' : Array( spaces.length + 1 ).join( '\\u00A0 ' ).substr( 0, spaces.length );\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/filters/parse\n */\n\n/* globals DOMParser */\n\nimport DomConverter from '@ckeditor/ckeditor5-engine/src/view/domconverter';\nimport ViewDocument from '@ckeditor/ckeditor5-engine/src/view/document';\n\nimport { normalizeSpacing, normalizeSpacerunSpans } from './space';\n\n/**\n * Parses provided HTML extracting contents of `<body>` and `<style>` tags.\n *\n * @param {String} htmlString HTML string to be parsed.\n * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor\n * @returns {Object} result\n * @returns {module:engine/view/documentfragment~DocumentFragment} result.body Parsed body\n * content as a traversable structure.\n * @returns {String} result.bodyString Entire body content as a string.\n * @returns {Array.<CSSStyleSheet>} result.styles Array of native `CSSStyleSheet` objects, each representing\n * separate `style` tag from the source HTML.\n * @returns {String} result.stylesString All `style` tags contents combined in the order of occurrence into one string.\n */\nexport function parseHtml( htmlString, stylesProcessor ) {\n\tconst domParser = new DOMParser();\n\n\t// Remove Word specific \"if comments\" so content inside is not omitted by the parser.\n\thtmlString = htmlString.replace( /<!--\\[if gte vml 1]>/g, '' );\n\n\tconst normalizedHtml = normalizeSpacing( cleanContentAfterBody( htmlString ) );\n\n\t// Parse htmlString as native Document object.\n\tconst htmlDocument = domParser.parseFromString( normalizedHtml, 'text/html' );\n\n\tnormalizeSpacerunSpans( htmlDocument );\n\n\t// Get `innerHTML` first as transforming to View modifies the source document.\n\tconst bodyString = htmlDocument.body.innerHTML;\n\n\t// Transform document.body to View.\n\tconst bodyView = documentToView( htmlDocument, stylesProcessor );\n\n\t// Extract stylesheets.\n\tconst stylesObject = extractStyles( htmlDocument );\n\n\treturn {\n\t\tbody: bodyView,\n\t\tbodyString,\n\t\tstyles: stylesObject.styles,\n\t\tstylesString: stylesObject.stylesString\n\t};\n}\n\n// Transforms native `Document` object into {@link module:engine/view/documentfragment~DocumentFragment}.\n//\n// @param {Document} htmlDocument Native `Document` object to be transformed.\n// @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor\n// @returns {module:engine/view/documentfragment~DocumentFragment}\nfunction documentToView( htmlDocument, stylesProcessor ) {\n\tconst viewDocument = new ViewDocument( stylesProcessor );\n\tconst domConverter = new DomConverter( viewDocument, { blockFillerMode: 'nbsp' } );\n\tconst fragment = htmlDocument.createDocumentFragment();\n\tconst nodes = htmlDocument.body.childNodes;\n\n\twhile ( nodes.length > 0 ) {\n\t\tfragment.appendChild( nodes[ 0 ] );\n\t}\n\n\treturn domConverter.domToView( fragment );\n}\n\n// Extracts both `CSSStyleSheet` and string representation from all `style` elements available in a provided `htmlDocument`.\n//\n// @param {Document} htmlDocument Native `Document` object from which styles will be extracted.\n// @returns {Object} result\n// @returns {Array.<CSSStyleSheet>} result.styles Array of native `CSSStyleSheet` object, each representing\n// separate `style` tag from the source object.\n// @returns {String} result.stylesString All `style` tags contents combined in the order of occurrence as one string.\nfunction extractStyles( htmlDocument ) {\n\tconst styles = [];\n\tconst stylesString = [];\n\tconst styleTags = Array.from( htmlDocument.getElementsByTagName( 'style' ) );\n\n\tfor ( const style of styleTags ) {\n\t\tif ( style.sheet && style.sheet.cssRules && style.sheet.cssRules.length ) {\n\t\t\tstyles.push( style.sheet );\n\t\t\tstylesString.push( style.innerHTML );\n\t\t}\n\t}\n\n\treturn {\n\t\tstyles,\n\t\tstylesString: stylesString.join( ' ' )\n\t};\n}\n\n// Removes leftover content from between closing </body> and closing </html> tag:\n//\n// \t\t<html><body><p>Foo Bar</p></body><span>Fo</span></html> -> <html><body><p>Foo Bar</p></body></html>\n//\n// This function is used as specific browsers (Edge) add some random content after `body` tag when pasting from Word.\n// @param {String} htmlString The HTML string to be cleaned.\n// @returns {String} The HTML string with leftover content removed.\nfunction cleanContentAfterBody( htmlString ) {\n\tconst regexp = /<\\/body>(.*?)(<\\/html>|$)/;\n\tconst match = htmlString.match( regexp );\n\n\tif ( match && match[ 1 ] ) {\n\t\thtmlString = htmlString.slice( 0, match.index ) + htmlString.slice( match.index ).replace( match[ 1 ], '' );\n\t}\n\n\treturn htmlString;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/filters/image\n */\n\n/* globals btoa */\n\nimport ViewMatcher from '@ckeditor/ckeditor5-engine/src/view/matcher';\nimport UpcastWriter from '@ckeditor/ckeditor5-engine/src/view/upcastwriter';\n\n/**\n * Replaces source attribute of all `<img>` elements representing regular\n * images (not the Word shapes) with inlined base64 image representation extracted from RTF or Blob data.\n *\n * @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment on which transform images.\n * @param {String} rtfData The RTF data from which images representation will be used.\n */\nexport function replaceImagesSourceWithBase64( documentFragment, rtfData ) {\n\tif ( !documentFragment.childCount ) {\n\t\treturn;\n\t}\n\n\tconst upcastWriter = new UpcastWriter();\n\tconst shapesIds = findAllShapesIds( documentFragment, upcastWriter );\n\n\tremoveAllImgElementsRepresentingShapes( shapesIds, documentFragment, upcastWriter );\n\tremoveAllShapeElements( documentFragment, upcastWriter );\n\n\tconst images = findAllImageElementsWithLocalSource( documentFragment, upcastWriter );\n\n\tif ( images.length ) {\n\t\treplaceImagesFileSourceWithInlineRepresentation( images, extractImageDataFromRtf( rtfData ), upcastWriter );\n\t}\n}\n\n/**\n * Converts given HEX string to base64 representation.\n *\n * @protected\n * @param {String} hexString The HEX string to be converted.\n * @returns {String} Base64 representation of a given HEX string.\n */\nexport function _convertHexToBase64( hexString ) {\n\treturn btoa( hexString.match( /\\w{2}/g ).map( char => {\n\t\treturn String.fromCharCode( parseInt( char, 16 ) );\n\t} ).join( '' ) );\n}\n\n// Finds all shapes (`<v:*>...</v:*>`) ids. Shapes can represent images (canvas)\n// or Word shapes (which does not have RTF or Blob representation).\n//\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment\n// from which to extract shape ids.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\n// @returns {Array.<String>} Array of shape ids.\nfunction findAllShapesIds( documentFragment, writer ) {\n\tconst range = writer.createRangeIn( documentFragment );\n\n\tconst shapeElementsMatcher = new ViewMatcher( {\n\t\tname: /v:(.+)/\n\t} );\n\n\tconst shapesIds = [];\n\n\tfor ( const value of range ) {\n\t\tconst el = value.item;\n\t\tconst prevSiblingName = el.previousSibling && el.previousSibling.name || null;\n\n\t\t// If shape element have 'o:gfxdata' attribute and is not directly before `<v:shapetype>` element it means it represent Word shape.\n\t\tif ( shapeElementsMatcher.match( el ) && el.getAttribute( 'o:gfxdata' ) && prevSiblingName !== 'v:shapetype' ) {\n\t\t\tshapesIds.push( value.item.getAttribute( 'id' ) );\n\t\t}\n\t}\n\n\treturn shapesIds;\n}\n\n// Removes all `<img>` elements which represents Word shapes and not regular images.\n//\n// @param {Array.<String>} shapesIds Shape ids which will be checked against `<img>` elements.\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment from which to remove `<img>` elements.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\nfunction removeAllImgElementsRepresentingShapes( shapesIds, documentFragment, writer ) {\n\tconst range = writer.createRangeIn( documentFragment );\n\n\tconst imageElementsMatcher = new ViewMatcher( {\n\t\tname: 'img'\n\t} );\n\n\tconst imgs = [];\n\n\tfor ( const value of range ) {\n\t\tif ( imageElementsMatcher.match( value.item ) ) {\n\t\t\tconst el = value.item;\n\t\t\tconst shapes = el.getAttribute( 'v:shapes' ) ? el.getAttribute( 'v:shapes' ).split( ' ' ) : [];\n\n\t\t\tif ( shapes.length && shapes.every( shape => shapesIds.indexOf( shape ) > -1 ) ) {\n\t\t\t\timgs.push( el );\n\t\t\t// Shapes may also have empty source while content is paste in some browsers (Safari).\n\t\t\t} else if ( !el.getAttribute( 'src' ) ) {\n\t\t\t\timgs.push( el );\n\t\t\t}\n\t\t}\n\t}\n\n\tfor ( const img of imgs ) {\n\t\twriter.remove( img );\n\t}\n}\n\n// Removes all shape elements (`<v:*>...</v:*>`) so they do not pollute the output structure.\n//\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment from which to remove shape elements.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\nfunction removeAllShapeElements( documentFragment, writer ) {\n\tconst range = writer.createRangeIn( documentFragment );\n\n\tconst shapeElementsMatcher = new ViewMatcher( {\n\t\tname: /v:(.+)/\n\t} );\n\n\tconst shapes = [];\n\n\tfor ( const value of range ) {\n\t\tif ( shapeElementsMatcher.match( value.item ) ) {\n\t\t\tshapes.push( value.item );\n\t\t}\n\t}\n\n\tfor ( const shape of shapes ) {\n\t\twriter.remove( shape );\n\t}\n}\n\n// Finds all `<img>` elements in a given document fragment which have source pointing to local `file://` resource.\n//\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment in which to look for `<img>` elements.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\n// @returns {Object} result All found images grouped by source type.\n// @returns {Array.<module:engine/view/element~Element>} result.file Array of found `<img>` elements with `file://` source.\n// @returns {Array.<module:engine/view/element~Element>} result.blob Array of found `<img>` elements with `blob:` source.\nfunction findAllImageElementsWithLocalSource( documentFragment, writer ) {\n\tconst range = writer.createRangeIn( documentFragment );\n\n\tconst imageElementsMatcher = new ViewMatcher( {\n\t\tname: 'img'\n\t} );\n\n\tconst imgs = [];\n\n\tfor ( const value of range ) {\n\t\tif ( imageElementsMatcher.match( value.item ) ) {\n\t\t\tif ( value.item.getAttribute( 'src' ).startsWith( 'file://' ) ) {\n\t\t\t\timgs.push( value.item );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn imgs;\n}\n\n// Extracts all images HEX representations from a given RTF data.\n//\n// @param {String} rtfData The RTF data from which to extract images HEX representation.\n// @returns {Array.<Object>} Array of found HEX representations. Each array item is an object containing:\n//\n// \t\t* {String} hex Image representation in HEX format.\n// \t\t* {string} type Type of image, `image/png` or `image/jpeg`.\nfunction extractImageDataFromRtf( rtfData ) {\n\tif ( !rtfData ) {\n\t\treturn [];\n\t}\n\n\tconst regexPictureHeader = /{\\\\pict[\\s\\S]+?\\\\bliptag-?\\d+(\\\\blipupi-?\\d+)?({\\\\\\*\\\\blipuid\\s?[\\da-fA-F]+)?[\\s}]*?/;\n\tconst regexPicture = new RegExp( '(?:(' + regexPictureHeader.source + '))([\\\\da-fA-F\\\\s]+)\\\\}', 'g' );\n\tconst images = rtfData.match( regexPicture );\n\tconst result = [];\n\n\tif ( images ) {\n\t\tfor ( const image of images ) {\n\t\t\tlet imageType = false;\n\n\t\t\tif ( image.includes( '\\\\pngblip' ) ) {\n\t\t\t\timageType = 'image/png';\n\t\t\t} else if ( image.includes( '\\\\jpegblip' ) ) {\n\t\t\t\timageType = 'image/jpeg';\n\t\t\t}\n\n\t\t\tif ( imageType ) {\n\t\t\t\tresult.push( {\n\t\t\t\t\thex: image.replace( regexPictureHeader, '' ).replace( /[^\\da-fA-F]/g, '' ),\n\t\t\t\t\ttype: imageType\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result;\n}\n\n// Replaces `src` attribute value of all given images with the corresponding base64 image representation.\n//\n// @param {Array.<module:engine/view/element~Element>} imageElements Array of image elements which will have its source replaced.\n// @param {Array.<Object>} imagesHexSources Array of images hex sources (usually the result of `extractImageDataFromRtf()` function).\n// The array should be the same length as `imageElements` parameter.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\nfunction replaceImagesFileSourceWithInlineRepresentation( imageElements, imagesHexSources, writer ) {\n\t// Assume there is an equal amount of image elements and images HEX sources so they can be matched accordingly based on existing order.\n\tif ( imageElements.length === imagesHexSources.length ) {\n\t\tfor ( let i = 0; i < imageElements.length; i++ ) {\n\t\t\tconst newSrc = `data:${ imagesHexSources[ i ].type };base64,${ _convertHexToBase64( imagesHexSources[ i ].hex ) }`;\n\t\t\twriter.setAttribute( 'src', newSrc, imageElements[ i ] );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/normalizers/mswordnormalizer\n */\n\nimport { parseHtml } from '../filters/parse';\nimport { transformListItemLikeElementsIntoLists } from '../filters/list';\nimport { replaceImagesSourceWithBase64 } from '../filters/image';\n\nconst msWordMatch1 = /<meta\\s*name=\"?generator\"?\\s*content=\"?microsoft\\s*word\\s*\\d+\"?\\/?>/i;\nconst msWordMatch2 = /xmlns:o=\"urn:schemas-microsoft-com/i;\n\n/**\n * Normalizer for the content pasted from Microsoft Word.\n *\n * @implements module:paste-from-office/normalizer~Normalizer\n */\nexport default class MSWordNormalizer {\n\t/**\n\t * Creates a new `MSWordNormalizer` instance.\n\t *\n\t * @param {module:engine/view/document~Document} document View document.\n\t */\n\tconstructor( document ) {\n\t\t/**\n\t\t * @readonly\n\t\t * @type {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = document;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tisActive( htmlString ) {\n\t\treturn msWordMatch1.test( htmlString ) || msWordMatch2.test( htmlString );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute( data ) {\n\t\tconst { body, stylesString } = parseHtml( data.dataTransfer.getData( 'text/html' ), this.document.stylesProcessor );\n\n\t\ttransformListItemLikeElementsIntoLists( body, stylesString );\n\t\treplaceImagesSourceWithBase64( body, data.dataTransfer.getData( 'text/rtf' ) );\n\n\t\tdata.content = body;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/utils/common\n */\n\n/**\n * A common method to update the numeric value. If a value is the default one, it will be unset.\n *\n * @param {String} key An attribute key.\n * @param {*} value The new attribute value.\n * @param {module:engine/model/item~Item} item A model item on which the attribute will be set.\n * @param {module:engine/model/writer~Writer} writer\n * @param {*} defaultValue The default attribute value. If a value is lower or equal, it will be unset.\n */\nexport function updateNumericAttribute( key, value, item, writer, defaultValue = 1 ) {\n\tif ( value > defaultValue ) {\n\t\twriter.setAttribute( key, value, item );\n\t} else {\n\t\twriter.removeAttribute( key, item );\n\t}\n}\n\n/**\n * A common method to create an empty table cell. It creates a proper model structure as a table cell must have at least one block inside.\n *\n * @param {module:engine/model/writer~Writer} writer The model writer.\n * @param {module:engine/model/position~Position} insertPosition The position at which the table cell should be inserted.\n * @param {Object} attributes The element attributes.\n * @returns {module:engine/model/element~Element} Created table cell.\n */\nexport function createEmptyTableCell( writer, insertPosition, attributes = {} ) {\n\tconst tableCell = writer.createElement( 'tableCell', attributes );\n\n\twriter.insertElement( 'paragraph', tableCell );\n\twriter.insert( tableCell, insertPosition );\n\n\treturn tableCell;\n}\n\n/**\n * Checks if a table cell belongs to the heading column section.\n *\n * @param {module:table/tableutils~TableUtils} tableUtils\n * @param {module:engine/model/element~Element} tableCell\n * @returns {Boolean}\n */\nexport function isHeadingColumnCell( tableUtils, tableCell ) {\n\tconst table = tableCell.parent.parent;\n\tconst headingColumns = parseInt( table.getAttribute( 'headingColumns' ) || 0 );\n\tconst { column } = tableUtils.getCellLocation( tableCell );\n\n\treturn !!headingColumns && column < headingColumns;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/converters/upcasttable\n */\n\nimport { createEmptyTableCell } from '../utils/common';\n\n/**\n * View the table element to model the table element conversion helper.\n *\n * This conversion helper converts the table element as well as table rows.\n *\n * @returns {Function} Conversion helper.\n */\nexport default function upcastTable() {\n\treturn dispatcher => {\n\t\tdispatcher.on( 'element:table', ( evt, data, conversionApi ) => {\n\t\t\tconst viewTable = data.viewItem;\n\n\t\t\t// When element was already consumed then skip it.\n\t\t\tif ( !conversionApi.consumable.test( viewTable, { name: true } ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst { rows, headingRows, headingColumns } = scanTable( viewTable );\n\n\t\t\t// Only set attributes if values is greater then 0.\n\t\t\tconst attributes = {};\n\n\t\t\tif ( headingColumns ) {\n\t\t\t\tattributes.headingColumns = headingColumns;\n\t\t\t}\n\n\t\t\tif ( headingRows ) {\n\t\t\t\tattributes.headingRows = headingRows;\n\t\t\t}\n\n\t\t\tconst table = conversionApi.writer.createElement( 'table', attributes );\n\n\t\t\tif ( !conversionApi.safeInsert( table, data.modelCursor ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconversionApi.consumable.consume( viewTable, { name: true } );\n\n\t\t\t// Upcast table rows in proper order (heading rows first).\n\t\t\trows.forEach( row => conversionApi.convertItem( row, conversionApi.writer.createPositionAt( table, 'end' ) ) );\n\n\t\t\t// Create one row and one table cell for empty table.\n\t\t\tif ( table.isEmpty ) {\n\t\t\t\tconst row = conversionApi.writer.createElement( 'tableRow' );\n\t\t\t\tconversionApi.writer.insert( row, conversionApi.writer.createPositionAt( table, 'end' ) );\n\n\t\t\t\tcreateEmptyTableCell( conversionApi.writer, conversionApi.writer.createPositionAt( row, 'end' ) );\n\t\t\t}\n\n\t\t\tconversionApi.updateConversionResult( table, data );\n\t\t} );\n\t};\n}\n\n/**\n * A conversion helper that skips empty <tr> from upcasting at the beginning of the table.\n *\n * AN empty row is considered a table model error but when handling clipboard data there could be rows that contain only row-spanned cells\n * and empty TR-s are used to maintain table structure (also {@link module:table/tablewalker~TableWalker} assumes that there are only rows\n * that have related `tableRow` elements).\n *\n * *Note:* Only the first empty rows are removed because those have no meaning and it solves the issue\n * of an improper table with all empty rows.\n *\n * @returns {Function} Conversion helper.\n */\nexport function skipEmptyTableRow() {\n\treturn dispatcher => {\n\t\tdispatcher.on( 'element:tr', ( evt, data ) => {\n\t\t\tif ( data.viewItem.isEmpty && data.modelCursor.index == 0 ) {\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t};\n}\n\n// Scans table rows and extracts required metadata from the table:\n//\n// headingRows    - The number of rows that go as table headers.\n// headingColumns - The maximum number of row headings.\n// rows           - Sorted `<tr>` elements as they should go into the model - ie. if `<thead>` is inserted after `<tbody>` in the view.\n//\n// @param {module:engine/view/element~Element} viewTable\n// @returns {{headingRows, headingColumns, rows}}\nfunction scanTable( viewTable ) {\n\tconst tableMeta = {\n\t\theadingRows: 0,\n\t\theadingColumns: 0\n\t};\n\n\t// The `<tbody>` and `<thead>` sections in the DOM do not have to be in order `<thead>` -> `<tbody>` and there might be more than one\n\t// of them.\n\t// As the model does not have these sections, rows from different sections must be sorted.\n\t// For example, below is a valid HTML table:\n\t//\n\t//\t\t<table>\n\t//\t\t\t<tbody><tr><td>2</td></tr></tbody>\n\t//\t\t\t<thead><tr><td>1</td></tr></thead>\n\t//\t\t\t<tbody><tr><td>3</td></tr></tbody>\n\t//\t\t</table>\n\t//\n\t// But browsers will render rows in order as: 1 as the heading and 2 and 3 as the body.\n\tconst headRows = [];\n\tconst bodyRows = [];\n\n\t// Currently the editor does not support more then one <thead> section.\n\t// Only the first <thead> from the view will be used as a heading row and the others will be converted to body rows.\n\tlet firstTheadElement;\n\n\tfor ( const tableChild of Array.from( viewTable.getChildren() ) ) {\n\t\t// Only `<thead>`, `<tbody>` & `<tfoot>` from allowed table children can have `<tr>`s.\n\t\t// The else is for future purposes (mainly `<caption>`).\n\t\tif ( tableChild.name === 'tbody' || tableChild.name === 'thead' || tableChild.name === 'tfoot' ) {\n\t\t\t// Save the first `<thead>` in the table as table header - all other ones will be converted to table body rows.\n\t\t\tif ( tableChild.name === 'thead' && !firstTheadElement ) {\n\t\t\t\tfirstTheadElement = tableChild;\n\t\t\t}\n\n\t\t\t// There might be some extra empty text nodes between the `<tr>`s.\n\t\t\t// Make sure further code operates on `tr`s only. (#145)\n\t\t\tconst trs = Array.from( tableChild.getChildren() ).filter( el => el.is( 'element', 'tr' ) );\n\n\t\t\tfor ( const tr of trs ) {\n\t\t\t\t// This <tr> is a child of a first <thead> element.\n\t\t\t\tif ( tr.parent.name === 'thead' && tr.parent === firstTheadElement ) {\n\t\t\t\t\ttableMeta.headingRows++;\n\t\t\t\t\theadRows.push( tr );\n\t\t\t\t} else {\n\t\t\t\t\tbodyRows.push( tr );\n\t\t\t\t\t// For other rows check how many column headings this row has.\n\n\t\t\t\t\tconst headingCols = scanRowForHeadingColumns( tr, tableMeta, firstTheadElement );\n\n\t\t\t\t\tif ( headingCols > tableMeta.headingColumns ) {\n\t\t\t\t\t\ttableMeta.headingColumns = headingCols;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\ttableMeta.rows = [ ...headRows, ...bodyRows ];\n\n\treturn tableMeta;\n}\n\n// Scans a `<tr>` element and its children for metadata:\n// - For heading row:\n//     - Adds this row to either the heading or the body rows.\n//     - Updates the number of heading rows.\n// - For body rows:\n//     - Calculates the number of column headings.\n//\n// @param {module:engine/view/element~Element} tr\n// @returns {Number}\nfunction scanRowForHeadingColumns( tr ) {\n\tlet headingColumns = 0;\n\tlet index = 0;\n\n\t// Filter out empty text nodes from tr children.\n\tconst children = Array.from( tr.getChildren() )\n\t\t.filter( child => child.name === 'th' || child.name === 'td' );\n\n\t// Count starting adjacent <th> elements of a <tr>.\n\twhile ( index < children.length && children[ index ].name === 'th' ) {\n\t\tconst th = children[ index ];\n\n\t\t// Adjust columns calculation by the number of spanned columns.\n\t\tconst colspan = parseInt( th.getAttribute( 'colspan' ) || 1 );\n\n\t\theadingColumns = headingColumns + colspan;\n\t\tindex++;\n\t}\n\n\treturn headingColumns;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tablewalker\n */\n\n// @if CK_DEBUG // import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * The table iterator class. It allows to iterate over table cells. For each cell the iterator yields\n * {@link module:table/tablewalker~TableSlot} with proper table cell attributes.\n */\nexport default class TableWalker {\n\t/**\n\t * Creates an instance of the table walker.\n\t *\n\t * The table walker iterates internally by traversing the table from row index = 0 and column index = 0.\n\t * It walks row by row and column by column in order to output values defined in the constructor.\n\t * By default it will output only the locations that are occupied by a cell. To include also spanned rows and columns,\n\t * pass the `includeAllSlots` option to the constructor.\n\t *\n\t * The most important values of the iterator are column and row indexes of a cell.\n\t *\n\t * See {@link module:table/tablewalker~TableSlot} what values are returned by the table walker.\n\t *\n\t * To iterate over a given row:\n\t *\n\t *\t\tconst tableWalker = new TableWalker( table, { startRow: 1, endRow: 2 } );\n\t *\n\t *\t\tfor ( const tableSlot of tableWalker ) {\n\t *\t\t\tconsole.log( 'A cell at row', tableSlot.row, 'and column', tableSlot.column );\n\t *\t\t}\n\t *\n\t * For instance the code above for the following table:\n\t *\n\t *\t\t+----+----+----+----+----+----+\n\t *\t\t| 00      | 02 | 03 | 04 | 05 |\n\t *\t\t|         +----+----+----+----+\n\t *\t\t|         | 12      | 14 | 15 |\n\t *\t\t|         +----+----+----+    +\n\t *\t\t|         | 22           |    |\n\t *\t\t|----+----+----+----+----+    +\n\t *\t\t| 30 | 31 | 32 | 33 | 34 |    |\n\t *\t\t+----+----+----+----+----+----+\n\t *\n\t * will log in the console:\n\t *\n\t *\t\t'A cell at row 1 and column 2'\n\t *\t\t'A cell at row 1 and column 4'\n\t *\t\t'A cell at row 1 and column 5'\n\t *\t\t'A cell at row 2 and column 2'\n\t *\n\t * To also iterate over spanned cells:\n\t *\n\t *\t\tconst tableWalker = new TableWalker( table, { row: 1, includeAllSlots: true } );\n\t *\n\t *\t\tfor ( const tableSlot of tableWalker ) {\n\t *\t\t\tconsole.log( 'Slot at', tableSlot.row, 'x', tableSlot.column, ':', tableSlot.isAnchor ? 'is anchored' : 'is spanned' );\n\t *\t\t}\n\t *\n\t * will log in the console for the table from the previous example:\n\t *\n\t *\t\t'Cell at 1 x 0 : is spanned'\n\t *\t\t'Cell at 1 x 1 : is spanned'\n\t *\t\t'Cell at 1 x 2 : is anchored'\n\t *\t\t'Cell at 1 x 3 : is spanned'\n\t *\t\t'Cell at 1 x 4 : is anchored'\n\t *\t\t'Cell at 1 x 5 : is anchored'\n\t *\n\t * **Note**: Option `row` is a shortcut that sets both `startRow` and `endRow` to the same row.\n\t * (Use either `row` or `startRow` and `endRow` but never together). Similarly the `column` option sets both `startColumn`\n\t * and `endColumn` to the same column (Use either `column` or `startColumn` and `endColumn` but never together).\n\t *\n\t * @constructor\n\t * @param {module:engine/model/element~Element} table A table over which the walker iterates.\n\t * @param {Object} [options={}] An object with configuration.\n\t * @param {Number} [options.row] A row index for which this iterator will output cells.\n\t * Can't be used together with `startRow` and `endRow`.\n\t * @param {Number} [options.startRow=0] A row index from which this iterator should start. Can't be used together with `row`.\n\t * @param {Number} [options.endRow] A row index at which this iterator should end. Can't be used together with `row`.\n\t * @param {Number} [options.column] A column index for which this iterator will output cells.\n\t * Can't be used together with `startColumn` and `endColumn`.\n\t * @param {Number} [options.startColumn=0] A column index from which this iterator should start. Can't be used together with `column`.\n\t * @param {Number} [options.endColumn] A column index at which this iterator should end. Can't be used together with `column`.\n\t * @param {Boolean} [options.includeAllSlots=false] Also return values for spanned cells.\n\t */\n\tconstructor( table, options = {} ) {\n\t\t/**\n\t\t * The walker's table element.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/element~Element}\n\t\t * @protected\n\t\t */\n\t\tthis._table = table;\n\n\t\t/**\n\t\t * A row index from which this iterator will start.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._startRow = options.row !== undefined ? options.row : options.startRow || 0;\n\n\t\t/**\n\t\t * A row index at which this iterator will end.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._endRow = options.row !== undefined ? options.row : options.endRow;\n\n\t\t/**\n\t\t * If set, the table walker will only output cells from a given column and following ones or cells that overlap them.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._startColumn = options.column !== undefined ? options.column : options.startColumn || 0;\n\n\t\t/**\n\t\t * If set, the table walker will only output cells up to a given column.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._endColumn = options.column !== undefined ? options.column : options.endColumn;\n\n\t\t/**\n\t\t * Enables output of spanned cells that are normally not yielded.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean}\n\t\t * @private\n\t\t */\n\t\tthis._includeAllSlots = !!options.includeAllSlots;\n\n\t\t/**\n\t\t * Row indexes to skip from the iteration.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Set<Number>}\n\t\t * @private\n\t\t */\n\t\tthis._skipRows = new Set();\n\n\t\t/**\n\t\t * The current row index.\n\t\t *\n\t\t * @member {Number}\n\t\t * @protected\n\t\t */\n\t\tthis._row = 0;\n\n\t\t/**\n\t\t * The current column index.\n\t\t *\n\t\t * @member {Number}\n\t\t * @protected\n\t\t */\n\t\tthis._column = 0;\n\n\t\t/**\n\t\t * The cell index in a parent row. For spanned cells when {@link #_includeAllSlots} is set to `true`,\n\t\t * this represents the index of the next table cell.\n\t\t *\n\t\t * @member {Number}\n\t\t * @protected\n\t\t */\n\t\tthis._cellIndex = 0;\n\n\t\t/**\n\t\t * Holds a map of spanned cells in a table.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Map.<Number, Map.<Number, Object>>}\n\t\t * @private\n\t\t */\n\t\tthis._spannedCells = new Map();\n\n\t\t/**\n\t\t * Index of the next column where a cell is anchored.\n\t\t *\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._nextCellAtColumn = -1;\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * @returns {Iterable.<module:table/tablewalker~TableSlot>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets the next table walker's value.\n\t *\n\t * @returns {module:table/tablewalker~TableSlot} The next table walker's value.\n\t */\n\tnext() {\n\t\tconst row = this._table.getChild( this._row );\n\n\t\t// Iterator is done when there's no row (table ended) or the row is after `endRow` limit.\n\t\tif ( !row || this._isOverEndRow() ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\tif ( this._isOverEndColumn() ) {\n\t\t\treturn this._advanceToNextRow();\n\t\t}\n\n\t\tlet outValue = null;\n\n\t\tconst spanData = this._getSpanned();\n\n\t\tif ( spanData ) {\n\t\t\tif ( this._includeAllSlots && !this._shouldSkipSlot() ) {\n\t\t\t\toutValue = this._formatOutValue( spanData.cell, spanData.row, spanData.column );\n\t\t\t}\n\t\t} else {\n\t\t\tconst cell = row.getChild( this._cellIndex );\n\n\t\t\tif ( !cell ) {\n\t\t\t\t// If there are no more cells left in row advance to the next row.\n\t\t\t\treturn this._advanceToNextRow();\n\t\t\t}\n\n\t\t\tconst colspan = parseInt( cell.getAttribute( 'colspan' ) || 1 );\n\t\t\tconst rowspan = parseInt( cell.getAttribute( 'rowspan' ) || 1 );\n\n\t\t\t// Record this cell spans if it's not 1x1 cell.\n\t\t\tif ( colspan > 1 || rowspan > 1 ) {\n\t\t\t\tthis._recordSpans( cell, rowspan, colspan );\n\t\t\t}\n\n\t\t\tif ( !this._shouldSkipSlot() ) {\n\t\t\t\toutValue = this._formatOutValue( cell );\n\t\t\t}\n\n\t\t\tthis._nextCellAtColumn = this._column + colspan;\n\t\t}\n\n\t\t// Advance to the next column before returning value.\n\t\tthis._column++;\n\n\t\tif ( this._column == this._nextCellAtColumn ) {\n\t\t\tthis._cellIndex++;\n\t\t}\n\n\t\t// The current value will be returned only if current row and column are not skipped.\n\t\treturn outValue || this.next();\n\t}\n\n\t/**\n\t * Marks a row to skip in the next iteration. It will also skip cells from the current row if there are any cells from the current row\n\t * to output.\n\t *\n\t * @param {Number} row The row index to skip.\n\t */\n\tskipRow( row ) {\n\t\tthis._skipRows.add( row );\n\t}\n\n\t/**\n\t * Advances internal cursor to the next row.\n\t *\n\t * @private\n\t * @returns {module:table/tablewalker~TableSlot}\n\t */\n\t_advanceToNextRow() {\n\t\tthis._row++;\n\t\tthis._column = 0;\n\t\tthis._cellIndex = 0;\n\t\tthis._nextCellAtColumn = -1;\n\n\t\treturn this.next();\n\t}\n\n\t/**\n\t * Checks if the current row is over {@link #_endRow}.\n\t *\n\t * @private\n\t * @returns {Boolean}\n\t */\n\t_isOverEndRow() {\n\t\t// If #_endRow is defined skip all rows after it.\n\t\treturn this._endRow !== undefined && this._row > this._endRow;\n\t}\n\n\t/**\n\t * Checks if the current cell is over {@link #_endColumn}\n\t *\n\t * @private\n\t * @returns {Boolean}\n\t */\n\t_isOverEndColumn() {\n\t\t// If #_endColumn is defined skip all cells after it.\n\t\treturn this._endColumn !== undefined && this._column > this._endColumn;\n\t}\n\n\t/**\n\t * A common method for formatting the iterator's output value.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} cell The table cell to output.\n\t * @param {Number} [anchorRow] The row index of a cell anchor slot.\n\t * @param {Number} [anchorColumn] The column index of a cell anchor slot.\n\t * @returns {{done: Boolean, value: {cell: *, row: Number, column: *, rowspan: *, colspan: *, cellIndex: Number}}}\n\t */\n\t_formatOutValue( cell, anchorRow = this._row, anchorColumn = this._column ) {\n\t\treturn {\n\t\t\tdone: false,\n\t\t\tvalue: new TableSlot( this, cell, anchorRow, anchorColumn )\n\t\t};\n\t}\n\n\t/**\n\t * Checks if the current slot should be skipped.\n\t *\n\t * @private\n\t * @returns {Boolean}\n\t */\n\t_shouldSkipSlot() {\n\t\tconst rowIsMarkedAsSkipped = this._skipRows.has( this._row );\n\t\tconst rowIsBeforeStartRow = this._row < this._startRow;\n\n\t\tconst columnIsBeforeStartColumn = this._column < this._startColumn;\n\t\tconst columnIsAfterEndColumn = this._endColumn !== undefined && this._column > this._endColumn;\n\n\t\treturn rowIsMarkedAsSkipped || rowIsBeforeStartRow || columnIsBeforeStartColumn || columnIsAfterEndColumn;\n\t}\n\n\t/**\n\t * Returns the cell element that is spanned over the current cell location.\n\t *\n\t * @private\n\t * @returns {module:engine/model/element~Element}\n\t */\n\t_getSpanned() {\n\t\tconst rowMap = this._spannedCells.get( this._row );\n\n\t\t// No spans for given row.\n\t\tif ( !rowMap ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// If spans for given rows has entry for column it means that this location if spanned by other cell.\n\t\treturn rowMap.get( this._column ) || null;\n\t}\n\n\t/**\n\t * Updates spanned cells map relative to the current cell location and its span dimensions.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} cell A cell that is spanned.\n\t * @param {Number} rowspan Cell height.\n\t * @param {Number} colspan Cell width.\n\t */\n\t_recordSpans( cell, rowspan, colspan ) {\n\t\tconst data = {\n\t\t\tcell,\n\t\t\trow: this._row,\n\t\t\tcolumn: this._column\n\t\t};\n\n\t\tfor ( let rowToUpdate = this._row; rowToUpdate < this._row + rowspan; rowToUpdate++ ) {\n\t\t\tfor ( let columnToUpdate = this._column; columnToUpdate < this._column + colspan; columnToUpdate++ ) {\n\t\t\t\tif ( rowToUpdate != this._row || columnToUpdate != this._column ) {\n\t\t\t\t\tthis._markSpannedCell( rowToUpdate, columnToUpdate, data );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Marks the cell location as spanned by another cell.\n\t *\n\t * @private\n\t * @param {Number} row The row index of the cell location.\n\t * @param {Number} column The column index of the cell location.\n\t * @param {Object} data A spanned cell details (cell element, anchor row and column).\n\t */\n\t_markSpannedCell( row, column, data ) {\n\t\tif ( !this._spannedCells.has( row ) ) {\n\t\t\tthis._spannedCells.set( row, new Map() );\n\t\t}\n\n\t\tconst rowSpans = this._spannedCells.get( row );\n\n\t\trowSpans.set( column, data );\n\t}\n}\n\n/**\n * An object returned by {@link module:table/tablewalker~TableWalker} when traversing table cells.\n */\nclass TableSlot {\n\t/**\n\t * Creates an instance of the table walker value.\n\t *\n\t * @protected\n\t * @param {module:table/tablewalker~TableWalker} tableWalker The table walker instance.\n\t * @param {module:engine/model/element~Element} cell The current table cell.\n\t * @param {Number} anchorRow The row index of a cell anchor slot.\n\t * @param {Number} anchorColumn The column index of a cell anchor slot.\n\t */\n\tconstructor( tableWalker, cell, anchorRow, anchorColumn ) {\n\t\t/**\n\t\t * The current table cell.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/element~Element}\n\t\t */\n\t\tthis.cell = cell;\n\n\t\t/**\n\t\t * The row index of a table slot.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.row = tableWalker._row;\n\n\t\t/**\n\t\t * The column index of a table slot.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.column = tableWalker._column;\n\n\t\t/**\n\t\t * The row index of a cell anchor slot.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.cellAnchorRow = anchorRow;\n\n\t\t/**\n\t\t * The column index of a cell anchor slot.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.cellAnchorColumn = anchorColumn;\n\n\t\t/**\n\t\t * The index of the current cell in the parent row.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._cellIndex = tableWalker._cellIndex;\n\n\t\t/**\n\t\t * The table element.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/element~Element}\n\t\t * @private\n\t\t */\n\t\tthis._table = tableWalker._table;\n\t}\n\n\t/**\n\t * Whether the cell is anchored in the current slot.\n\t *\n\t * @readonly\n\t * @returns {Boolean}\n\t */\n\tget isAnchor() {\n\t\treturn this.row === this.cellAnchorRow && this.column === this.cellAnchorColumn;\n\t}\n\n\t/**\n\t * The width of a cell defined by a `colspan` attribute. If the model attribute is not present, it is set to `1`.\n\t *\n\t * @readonly\n\t * @returns {Number}\n\t */\n\tget cellWidth() {\n\t\treturn parseInt( this.cell.getAttribute( 'colspan' ) || 1 );\n\t}\n\n\t/**\n\t * The height of a cell defined by a `rowspan` attribute. If the model attribute is not present, it is set to `1`.\n\t *\n\t * @readonly\n\t * @returns {Number}\n\t */\n\tget cellHeight() {\n\t\treturn parseInt( this.cell.getAttribute( 'rowspan' ) || 1 );\n\t}\n\n\t/**\n\t * Returns the {@link module:engine/model/position~Position} before the table slot.\n\t *\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tgetPositionBefore() {\n\t\tconst model = this._table.root.document.model;\n\n\t\treturn model.createPositionAt( this._table.getChild( this.row ), this._cellIndex );\n\t}\n\n\t// @if CK_DEBUG // get isSpanned() { throwMissingGetterError( 'isSpanned' ); }\n\t// @if CK_DEBUG // get colspan() { throwMissingGetterError( 'colspan' ); }\n\t// @if CK_DEBUG // get rowspan() { throwMissingGetterError( 'rowspan' ); }\n\t// @if CK_DEBUG // get cellIndex() { throwMissingGetterError( 'cellIndex' ); }\n}\n\n/**\n * This `TableSlot`'s getter (property) was removed in CKEditor 5 v20.0.0.\n *\n * Check out the new `TableWalker`'s API in the documentation.\n *\n * @error tableslot-getter-removed\n * @param {String} getterName\n */\n\n// @if CK_DEBUG // function throwMissingGetterError( getterName ) {\n// @if CK_DEBUG //\t\tthrow new CKEditorError( 'tableslot-getter-removed', this, {\n// @if CK_DEBUG //\t\t\tgetterName\n// @if CK_DEBUG //\t\t} );\n// @if CK_DEBUG // }\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/converters/downcast\n */\n\nimport TableWalker from './../tablewalker';\nimport { setHighlightHandling, toWidget, toWidgetEditable } from '@ckeditor/ckeditor5-widget/src/utils';\nimport toArray from '@ckeditor/ckeditor5-utils/src/toarray';\n\n/**\n * Model table element to view table element conversion helper.\n *\n * This conversion helper creates the whole table element with child elements.\n *\n * @param {Object} options\n * @param {Boolean} options.asWidget If set to `true`, the downcast conversion will produce a widget.\n * @returns {Function} Conversion helper.\n */\nexport function downcastInsertTable( options = {} ) {\n\treturn dispatcher => dispatcher.on( 'insert:table', ( evt, data, conversionApi ) => {\n\t\tconst table = data.item;\n\n\t\tif ( !conversionApi.consumable.consume( table, 'insert' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Consume attributes if present to not fire attribute change downcast\n\t\tconversionApi.consumable.consume( table, 'attribute:headingRows:table' );\n\t\tconversionApi.consumable.consume( table, 'attribute:headingColumns:table' );\n\n\t\tconst asWidget = options && options.asWidget;\n\n\t\tconst figureElement = conversionApi.writer.createContainerElement( 'figure', { class: 'table' } );\n\t\tconst tableElement = conversionApi.writer.createContainerElement( 'table' );\n\t\tconversionApi.writer.insert( conversionApi.writer.createPositionAt( figureElement, 0 ), tableElement );\n\n\t\tlet tableWidget;\n\n\t\tif ( asWidget ) {\n\t\t\ttableWidget = toTableWidget( figureElement, conversionApi.writer );\n\t\t}\n\n\t\tconst tableWalker = new TableWalker( table );\n\n\t\tconst tableAttributes = {\n\t\t\theadingRows: table.getAttribute( 'headingRows' ) || 0,\n\t\t\theadingColumns: table.getAttribute( 'headingColumns' ) || 0\n\t\t};\n\n\t\t// Cache for created table rows.\n\t\tconst viewRows = new Map();\n\n\t\tfor ( const tableSlot of tableWalker ) {\n\t\t\tconst { row, cell } = tableSlot;\n\n\t\t\tconst tableRow = table.getChild( row );\n\t\t\tconst trElement = viewRows.get( row ) || createTr( tableElement, tableRow, row, tableAttributes, conversionApi );\n\t\t\tviewRows.set( row, trElement );\n\n\t\t\t// Consume table cell - it will be always consumed as we convert whole table at once.\n\t\t\tconversionApi.consumable.consume( cell, 'insert' );\n\n\t\t\tconst insertPosition = conversionApi.writer.createPositionAt( trElement, 'end' );\n\n\t\t\tcreateViewTableCellElement( tableSlot, tableAttributes, insertPosition, conversionApi, options );\n\t\t}\n\n\t\t// Insert empty TR elements if there are any rows without anchored cells. Since the model is always normalized\n\t\t// this can happen only in the document fragment that only part of the table is down-casted.\n\t\tfor ( const tableRow of table.getChildren() ) {\n\t\t\tconst rowIndex = tableRow.index;\n\n\t\t\tif ( !viewRows.has( rowIndex ) ) {\n\t\t\t\tviewRows.set( rowIndex, createTr( tableElement, tableRow, rowIndex, tableAttributes, conversionApi ) );\n\t\t\t}\n\t\t}\n\n\t\tconst viewPosition = conversionApi.mapper.toViewPosition( data.range.start );\n\n\t\tconversionApi.mapper.bindElements( table, asWidget ? tableWidget : figureElement );\n\t\tconversionApi.writer.insert( viewPosition, asWidget ? tableWidget : figureElement );\n\t} );\n}\n\n/**\n * Model row element to view `<tr>` element conversion helper.\n *\n * This conversion helper creates the whole `<tr>` element with child elements.\n *\n * @returns {Function} Conversion helper.\n */\nexport function downcastInsertRow() {\n\treturn dispatcher => dispatcher.on( 'insert:tableRow', ( evt, data, conversionApi ) => {\n\t\tconst tableRow = data.item;\n\n\t\tif ( !conversionApi.consumable.consume( tableRow, 'insert' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst table = tableRow.parent;\n\n\t\tconst figureElement = conversionApi.mapper.toViewElement( table );\n\t\tconst tableElement = getViewTable( figureElement );\n\n\t\tconst row = table.getChildIndex( tableRow );\n\n\t\tconst tableWalker = new TableWalker( table, { row } );\n\n\t\tconst tableAttributes = {\n\t\t\theadingRows: table.getAttribute( 'headingRows' ) || 0,\n\t\t\theadingColumns: table.getAttribute( 'headingColumns' ) || 0\n\t\t};\n\n\t\t// Cache for created table rows.\n\t\tconst viewRows = new Map();\n\n\t\tfor ( const tableSlot of tableWalker ) {\n\t\t\tconst trElement = viewRows.get( row ) || createTr( tableElement, tableRow, row, tableAttributes, conversionApi );\n\t\t\tviewRows.set( row, trElement );\n\n\t\t\t// Consume table cell - it will be always consumed as we convert whole row at once.\n\t\t\tconversionApi.consumable.consume( tableSlot.cell, 'insert' );\n\n\t\t\tconst insertPosition = conversionApi.writer.createPositionAt( trElement, 'end' );\n\n\t\t\tcreateViewTableCellElement( tableSlot, tableAttributes, insertPosition, conversionApi, { asWidget: true } );\n\t\t}\n\t} );\n}\n\n/**\n * Model table cell element to view `<td>` or `<th>` element conversion helper.\n *\n * This conversion helper will create proper `<th>` elements for table cells that are in the heading section (heading row or column)\n * and `<td>` otherwise.\n *\n * @returns {Function} Conversion helper.\n */\nexport function downcastInsertCell() {\n\treturn dispatcher => dispatcher.on( 'insert:tableCell', ( evt, data, conversionApi ) => {\n\t\tconst tableCell = data.item;\n\n\t\tif ( !conversionApi.consumable.consume( tableCell, 'insert' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst tableRow = tableCell.parent;\n\t\tconst table = tableRow.parent;\n\t\tconst rowIndex = table.getChildIndex( tableRow );\n\n\t\tconst tableWalker = new TableWalker( table, { row: rowIndex } );\n\n\t\tconst tableAttributes = {\n\t\t\theadingRows: table.getAttribute( 'headingRows' ) || 0,\n\t\t\theadingColumns: table.getAttribute( 'headingColumns' ) || 0\n\t\t};\n\n\t\t// We need to iterate over a table in order to get proper row & column values from a walker\n\t\tfor ( const tableSlot of tableWalker ) {\n\t\t\tif ( tableSlot.cell === tableCell ) {\n\t\t\t\tconst trElement = conversionApi.mapper.toViewElement( tableRow );\n\t\t\t\tconst insertPosition = conversionApi.writer.createPositionAt( trElement, tableRow.getChildIndex( tableCell ) );\n\n\t\t\t\tcreateViewTableCellElement( tableSlot, tableAttributes, insertPosition, conversionApi, { asWidget: true } );\n\n\t\t\t\t// No need to iterate further.\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t} );\n}\n\n/**\n * Conversion helper that acts on heading column table attribute change.\n *\n * Depending on changed attributes this converter will rename `<td` to `<th>` elements or vice versa depending on the cell column index.\n *\n * @returns {Function} Conversion helper.\n */\nexport function downcastTableHeadingColumnsChange() {\n\treturn dispatcher => dispatcher.on( 'attribute:headingColumns:table', ( evt, data, conversionApi ) => {\n\t\tconst table = data.item;\n\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst tableAttributes = {\n\t\t\theadingRows: table.getAttribute( 'headingRows' ) || 0,\n\t\t\theadingColumns: table.getAttribute( 'headingColumns' ) || 0\n\t\t};\n\n\t\tconst oldColumns = data.attributeOldValue;\n\t\tconst newColumns = data.attributeNewValue;\n\n\t\tconst lastColumnToCheck = ( oldColumns > newColumns ? oldColumns : newColumns ) - 1;\n\n\t\tfor ( const tableSlot of new TableWalker( table, { endColumn: lastColumnToCheck } ) ) {\n\t\t\trenameViewTableCellIfRequired( tableSlot, tableAttributes, conversionApi );\n\t\t}\n\t} );\n}\n\n/**\n * Conversion helper that acts on a removed row.\n *\n * @returns {Function} Conversion helper.\n */\nexport function downcastRemoveRow() {\n\treturn dispatcher => dispatcher.on( 'remove:tableRow', ( evt, data, conversionApi ) => {\n\t\t// Prevent default remove converter.\n\t\tevt.stop();\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst mapper = conversionApi.mapper;\n\n\t\tconst viewStart = mapper.toViewPosition( data.position ).getLastMatchingPosition( value => !value.item.is( 'element', 'tr' ) );\n\t\tconst viewItem = viewStart.nodeAfter;\n\t\tconst tableSection = viewItem.parent;\n\t\tconst viewTable = tableSection.parent;\n\n\t\t// Remove associated <tr> from the view.\n\t\tconst removeRange = viewWriter.createRangeOn( viewItem );\n\t\tconst removed = viewWriter.remove( removeRange );\n\n\t\tfor ( const child of viewWriter.createRangeIn( removed ).getItems() ) {\n\t\t\tmapper.unbindViewElement( child );\n\t\t}\n\n\t\t// Cleanup: Ensure that thead & tbody sections are removed if left empty after removing rows. See #6437, #6391.\n\t\tremoveTableSectionIfEmpty( 'thead', viewTable, conversionApi );\n\t\tremoveTableSectionIfEmpty( 'tbody', viewTable, conversionApi );\n\t}, { priority: 'higher' } );\n}\n\n/**\n * Overrides paragraph inside table cell conversion.\n *\n * This converter:\n * * should be used to override default paragraph conversion in the editing view.\n * * It will only convert <paragraph> placed directly inside <tableCell>.\n * * For a single paragraph without attributes it returns `<span>` to simulate data table.\n * * For all other cases it returns `<p>` element.\n *\n * @param {module:engine/model/element~Element} modelElement\n * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n * @returns {module:engine/view/containerelement~ContainerElement|undefined}\n */\nexport function convertParagraphInTableCell( modelElement, conversionApi ) {\n\tconst { writer } = conversionApi;\n\n\tif ( !modelElement.parent.is( 'element', 'tableCell' ) ) {\n\t\treturn;\n\t}\n\n\tif ( isSingleParagraphWithoutAttributes( modelElement ) ) {\n\t\t// Use display:inline-block to force Chrome/Safari to limit text mutations to this element.\n\t\t// See #6062.\n\t\treturn writer.createContainerElement( 'span', { style: 'display:inline-block' } );\n\t} else {\n\t\treturn writer.createContainerElement( 'p' );\n\t}\n}\n\n/**\n * Checks if given model `<paragraph>` is an only child of a parent (`<tableCell>`) and if it has any attribute set.\n *\n * The paragraph should be converted in the editing view to:\n *\n * * If returned `true` - to a `<span style=\"display:inline-block\">`\n * * If returned `false` - to a `<p>`\n *\n * @param {module:engine/model/element~Element} modelElement\n * @returns {Boolean}\n */\nexport function isSingleParagraphWithoutAttributes( modelElement ) {\n\tconst tableCell = modelElement.parent;\n\n\tconst isSingleParagraph = tableCell.childCount === 1;\n\n\treturn isSingleParagraph && !hasAnyAttribute( modelElement );\n}\n\n// Converts a given {@link module:engine/view/element~Element} to a table widget:\n// * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to recognize the table widget element.\n// * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator.\n//\n// @param {module:engine/view/element~Element} viewElement\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer An instance of the view writer.\n// @param {String} label The element's label. It will be concatenated with the table `alt` attribute if one is present.\n// @returns {module:engine/view/element~Element}\nfunction toTableWidget( viewElement, writer ) {\n\twriter.setCustomProperty( 'table', true, viewElement );\n\n\treturn toWidget( viewElement, writer, { hasSelectionHandle: true } );\n}\n\n// Renames an existing table cell in the view to a given element name.\n//\n// **Note** This method will not do anything if a view table cell has not been converted yet.\n//\n// @param {module:engine/model/element~Element} tableCell\n// @param {String} desiredCellElementName\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\nfunction renameViewTableCell( tableCell, desiredCellElementName, conversionApi ) {\n\tconst viewWriter = conversionApi.writer;\n\tconst viewCell = conversionApi.mapper.toViewElement( tableCell );\n\n\tconst editable = viewWriter.createEditableElement( desiredCellElementName, viewCell.getAttributes() );\n\tconst renamedCell = toWidgetEditable( editable, viewWriter );\n\n\tsetHighlightHandling(\n\t\trenamedCell,\n\t\tviewWriter,\n\t\t( element, descriptor, writer ) => writer.addClass( toArray( descriptor.classes ), element ),\n\t\t( element, descriptor, writer ) => writer.removeClass( toArray( descriptor.classes ), element )\n\t);\n\n\tviewWriter.insert( viewWriter.createPositionAfter( viewCell ), renamedCell );\n\tviewWriter.move( viewWriter.createRangeIn( viewCell ), viewWriter.createPositionAt( renamedCell, 0 ) );\n\tviewWriter.remove( viewWriter.createRangeOn( viewCell ) );\n\n\tconversionApi.mapper.unbindViewElement( viewCell );\n\tconversionApi.mapper.bindElements( tableCell, renamedCell );\n}\n\n// Renames a table cell element in the view according to its location in the table.\n//\n// @param {module:table/tablewalker~TableSlot} tableSlot\n// @param {{headingColumns, headingRows}} tableAttributes\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\nfunction renameViewTableCellIfRequired( tableSlot, tableAttributes, conversionApi ) {\n\tconst { cell } = tableSlot;\n\n\t// Check whether current columnIndex is overlapped by table cells from previous rows.\n\tconst desiredCellElementName = getCellElementName( tableSlot, tableAttributes );\n\n\tconst viewCell = conversionApi.mapper.toViewElement( cell );\n\n\t// If in single change we're converting attribute changes and inserting cell the table cell might not be inserted into view\n\t// because of child conversion is done after parent.\n\tif ( viewCell && viewCell.name !== desiredCellElementName ) {\n\t\trenameViewTableCell( cell, desiredCellElementName, conversionApi );\n\t}\n}\n\n// Creates a table cell element in the view.\n//\n// @param {module:table/tablewalker~TableSlot} tableSlot\n// @param {module:engine/view/position~Position} insertPosition\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\nfunction createViewTableCellElement( tableSlot, tableAttributes, insertPosition, conversionApi, options ) {\n\tconst asWidget = options && options.asWidget;\n\tconst cellElementName = getCellElementName( tableSlot, tableAttributes );\n\n\tconst cellElement = asWidget ?\n\t\ttoWidgetEditable( conversionApi.writer.createEditableElement( cellElementName ), conversionApi.writer ) :\n\t\tconversionApi.writer.createContainerElement( cellElementName );\n\n\tif ( asWidget ) {\n\t\tsetHighlightHandling(\n\t\t\tcellElement,\n\t\t\tconversionApi.writer,\n\t\t\t( element, descriptor, writer ) => writer.addClass( toArray( descriptor.classes ), element ),\n\t\t\t( element, descriptor, writer ) => writer.removeClass( toArray( descriptor.classes ), element )\n\t\t);\n\t}\n\n\tconst tableCell = tableSlot.cell;\n\n\tconst firstChild = tableCell.getChild( 0 );\n\tconst isSingleParagraph = tableCell.childCount === 1 && firstChild.name === 'paragraph';\n\n\tconversionApi.writer.insert( insertPosition, cellElement );\n\n\tconversionApi.mapper.bindElements( tableCell, cellElement );\n\n\t// Additional requirement for data pipeline to have backward compatible data tables.\n\tif ( !asWidget && !hasAnyAttribute( firstChild ) && isSingleParagraph ) {\n\t\tconst innerParagraph = tableCell.getChild( 0 );\n\n\t\tconversionApi.consumable.consume( innerParagraph, 'insert' );\n\n\t\tconversionApi.mapper.bindElements( innerParagraph, cellElement );\n\t}\n}\n\n// Creates a `<tr>` view element.\n//\n// @param {module:engine/view/element~Element} tableElement\n// @param {module:engine/model/element~Element} tableRow\n// @param {Number} rowIndex\n// @param {{headingColumns, headingRows}} tableAttributes\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n// @returns {module:engine/view/element~Element}\nfunction createTr( tableElement, tableRow, rowIndex, tableAttributes, conversionApi ) {\n\t// Will always consume since we're converting <tableRow> element from a parent <table>.\n\tconversionApi.consumable.consume( tableRow, 'insert' );\n\n\tconst trElement = tableRow.isEmpty ?\n\t\tconversionApi.writer.createEmptyElement( 'tr' ) :\n\t\tconversionApi.writer.createContainerElement( 'tr' );\n\n\tconversionApi.mapper.bindElements( tableRow, trElement );\n\n\tconst headingRows = tableAttributes.headingRows;\n\tconst tableSection = getOrCreateTableSection( getSectionName( rowIndex, tableAttributes ), tableElement, conversionApi );\n\n\tconst offset = headingRows > 0 && rowIndex >= headingRows ? rowIndex - headingRows : rowIndex;\n\tconst position = conversionApi.writer.createPositionAt( tableSection, offset );\n\n\tconversionApi.writer.insert( position, trElement );\n\n\treturn trElement;\n}\n\n// Returns `th` for heading cells and `td` for other cells for the current table walker value.\n//\n// @param {module:table/tablewalker~TableSlot} tableSlot\n// @param {{headingColumns, headingRows}} tableAttributes\n// @returns {String}\nfunction getCellElementName( tableSlot, tableAttributes ) {\n\tconst { row, column } = tableSlot;\n\tconst { headingColumns, headingRows } = tableAttributes;\n\n\t// Column heading are all tableCells in the first `columnHeading` rows.\n\tconst isColumnHeading = headingRows && headingRows > row;\n\n\t// So a whole row gets <th> element.\n\tif ( isColumnHeading ) {\n\t\treturn 'th';\n\t}\n\n\t// Row heading are tableCells which columnIndex is lower then headingColumns.\n\tconst isRowHeading = headingColumns && headingColumns > column;\n\n\treturn isRowHeading ? 'th' : 'td';\n}\n\n// Returns the table section name for the current table walker value.\n//\n// @param {Number} row\n// @param {{headingColumns, headingRows}} tableAttributes\n// @returns {String}\nfunction getSectionName( row, tableAttributes ) {\n\treturn row < tableAttributes.headingRows ? 'thead' : 'tbody';\n}\n\n// Creates or returns an existing `<tbody>` or `<thead>` element with caching.\n//\n// @param {String} sectionName\n// @param {module:engine/view/element~Element} viewTable\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n// @param {Object} cachedTableSection An object that stores cached elements.\n// @returns {module:engine/view/containerelement~ContainerElement}\nfunction getOrCreateTableSection( sectionName, viewTable, conversionApi ) {\n\tconst viewTableSection = getExistingTableSectionElement( sectionName, viewTable );\n\n\treturn viewTableSection ? viewTableSection : createTableSection( sectionName, viewTable, conversionApi );\n}\n\n// Finds an existing `<tbody>` or `<thead>` element or returns undefined.\n//\n// @param {String} sectionName\n// @param {module:engine/view/element~Element} tableElement\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\nfunction getExistingTableSectionElement( sectionName, tableElement ) {\n\tfor ( const tableSection of tableElement.getChildren() ) {\n\t\tif ( tableSection.name == sectionName ) {\n\t\t\treturn tableSection;\n\t\t}\n\t}\n}\n\n// Creates a table section at the end of the table.\n//\n// @param {String} sectionName\n// @param {module:engine/view/element~Element} tableElement\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n// @returns {module:engine/view/containerelement~ContainerElement}\nfunction createTableSection( sectionName, tableElement, conversionApi ) {\n\tconst tableChildElement = conversionApi.writer.createContainerElement( sectionName );\n\n\tconst insertPosition = conversionApi.writer.createPositionAt( tableElement, sectionName == 'tbody' ? 'end' : 0 );\n\n\tconversionApi.writer.insert( insertPosition, tableChildElement );\n\n\treturn tableChildElement;\n}\n\n// Removes an existing `<tbody>` or `<thead>` element if it is empty.\n//\n// @param {String} sectionName\n// @param {module:engine/view/element~Element} tableElement\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\nfunction removeTableSectionIfEmpty( sectionName, tableElement, conversionApi ) {\n\tconst tableSection = getExistingTableSectionElement( sectionName, tableElement );\n\n\tif ( tableSection && tableSection.childCount === 0 ) {\n\t\tconversionApi.writer.remove( conversionApi.writer.createRangeOn( tableSection ) );\n\t}\n}\n\n// Finds a '<table>' element inside the `<figure>` widget.\n//\n// @param {module:engine/view/element~Element} viewFigure\nfunction getViewTable( viewFigure ) {\n\tfor ( const child of viewFigure.getChildren() ) {\n\t\tif ( child.name === 'table' ) {\n\t\t\treturn child;\n\t\t}\n\t}\n}\n\n// Checks if an element has any attributes set.\n//\n// @param {module:engine/model/element~Element element\n// @returns {Boolean}\nfunction hasAnyAttribute( element ) {\n\treturn !![ ...element.getAttributeKeys() ].length;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/commands/inserttablecommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { findOptimalInsertionPosition } from '@ckeditor/ckeditor5-widget/src/utils';\n\n/**\n * The insert table command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'insertTable'` editor command.\n *\n * To insert a table at the current selection, execute the command and specify the dimensions:\n *\n *\t\teditor.execute( 'insertTable', { rows: 20, columns: 5 } );\n *\n * @extends module:core/command~Command\n */\nexport default class InsertTableCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst schema = model.schema;\n\n\t\tconst validParent = getInsertTableParent( selection.getFirstPosition() );\n\n\t\tthis.isEnabled = schema.checkChild( validParent, 'table' );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * Inserts a table with the given number of rows and columns into the editor.\n\t *\n\t * @param {Object} options\n\t * @param {Number} [options.rows=2] The number of rows to create in the inserted table.\n\t * @param {Number} [options.columns=2] The number of columns to create in the inserted table.\n\t * @param {Number} [options.headingRows=0] The number of heading rows.\n\t * @param {Number} [options.headingColumns=0] The number of heading columns.\n\t * @fires execute\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\n\t\tconst insertPosition = findOptimalInsertionPosition( selection, model );\n\n\t\tmodel.change( writer => {\n\t\t\tconst table = tableUtils.createTable( writer, options );\n\n\t\t\tmodel.insertContent( table, insertPosition );\n\n\t\t\twriter.setSelection( writer.createPositionAt( table.getNodeByPath( [ 0, 0, 0 ] ), 0 ) );\n\t\t} );\n\t}\n}\n\n// Returns valid parent to insert table\n//\n// @param {module:engine/model/position} position\nfunction getInsertTableParent( position ) {\n\tconst parent = position.parent;\n\n\treturn parent === parent.root ? parent : parent.parent;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/utils/selection\n */\n\nimport TableWalker from '../tablewalker';\n\n/**\n * Returns all model table cells that are fully selected (from the outside)\n * within the provided model selection's ranges.\n *\n * To obtain the cells selected from the inside, use\n * {@link module:table/utils/selection~getTableCellsContainingSelection}.\n *\n * @param {module:engine/model/selection~Selection} selection\n * @returns {Array.<module:engine/model/element~Element>}\n */\nexport function getSelectedTableCells( selection ) {\n\tconst cells = [];\n\n\tfor ( const range of sortRanges( selection.getRanges() ) ) {\n\t\tconst element = range.getContainedElement();\n\n\t\tif ( element && element.is( 'element', 'tableCell' ) ) {\n\t\t\tcells.push( element );\n\t\t}\n\t}\n\n\treturn cells;\n}\n\n/**\n * Returns all model table cells that the provided model selection's ranges\n * {@link module:engine/model/range~Range#start} inside.\n *\n * To obtain the cells selected from the outside, use\n * {@link module:table/utils/selection~getSelectedTableCells}.\n *\n * @param {module:engine/model/selection~Selection} selection\n * @returns {Array.<module:engine/model/element~Element>}\n */\nexport function getTableCellsContainingSelection( selection ) {\n\tconst cells = [];\n\n\tfor ( const range of selection.getRanges() ) {\n\t\tconst cellWithSelection = range.start.findAncestor( 'tableCell' );\n\n\t\tif ( cellWithSelection ) {\n\t\t\tcells.push( cellWithSelection );\n\t\t}\n\t}\n\n\treturn cells;\n}\n\n/**\n * Returns all model table cells that are either completely selected\n * by selection ranges or host selection range\n * {@link module:engine/model/range~Range#start start positions} inside them.\n *\n * Combines {@link module:table/utils/selection~getTableCellsContainingSelection} and\n * {@link module:table/utils/selection~getSelectedTableCells}.\n *\n * @param {module:engine/model/selection~Selection} selection\n * @returns {Array.<module:engine/model/element~Element>}\n */\nexport function getSelectionAffectedTableCells( selection ) {\n\tconst selectedCells = getSelectedTableCells( selection );\n\n\tif ( selectedCells.length ) {\n\t\treturn selectedCells;\n\t}\n\n\treturn getTableCellsContainingSelection( selection );\n}\n\n/**\n * Returns an object with the `first` and `last` row index contained in the given `tableCells`.\n *\n *\t\tconst selectedTableCells = getSelectedTableCells( editor.model.document.selection );\n *\n *\t\tconst { first, last } = getRowIndexes( selectedTableCells );\n *\n *\t\tconsole.log( `Selected rows: ${ first } to ${ last }` );\n *\n * @param {Array.<module:engine/model/element~Element>} tableCells\n * @returns {Object} Returns an object with the `first` and `last` table row indexes.\n */\nexport function getRowIndexes( tableCells ) {\n\tconst indexes = tableCells.map( cell => cell.parent.index );\n\n\treturn getFirstLastIndexesObject( indexes );\n}\n\n/**\n * Returns an object with the `first` and `last` column index contained in the given `tableCells`.\n *\n *\t\tconst selectedTableCells = getSelectedTableCells( editor.model.document.selection );\n *\n *\t\tconst { first, last } = getColumnIndexes( selectedTableCells );\n *\n *\t\tconsole.log( `Selected columns: ${ first } to ${ last }` );\n *\n * @param {Array.<module:engine/model/element~Element>} tableCells\n * @returns {Object} Returns an object with the `first` and `last` table column indexes.\n */\nexport function getColumnIndexes( tableCells ) {\n\tconst table = tableCells[ 0 ].findAncestor( 'table' );\n\tconst tableMap = [ ...new TableWalker( table ) ];\n\n\tconst indexes = tableMap\n\t\t.filter( entry => tableCells.includes( entry.cell ) )\n\t\t.map( entry => entry.column );\n\n\treturn getFirstLastIndexesObject( indexes );\n}\n\n/**\n * Checks if the selection contains cells that do not exceed rectangular selection.\n *\n * In a table below:\n *\n *\t\t┌───┬───┬───┬───┐\n *\t\t│ a │ b │ c │ d │\n *\t\t├───┴───┼───┤   │\n *\t\t│ e     │ f │   │\n *\t\t│       ├───┼───┤\n *\t\t│       │ g │ h │\n *\t\t└───────┴───┴───┘\n *\n * Valid selections are these which create a solid rectangle (without gaps), such as:\n *   - a, b (two horizontal cells)\n *   - c, f (two vertical cells)\n *   - a, b, e (cell \"e\" spans over four cells)\n *   - c, d, f (cell d spans over a cell in the row below)\n *\n * While an invalid selection would be:\n *   - a, c (the unselected cell \"b\" creates a gap)\n *   - f, g, h (cell \"d\" spans over a cell from the row of \"f\" cell - thus creates a gap)\n *\n * @param {Array.<module:engine/model/element~Element>} selectedTableCells\n * @param {module:table/tableutils~TableUtils} tableUtils\n * @returns {Boolean}\n */\nexport function isSelectionRectangular( selectedTableCells, tableUtils ) {\n\tif ( selectedTableCells.length < 2 || !areCellInTheSameTableSection( selectedTableCells ) ) {\n\t\treturn false;\n\t}\n\n\t// A valid selection is a fully occupied rectangle composed of table cells.\n\t// Below we will calculate the area of a selected table cells and the area of valid selection.\n\t// The area of a valid selection is defined by top-left and bottom-right cells.\n\tconst rows = new Set();\n\tconst columns = new Set();\n\n\tlet areaOfSelectedCells = 0;\n\n\tfor ( const tableCell of selectedTableCells ) {\n\t\tconst { row, column } = tableUtils.getCellLocation( tableCell );\n\t\tconst rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );\n\t\tconst colspan = parseInt( tableCell.getAttribute( 'colspan' ) || 1 );\n\n\t\t// Record row & column indexes of current cell.\n\t\trows.add( row );\n\t\tcolumns.add( column );\n\n\t\t// For cells that spans over multiple rows add also the last row that this cell spans over.\n\t\tif ( rowspan > 1 ) {\n\t\t\trows.add( row + rowspan - 1 );\n\t\t}\n\n\t\t// For cells that spans over multiple columns add also the last column that this cell spans over.\n\t\tif ( colspan > 1 ) {\n\t\t\tcolumns.add( column + colspan - 1 );\n\t\t}\n\n\t\tareaOfSelectedCells += ( rowspan * colspan );\n\t}\n\n\t// We can only merge table cells that are in adjacent rows...\n\tconst areaOfValidSelection = getBiggestRectangleArea( rows, columns );\n\n\treturn areaOfValidSelection == areaOfSelectedCells;\n}\n\n/**\n * Returns array of sorted ranges.\n *\n * @param {Iterable.<module:engine/model/range~Range>} ranges\n * @return {Array.<module:engine/model/range~Range>}\n */\nexport function sortRanges( ranges ) {\n\treturn Array.from( ranges ).sort( compareRangeOrder );\n}\n\n// Helper method to get an object with `first` and `last` indexes from an unsorted array of indexes.\nfunction getFirstLastIndexesObject( indexes ) {\n\tconst allIndexesSorted = indexes.sort( ( indexA, indexB ) => indexA - indexB );\n\n\tconst first = allIndexesSorted[ 0 ];\n\tconst last = allIndexesSorted[ allIndexesSorted.length - 1 ];\n\n\treturn { first, last };\n}\n\nfunction compareRangeOrder( rangeA, rangeB ) {\n\t// Since table cell ranges are disjoint, it's enough to check their start positions.\n\tconst posA = rangeA.start;\n\tconst posB = rangeB.start;\n\n\t// Checking for equal position (returning 0) is not needed because this would be either:\n\t// a. Intersecting range (not allowed by model)\n\t// b. Collapsed range on the same position (allowed by model but should not happen).\n\treturn posA.isBefore( posB ) ? -1 : 1;\n}\n\n// Calculates the area of a maximum rectangle that can span over the provided row & column indexes.\n//\n// @param {Array.<Number>} rows\n// @param {Array.<Number>} columns\n// @returns {Number}\nfunction getBiggestRectangleArea( rows, columns ) {\n\tconst rowsIndexes = Array.from( rows.values() );\n\tconst columnIndexes = Array.from( columns.values() );\n\n\tconst lastRow = Math.max( ...rowsIndexes );\n\tconst firstRow = Math.min( ...rowsIndexes );\n\tconst lastColumn = Math.max( ...columnIndexes );\n\tconst firstColumn = Math.min( ...columnIndexes );\n\n\treturn ( lastRow - firstRow + 1 ) * ( lastColumn - firstColumn + 1 );\n}\n\n// Checks if the selection does not mix a header (column or row) with other cells.\n//\n// For instance, in the table below valid selections consist of cells with the same letter only.\n// So, a-a (same heading row and column) or d-d (body cells) are valid while c-d or a-b are not.\n//\n//\t\t header columns\n//\t\t  ↓   ↓\n//\t\t┌───┬───┬───┬───┐\n//\t\t│ a │ a │ b │ b │  ← header row\n//\t\t├───┼───┼───┼───┤\n//\t\t│ c │ c │ d │ d │\n//\t\t├───┼───┼───┼───┤\n//\t\t│ c │ c │ d │ d │\n//\t\t└───┴───┴───┴───┘\nfunction areCellInTheSameTableSection( tableCells ) {\n\tconst table = tableCells[ 0 ].findAncestor( 'table' );\n\n\tconst rowIndexes = getRowIndexes( tableCells );\n\tconst headingRows = parseInt( table.getAttribute( 'headingRows' ) || 0 );\n\n\t// Calculating row indexes is a bit cheaper so if this check fails we can't merge.\n\tif ( !areIndexesInSameSection( rowIndexes, headingRows ) ) {\n\t\treturn false;\n\t}\n\n\tconst headingColumns = parseInt( table.getAttribute( 'headingColumns' ) || 0 );\n\tconst columnIndexes = getColumnIndexes( tableCells );\n\n\t// Similarly cells must be in same column section.\n\treturn areIndexesInSameSection( columnIndexes, headingColumns );\n}\n\n// Unified check if table rows/columns indexes are in the same heading/body section.\nfunction areIndexesInSameSection( { first, last }, headingSectionSize ) {\n\tconst firstCellIsInHeading = first < headingSectionSize;\n\tconst lastCellIsInHeading = last < headingSectionSize;\n\n\treturn firstCellIsInHeading === lastCellIsInHeading;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/commands/insertrowcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { getRowIndexes, getSelectionAffectedTableCells } from '../utils/selection';\n\n/**\n * The insert row command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'insertTableRowBelow'` and\n * `'insertTableRowAbove'` editor commands.\n *\n * To insert a row below the selected cell, execute the following command:\n *\n *\t\teditor.execute( 'insertTableRowBelow' );\n *\n * To insert a row above the selected cell, execute the following command:\n *\n *\t\teditor.execute( 'insertTableRowAbove' );\n *\n * @extends module:core/command~Command\n */\nexport default class InsertRowCommand extends Command {\n\t/**\n\t * Creates a new `InsertRowCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor on which this command will be used.\n\t * @param {Object} options\n\t * @param {String} [options.order=\"below\"] The order of insertion relative to the row in which the caret is located.\n\t * Possible values: `\"above\"` and `\"below\"`.\n\t */\n\tconstructor( editor, options = {} ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The order of insertion relative to the row in which the caret is located.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} module:table/commands/insertrowcommand~InsertRowCommand#order\n\t\t */\n\t\tthis.order = options.order || 'below';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst selection = this.editor.model.document.selection;\n\n\t\tconst tableParent = selection.getFirstPosition().findAncestor( 'table' );\n\n\t\tthis.isEnabled = !!tableParent;\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * Depending on the command's {@link #order} value, it inserts a row `'below'` or `'above'` the row in which selection is set.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\t\tconst tableUtils = editor.plugins.get( 'TableUtils' );\n\t\tconst insertAbove = this.order === 'above';\n\n\t\tconst affectedTableCells = getSelectionAffectedTableCells( selection );\n\t\tconst rowIndexes = getRowIndexes( affectedTableCells );\n\n\t\tconst row = insertAbove ? rowIndexes.first : rowIndexes.last;\n\t\tconst table = affectedTableCells[ 0 ].findAncestor( 'table' );\n\n\t\ttableUtils.insertRows( table, { at: insertAbove ? row : row + 1, copyStructureFromAbove: !insertAbove } );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/commands/insertcolumncommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { getColumnIndexes, getSelectionAffectedTableCells } from '../utils/selection';\n\n/**\n * The insert column command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'insertTableColumnLeft'` and\n * `'insertTableColumnRight'` editor commands.\n *\n * To insert a column to the left of the selected cell, execute the following command:\n *\n *\t\teditor.execute( 'insertTableColumnLeft' );\n *\n * To insert a column to the right of the selected cell, execute the following command:\n *\n *\t\teditor.execute( 'insertTableColumnRight' );\n *\n * @extends module:core/command~Command\n */\nexport default class InsertColumnCommand extends Command {\n\t/**\n\t * Creates a new `InsertColumnCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor on which this command will be used.\n\t * @param {Object} options\n\t * @param {String} [options.order=\"right\"] The order of insertion relative to the column in which the caret is located.\n\t * Possible values: `\"left\"` and `\"right\"`.\n\t */\n\tconstructor( editor, options = {} ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The order of insertion relative to the column in which the caret is located.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} module:table/commands/insertcolumncommand~InsertColumnCommand#order\n\t\t */\n\t\tthis.order = options.order || 'right';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst selection = this.editor.model.document.selection;\n\n\t\tconst tableParent = selection.getFirstPosition().findAncestor( 'table' );\n\n\t\tthis.isEnabled = !!tableParent;\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * Depending on the command's {@link #order} value, it inserts a column to the `'left'` or `'right'` of the column\n\t * in which the selection is set.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\t\tconst tableUtils = editor.plugins.get( 'TableUtils' );\n\t\tconst insertBefore = this.order === 'left';\n\n\t\tconst affectedTableCells = getSelectionAffectedTableCells( selection );\n\t\tconst columnIndexes = getColumnIndexes( affectedTableCells );\n\n\t\tconst column = insertBefore ? columnIndexes.first : columnIndexes.last;\n\t\tconst table = affectedTableCells[ 0 ].findAncestor( 'table' );\n\n\t\ttableUtils.insertColumns( table, { columns: 1, at: insertBefore ? column : column + 1 } );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/commands/splitcellcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { getSelectionAffectedTableCells } from '../utils/selection';\n\n/**\n * The split cell command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'splitTableCellVertically'`\n * and `'splitTableCellHorizontally'`  editor commands.\n *\n * You can split any cell vertically or horizontally by executing this command. For example, to split the selected table cell vertically:\n *\n *\t\teditor.execute( 'splitTableCellVertically' );\n *\n * @extends module:core/command~Command\n */\nexport default class SplitCellCommand extends Command {\n\t/**\n\t * Creates a new `SplitCellCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor on which this command will be used.\n\t * @param {Object} options\n\t * @param {String} options.direction Indicates whether the command should split cells `'horizontally'` or `'vertically'`.\n\t */\n\tconstructor( editor, options = {} ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The direction that indicates which cell will be split.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} #direction\n\t\t */\n\t\tthis.direction = options.direction || 'horizontally';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst selectedCells = getSelectionAffectedTableCells( this.editor.model.document.selection );\n\n\t\tthis.isEnabled = selectedCells.length === 1;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst tableCell = getSelectionAffectedTableCells( this.editor.model.document.selection )[ 0 ];\n\t\tconst isHorizontal = this.direction === 'horizontally';\n\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\n\t\tif ( isHorizontal ) {\n\t\t\ttableUtils.splitCellHorizontally( tableCell, 2 );\n\t\t} else {\n\t\t\ttableUtils.splitCellVertically( tableCell, 2 );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/utils/structure\n */\n\nimport TableWalker from '../tablewalker';\nimport { createEmptyTableCell, updateNumericAttribute } from './common';\n\n/**\n * Returns a cropped table according to given dimensions.\n\n * To return a cropped table that starts at first row and first column and end in third row and column:\n *\n *\t\tconst croppedTable = cropTableToDimensions( table, {\n *\t\t\tstartRow: 1,\n *\t\t\tendRow: 1,\n *\t\t\tstartColumn: 3,\n *\t\t\tendColumn: 3\n *\t\t}, writer );\n *\n * Calling the code above for the table below:\n *\n *\t\t      0   1   2   3   4                      0   1   2\n *\t\t    ┌───┬───┬───┬───┬───┐\n *\t\t 0  │ a │ b │ c │ d │ e │\n *\t\t    ├───┴───┤   ├───┴───┤                  ┌───┬───┬───┐\n *\t\t 1  │ f     │   │ g     │                  │   │   │ g │  0\n *\t\t    ├───┬───┴───┼───┬───┤   will return:   ├───┴───┼───┤\n *\t\t 2  │ h │ i     │ j │ k │                  │ i     │ j │  1\n *\t\t    ├───┤       ├───┤   │                  │       ├───┤\n *\t\t 3  │ l │       │ m │   │                  │       │ m │  2\n *\t\t    ├───┼───┬───┤   ├───┤                  └───────┴───┘\n *\t\t 4  │ n │ o │ p │   │ q │\n *\t\t    └───┴───┴───┴───┴───┘\n *\n * @param {module:engine/model/element~Element} sourceTable\n * @param {Object} cropDimensions\n * @param {Number} cropDimensions.startRow\n * @param {Number} cropDimensions.startColumn\n * @param {Number} cropDimensions.endRow\n * @param {Number} cropDimensions.endColumn\n * @param {module:engine/model/writer~Writer} writer\n * @returns {module:engine/model/element~Element}\n */\nexport function cropTableToDimensions( sourceTable, cropDimensions, writer ) {\n\tconst { startRow, startColumn, endRow, endColumn } = cropDimensions;\n\n\t// Create empty table with empty rows equal to crop height.\n\tconst croppedTable = writer.createElement( 'table' );\n\tconst cropHeight = endRow - startRow + 1;\n\n\tfor ( let i = 0; i < cropHeight; i++ ) {\n\t\twriter.insertElement( 'tableRow', croppedTable, 'end' );\n\t}\n\n\tconst tableMap = [ ...new TableWalker( sourceTable, { startRow, endRow, startColumn, endColumn, includeAllSlots: true } ) ];\n\n\t// Iterate over source table slots (including empty - spanned - ones).\n\tfor ( const { row: sourceRow, column: sourceColumn, cell: tableCell, isAnchor, cellAnchorRow, cellAnchorColumn } of tableMap ) {\n\t\t// Row index in cropped table.\n\t\tconst rowInCroppedTable = sourceRow - startRow;\n\t\tconst row = croppedTable.getChild( rowInCroppedTable );\n\n\t\t// For empty slots: fill the gap with empty table cell.\n\t\tif ( !isAnchor ) {\n\t\t\t// But fill the gap only if the spanning cell is anchored outside cropped area.\n\t\t\t// In the table from method jsdoc those cells are: \"c\" & \"f\".\n\t\t\tif ( cellAnchorRow < startRow || cellAnchorColumn < startColumn ) {\n\t\t\t\tcreateEmptyTableCell( writer, writer.createPositionAt( row, 'end' ) );\n\t\t\t}\n\t\t}\n\t\t// Otherwise clone the cell with all children and trim if it exceeds cropped area.\n\t\telse {\n\t\t\tconst tableCellCopy = writer.cloneElement( tableCell );\n\n\t\t\twriter.append( tableCellCopy, row );\n\n\t\t\t// Trim table if it exceeds cropped area.\n\t\t\t// In the table from method jsdoc those cells are: \"g\" & \"m\".\n\t\t\ttrimTableCellIfNeeded( tableCellCopy, sourceRow, sourceColumn, endRow, endColumn, writer );\n\t\t}\n\t}\n\n\t// Adjust heading rows & columns in cropped table if crop selection includes headings parts.\n\taddHeadingsToCroppedTable( croppedTable, sourceTable, startRow, startColumn, writer );\n\n\treturn croppedTable;\n}\n\n/**\n * Returns slot info of cells that starts above and overlaps a given row.\n *\n * In a table below, passing `overlapRow = 3`\n *\n *\t\t   ┌───┬───┬───┬───┬───┐\n *\t\t0  │ a │ b │ c │ d │ e │\n *\t\t   │   ├───┼───┼───┼───┤\n *\t\t1  │   │ f │ g │ h │ i │\n *\t\t   ├───┤   ├───┼───┤   │\n *\t\t2  │ j │   │ k │ l │   │\n *\t\t   │   │   │   ├───┼───┤\n *\t\t3  │   │   │   │ m │ n │  <- overlap row to check\n *\t\t   ├───┼───┤   │   ├───│\n *\t\t4  │ o │ p │   │   │ q │\n *\t\t   └───┴───┴───┴───┴───┘\n *\n * will return slot info for cells: \"j\", \"f\", \"k\".\n *\n * @param {module:engine/model/element~Element} table The table to check.\n * @param {Number} overlapRow The index of the row to check.\n * @param {Number} [startRow=0] A row to start analysis. Use it when it is known that the cells above that row will not overlap.\n * @returns {Array.<module:table/tablewalker~TableSlot>}\n */\nexport function getVerticallyOverlappingCells( table, overlapRow, startRow = 0 ) {\n\tconst cells = [];\n\n\tconst tableWalker = new TableWalker( table, { startRow, endRow: overlapRow - 1 } );\n\n\tfor ( const slotInfo of tableWalker ) {\n\t\tconst { row, cellHeight } = slotInfo;\n\t\tconst cellEndRow = row + cellHeight - 1;\n\n\t\tif ( row < overlapRow && overlapRow <= cellEndRow ) {\n\t\t\tcells.push( slotInfo );\n\t\t}\n\t}\n\n\treturn cells;\n}\n\n/**\n * Splits the table cell horizontally.\n *\n * @param {module:engine/model/element~Element} tableCell\n * @param {Number} splitRow\n * @param {module:engine/model/writer~Writer} writer\n * @returns {module:engine/model/element~Element} Created table cell.\n */\nexport function splitHorizontally( tableCell, splitRow, writer ) {\n\tconst tableRow = tableCell.parent;\n\tconst table = tableRow.parent;\n\tconst rowIndex = tableRow.index;\n\n\tconst rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) );\n\tconst newRowspan = splitRow - rowIndex;\n\n\tconst newCellAttributes = {};\n\tconst newCellRowSpan = rowspan - newRowspan;\n\n\tif ( newCellRowSpan > 1 ) {\n\t\tnewCellAttributes.rowspan = newCellRowSpan;\n\t}\n\n\tconst colspan = parseInt( tableCell.getAttribute( 'colspan' ) || 1 );\n\n\tif ( colspan > 1 ) {\n\t\tnewCellAttributes.colspan = colspan;\n\t}\n\n\tconst startRow = rowIndex;\n\tconst endRow = startRow + newRowspan;\n\tconst tableMap = [ ...new TableWalker( table, { startRow, endRow, includeAllSlots: true } ) ];\n\n\tlet newCell = null;\n\tlet columnIndex;\n\n\tfor ( const tableSlot of tableMap ) {\n\t\tconst { row, column, cell } = tableSlot;\n\n\t\tif ( cell === tableCell && columnIndex === undefined ) {\n\t\t\tcolumnIndex = column;\n\t\t}\n\n\t\tif ( columnIndex !== undefined && columnIndex === column && row === endRow ) {\n\t\t\tnewCell = createEmptyTableCell( writer, tableSlot.getPositionBefore(), newCellAttributes );\n\t\t}\n\t}\n\n\t// Update the rowspan attribute after updating table.\n\tupdateNumericAttribute( 'rowspan', newRowspan, tableCell, writer );\n\n\treturn newCell;\n}\n\n/**\n * Returns slot info of cells that starts before and overlaps a given column.\n *\n * In a table below, passing `overlapColumn = 3`\n *\n *\t\t  0   1   2   3   4\n *\t\t┌───────┬───────┬───┐\n *\t\t│ a     │ b     │ c │\n *\t\t│───┬───┴───────┼───┤\n *\t\t│ d │ e         │ f │\n *\t\t├───┼───┬───────┴───┤\n *\t\t│ g │ h │ i         │\n *\t\t├───┼───┼───┬───────┤\n *\t\t│ j │ k │ l │ m     │\n *\t\t├───┼───┴───┼───┬───┤\n *\t\t│ n │ o     │ p │ q │\n *\t\t└───┴───────┴───┴───┘\n *\t\t              ^\n *\t\t              Overlap column to check\n *\n * will return slot info for cells: \"b\", \"e\", \"i\".\n *\n * @param {module:engine/model/element~Element} table The table to check.\n * @param {Number} overlapColumn The index of the column to check.\n * @returns {Array.<module:table/tablewalker~TableSlot>}\n */\nexport function getHorizontallyOverlappingCells( table, overlapColumn ) {\n\tconst cellsToSplit = [];\n\n\tconst tableWalker = new TableWalker( table );\n\n\tfor ( const slotInfo of tableWalker ) {\n\t\tconst { column, cellWidth } = slotInfo;\n\t\tconst cellEndColumn = column + cellWidth - 1;\n\n\t\tif ( column < overlapColumn && overlapColumn <= cellEndColumn ) {\n\t\t\tcellsToSplit.push( slotInfo );\n\t\t}\n\t}\n\n\treturn cellsToSplit;\n}\n\n/**\n * Splits the table cell vertically.\n *\n * @param {module:engine/model/element~Element} tableCell\n * @param {Number} columnIndex The table cell column index.\n * @param {Number} splitColumn The index of column to split cell on.\n * @param {module:engine/model/writer~Writer} writer\n * @returns {module:engine/model/element~Element} Created table cell.\n */\nexport function splitVertically( tableCell, columnIndex, splitColumn, writer ) {\n\tconst colspan = parseInt( tableCell.getAttribute( 'colspan' ) );\n\tconst newColspan = splitColumn - columnIndex;\n\n\tconst newCellAttributes = {};\n\tconst newCellColSpan = colspan - newColspan;\n\n\tif ( newCellColSpan > 1 ) {\n\t\tnewCellAttributes.colspan = newCellColSpan;\n\t}\n\n\tconst rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );\n\n\tif ( rowspan > 1 ) {\n\t\tnewCellAttributes.rowspan = rowspan;\n\t}\n\n\tconst newCell = createEmptyTableCell( writer, writer.createPositionAfter( tableCell ), newCellAttributes );\n\n\t// Update the colspan attribute after updating table.\n\tupdateNumericAttribute( 'colspan', newColspan, tableCell, writer );\n\n\treturn newCell;\n}\n\n/**\n * Adjusts table cell dimensions to not exceed limit row and column.\n *\n * If table cell width (or height) covers a column (or row) that is after a limit column (or row)\n * this method will trim \"colspan\" (or \"rowspan\") attribute so the table cell will fit in a defined limits.\n *\n * @param {module:engine/model/element~Element} tableCell\n * @param {Number} cellRow\n * @param {Number} cellColumn\n * @param {Number} limitRow\n * @param {Number} limitColumn\n * @param {module:engine/model/writer~Writer} writer\n */\nexport function trimTableCellIfNeeded( tableCell, cellRow, cellColumn, limitRow, limitColumn, writer ) {\n\tconst colspan = parseInt( tableCell.getAttribute( 'colspan' ) || 1 );\n\tconst rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );\n\n\tconst endColumn = cellColumn + colspan - 1;\n\n\tif ( endColumn > limitColumn ) {\n\t\tconst trimmedSpan = limitColumn - cellColumn + 1;\n\n\t\tupdateNumericAttribute( 'colspan', trimmedSpan, tableCell, writer, 1 );\n\t}\n\n\tconst endRow = cellRow + rowspan - 1;\n\n\tif ( endRow > limitRow ) {\n\t\tconst trimmedSpan = limitRow - cellRow + 1;\n\n\t\tupdateNumericAttribute( 'rowspan', trimmedSpan, tableCell, writer, 1 );\n\t}\n}\n\n// Sets proper heading attributes to a cropped table.\nfunction addHeadingsToCroppedTable( croppedTable, sourceTable, startRow, startColumn, writer ) {\n\tconst headingRows = parseInt( sourceTable.getAttribute( 'headingRows' ) || 0 );\n\n\tif ( headingRows > 0 ) {\n\t\tconst headingRowsInCrop = headingRows - startRow;\n\t\tupdateNumericAttribute( 'headingRows', headingRowsInCrop, croppedTable, writer, 0 );\n\t}\n\n\tconst headingColumns = parseInt( sourceTable.getAttribute( 'headingColumns' ) || 0 );\n\n\tif ( headingColumns > 0 ) {\n\t\tconst headingColumnsInCrop = headingColumns - startColumn;\n\t\tupdateNumericAttribute( 'headingColumns', headingColumnsInCrop, croppedTable, writer, 0 );\n\t}\n}\n\n/**\n * Removes columns that have no cells anchored.\n *\n * In table below:\n *\n *     +----+----+----+----+----+----+----+\n *     | 00 | 01      | 03 | 04      | 06 |\n *     +----+----+----+----+         +----+\n *     | 10 | 11      | 13 |         | 16 |\n *     +----+----+----+----+----+----+----+\n *     | 20 | 21      | 23 | 24      | 26 |\n *     +----+----+----+----+----+----+----+\n *                  ^--- empty ---^\n *\n * Will remove columns 2 and 5.\n *\n * **Note:** This is a low-level helper method for clearing invalid model state when doing table modifications.\n * To remove a column from a table use {@link module:table/tableutils~TableUtils#removeColumns `TableUtils.removeColumns()`}.\n *\n * @protected\n * @param {module:engine/model/element~Element} table\n * @param {module:table/tableutils~TableUtils} tableUtils\n * @returns {Boolean} True if removed some columns.\n */\nexport function removeEmptyColumns( table, tableUtils ) {\n\tconst width = tableUtils.getColumns( table );\n\tconst columnsMap = new Array( width ).fill( 0 );\n\n\tfor ( const { column } of new TableWalker( table ) ) {\n\t\tcolumnsMap[ column ]++;\n\t}\n\n\tconst emptyColumns = columnsMap.reduce( ( result, cellsCount, column ) => {\n\t\treturn cellsCount ? result : [ ...result, column ];\n\t}, [] );\n\n\tif ( emptyColumns.length > 0 ) {\n\t\t// Remove only last empty column because it will recurrently trigger removing empty rows.\n\t\tconst emptyColumn = emptyColumns[ emptyColumns.length - 1 ];\n\n\t\t// @if CK_DEBUG_TABLE // console.log( `Removing empty column: ${ emptyColumn }.` );\n\t\ttableUtils.removeColumns( table, { at: emptyColumn } );\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n/**\n * Removes rows that have no cells anchored.\n *\n * In table below:\n *\n *     +----+----+----+\n *     | 00 | 01 | 02 |\n *     +----+----+----+\n *     | 10 | 11 | 12 |\n *     +    +    +    +\n *     |    |    |    | <-- empty\n *     +----+----+----+\n *     | 30 | 31 | 32 |\n *     +----+----+----+\n *     | 40      | 42 |\n *     +         +    +\n *     |         |    | <-- empty\n *     +----+----+----+\n *     | 60 | 61 | 62 |\n *     +----+----+----+\n *\n * Will remove rows 2 and 5.\n *\n * **Note:** This is a low-level helper method for clearing invalid model state when doing table modifications.\n * To remove a row from a table use {@link module:table/tableutils~TableUtils#removeRows `TableUtils.removeRows()`}.\n *\n * @protected\n * @param {module:engine/model/element~Element} table\n * @param {module:table/tableutils~TableUtils} tableUtils\n * @returns {Boolean} True if removed some rows.\n */\nexport function removeEmptyRows( table, tableUtils ) {\n\tconst emptyRows = [];\n\n\tfor ( let rowIndex = 0; rowIndex < table.childCount; rowIndex++ ) {\n\t\tconst tableRow = table.getChild( rowIndex );\n\n\t\tif ( tableRow.isEmpty ) {\n\t\t\temptyRows.push( rowIndex );\n\t\t}\n\t}\n\n\tif ( emptyRows.length > 0 ) {\n\t\t// Remove only last empty row because it will recurrently trigger removing empty columns.\n\t\tconst emptyRow = emptyRows[ emptyRows.length - 1 ];\n\n\t\t// @if CK_DEBUG_TABLE // console.log( `Removing empty row: ${ emptyRow }.` );\n\t\ttableUtils.removeRows( table, { at: emptyRow } );\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n/**\n * Removes rows and columns that have no cells anchored.\n *\n * In table below:\n *\n *     +----+----+----+----+\n *     | 00      | 02      |\n *     +----+----+         +\n *     | 10      |         |\n *     +----+----+----+----+\n *     | 20      | 22 | 23 |\n *     +         +    +    +\n *     |         |    |    | <-- empty row\n *     +----+----+----+----+\n *             ^--- empty column\n *\n * Will remove row 3 and column 1.\n *\n * **Note:** This is a low-level helper method for clearing invalid model state when doing table modifications.\n * To remove a rows from a table use {@link module:table/tableutils~TableUtils#removeRows `TableUtils.removeRows()`} and\n * {@link module:table/tableutils~TableUtils#removeColumns `TableUtils.removeColumns()`} to remove a column.\n *\n * @protected\n * @param {module:engine/model/element~Element} table\n * @param {module:table/tableutils~TableUtils} tableUtils\n */\nexport function removeEmptyRowsColumns( table, tableUtils ) {\n\tconst removedColumns = removeEmptyColumns( table, tableUtils );\n\n\t// If there was some columns removed then cleaning empty rows was already triggered.\n\tif ( !removedColumns ) {\n\t\tremoveEmptyRows( table, tableUtils );\n\t}\n}\n\n/**\n * Returns adjusted last row index if selection covers part of a row with empty slots (spanned by other cells).\n * The `dimensions.lastRow` is equal to last row index but selection might be bigger.\n *\n * This happens *only* on rectangular selection so we analyze a case like this:\n *\n *        +---+---+---+---+\n *      0 | a | b | c | d |\n *        +   +   +---+---+\n *      1 |   | e | f | g |\n *        +   +---+   +---+\n *      2 |   | h |   | i | <- last row, each cell has rowspan = 2,\n *        +   +   +   +   +    so we need to return 3, not 2\n *      3 |   |   |   |   |\n *        +---+---+---+---+\n *\n * @param {module:engine/model/element~Element} table\n * @param {Object} dimensions\n * @param {Number} dimensions.firstRow\n * @param {Number} dimensions.firstColumn\n * @param {Number} dimensions.lastRow\n * @param {Number} dimensions.lastColumn\n * @returns {Number} Adjusted last row index.\n */\nexport function adjustLastRowIndex( table, dimensions ) {\n\tconst lastRowMap = Array.from( new TableWalker( table, {\n\t\tstartColumn: dimensions.firstColumn,\n\t\tendColumn: dimensions.lastColumn,\n\t\trow: dimensions.lastRow\n\t} ) );\n\n\tconst everyCellHasSingleRowspan = lastRowMap.every( ( { cellHeight } ) => cellHeight === 1 );\n\n\t// It is a \"flat\" row, so the last row index is OK.\n\tif ( everyCellHasSingleRowspan ) {\n\t\treturn dimensions.lastRow;\n\t}\n\n\t// Otherwise get any cell's rowspan and adjust the last row index.\n\tconst rowspanAdjustment = lastRowMap[ 0 ].cellHeight - 1;\n\treturn dimensions.lastRow + rowspanAdjustment;\n}\n\n/**\n * Returns adjusted last column index if selection covers part of a column with empty slots (spanned by other cells).\n * The `dimensions.lastColumn` is equal to last column index but selection might be bigger.\n *\n * This happens *only* on rectangular selection so we analyze a case like this:\n *\n *       0   1   2   3\n *     +---+---+---+---+\n *     | a             |\n *     +---+---+---+---+\n *     | b | c | d     |\n *     +---+---+---+---+\n *     | e     | f     |\n *     +---+---+---+---+\n *     | g | h         |\n *     +---+---+---+---+\n *               ^\n *              last column, each cell has colspan = 2, so we need to return 3, not 2\n *\n * @param {module:engine/model/element~Element} table\n * @param {Object} dimensions\n * @param {Number} dimensions.firstRow\n * @param {Number} dimensions.firstColumn\n * @param {Number} dimensions.lastRow\n * @param {Number} dimensions.lastColumn\n * @returns {Number} Adjusted last column index.\n */\nexport function adjustLastColumnIndex( table, dimensions ) {\n\tconst lastColumnMap = Array.from( new TableWalker( table, {\n\t\tstartRow: dimensions.firstRow,\n\t\tendRow: dimensions.lastRow,\n\t\tcolumn: dimensions.lastColumn\n\t} ) );\n\n\tconst everyCellHasSingleColspan = lastColumnMap.every( ( { cellWidth } ) => cellWidth === 1 );\n\n\t// It is a \"flat\" column, so the last column index is OK.\n\tif ( everyCellHasSingleColspan ) {\n\t\treturn dimensions.lastColumn;\n\t}\n\n\t// Otherwise get any cell's colspan and adjust the last column index.\n\tconst colspanAdjustment = lastColumnMap[ 0 ].cellWidth - 1;\n\treturn dimensions.lastColumn + colspanAdjustment;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/commands/mergecellcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport TableWalker from '../tablewalker';\nimport { getTableCellsContainingSelection } from '../utils/selection';\nimport { isHeadingColumnCell } from '../utils/common';\nimport { removeEmptyRowsColumns } from '../utils/structure';\n\n/**\n * The merge cell command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'mergeTableCellRight'`, `'mergeTableCellLeft'`,\n * `'mergeTableCellUp'` and `'mergeTableCellDown'` editor commands.\n *\n * To merge a table cell at the current selection with another cell, execute the command corresponding with the preferred direction.\n *\n * For example, to merge with a cell to the right:\n *\n *\t\teditor.execute( 'mergeTableCellRight' );\n *\n * **Note**: If a table cell has a different [`rowspan`](https://www.w3.org/TR/html50/tabular-data.html#attr-tdth-rowspan)\n * (for `'mergeTableCellRight'` and `'mergeTableCellLeft'`) or [`colspan`](https://www.w3.org/TR/html50/tabular-data.html#attr-tdth-colspan)\n * (for `'mergeTableCellUp'` and `'mergeTableCellDown'`), the command will be disabled.\n *\n * @extends module:core/command~Command\n */\nexport default class MergeCellCommand extends Command {\n\t/**\n\t * Creates a new `MergeCellCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor on which this command will be used.\n\t * @param {Object} options\n\t * @param {String} options.direction Indicates which cell to merge with the currently selected one.\n\t * Possible values are: `'left'`, `'right'`, `'up'` and `'down'`.\n\t */\n\tconstructor( editor, options ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The direction that indicates which cell will be merged with the currently selected one.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} #direction\n\t\t */\n\t\tthis.direction = options.direction;\n\n\t\t/**\n\t\t * Whether the merge is horizontal (left/right) or vertical (up/down).\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} #isHorizontal\n\t\t */\n\t\tthis.isHorizontal = this.direction == 'right' || this.direction == 'left';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst cellToMerge = this._getMergeableCell();\n\n\t\tthis.value = cellToMerge;\n\t\tthis.isEnabled = !!cellToMerge;\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * Depending on the command's {@link #direction} value, it will merge the cell that is to the `'left'`, `'right'`, `'up'` or `'down'`.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst tableCell = getTableCellsContainingSelection( doc.selection )[ 0 ];\n\n\t\tconst cellToMerge = this.value;\n\t\tconst direction = this.direction;\n\n\t\tmodel.change( writer => {\n\t\t\tconst isMergeNext = direction == 'right' || direction == 'down';\n\n\t\t\t// The merge mechanism is always the same so sort cells to be merged.\n\t\t\tconst cellToExpand = isMergeNext ? tableCell : cellToMerge;\n\t\t\tconst cellToRemove = isMergeNext ? cellToMerge : tableCell;\n\n\t\t\t// Cache the parent of cell to remove for later check.\n\t\t\tconst removedTableCellRow = cellToRemove.parent;\n\n\t\t\tmergeTableCells( cellToRemove, cellToExpand, writer );\n\n\t\t\tconst spanAttribute = this.isHorizontal ? 'colspan' : 'rowspan';\n\t\t\tconst cellSpan = parseInt( tableCell.getAttribute( spanAttribute ) || 1 );\n\t\t\tconst cellToMergeSpan = parseInt( cellToMerge.getAttribute( spanAttribute ) || 1 );\n\n\t\t\t// Update table cell span attribute and merge set selection on merged contents.\n\t\t\twriter.setAttribute( spanAttribute, cellSpan + cellToMergeSpan, cellToExpand );\n\t\t\twriter.setSelection( writer.createRangeIn( cellToExpand ) );\n\n\t\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\t\t\tconst table = removedTableCellRow.findAncestor( 'table' );\n\n\t\t\t// Remove empty rows and columns after merging.\n\t\t\tremoveEmptyRowsColumns( table, tableUtils );\n\t\t} );\n\t}\n\n\t/**\n\t * Returns a cell that can be merged with the current cell depending on the command's direction.\n\t *\n\t * @returns {module:engine/model/element~Element|undefined}\n\t * @private\n\t */\n\t_getMergeableCell() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst tableCell = getTableCellsContainingSelection( doc.selection )[ 0 ];\n\n\t\tif ( !tableCell ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\n\t\t// First get the cell on proper direction.\n\t\tconst cellToMerge = this.isHorizontal ?\n\t\t\tgetHorizontalCell( tableCell, this.direction, tableUtils ) :\n\t\t\tgetVerticalCell( tableCell, this.direction );\n\n\t\tif ( !cellToMerge ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If found check if the span perpendicular to merge direction is equal on both cells.\n\t\tconst spanAttribute = this.isHorizontal ? 'rowspan' : 'colspan';\n\t\tconst span = parseInt( tableCell.getAttribute( spanAttribute ) || 1 );\n\n\t\tconst cellToMergeSpan = parseInt( cellToMerge.getAttribute( spanAttribute ) || 1 );\n\n\t\tif ( cellToMergeSpan === span ) {\n\t\t\treturn cellToMerge;\n\t\t}\n\t}\n}\n\n// Returns the cell that can be merged horizontally.\n//\n// @param {module:engine/model/element~Element} tableCell\n// @param {String} direction\n// @returns {module:engine/model/node~Node|null}\nfunction getHorizontalCell( tableCell, direction, tableUtils ) {\n\tconst tableRow = tableCell.parent;\n\tconst table = tableRow.parent;\n\tconst horizontalCell = direction == 'right' ? tableCell.nextSibling : tableCell.previousSibling;\n\tconst hasHeadingColumns = ( table.getAttribute( 'headingColumns' ) || 0 ) > 0;\n\n\tif ( !horizontalCell ) {\n\t\treturn;\n\t}\n\n\t// Sort cells:\n\tconst cellOnLeft = direction == 'right' ? tableCell : horizontalCell;\n\tconst cellOnRight = direction == 'right' ? horizontalCell : tableCell;\n\n\t// Get their column indexes:\n\tconst { column: leftCellColumn } = tableUtils.getCellLocation( cellOnLeft );\n\tconst { column: rightCellColumn } = tableUtils.getCellLocation( cellOnRight );\n\n\tconst leftCellSpan = parseInt( cellOnLeft.getAttribute( 'colspan' ) || 1 );\n\n\tconst isCellOnLeftInHeadingColumn = isHeadingColumnCell( tableUtils, cellOnLeft, table );\n\tconst isCellOnRightInHeadingColumn = isHeadingColumnCell( tableUtils, cellOnRight, table );\n\n\t// We cannot merge heading columns cells with regular cells.\n\tif ( hasHeadingColumns && isCellOnLeftInHeadingColumn != isCellOnRightInHeadingColumn ) {\n\t\treturn;\n\t}\n\n\t// The cell on the right must have index that is distant to the cell on the left by the left cell's width (colspan).\n\tconst cellsAreTouching = leftCellColumn + leftCellSpan === rightCellColumn;\n\n\t// If the right cell's column index is different it means that there are rowspanned cells between them.\n\treturn cellsAreTouching ? horizontalCell : undefined;\n}\n\n// Returns the cell that can be merged vertically.\n//\n// @param {module:engine/model/element~Element} tableCell\n// @param {String} direction\n// @returns {module:engine/model/node~Node|null}\nfunction getVerticalCell( tableCell, direction ) {\n\tconst tableRow = tableCell.parent;\n\tconst table = tableRow.parent;\n\n\tconst rowIndex = table.getChildIndex( tableRow );\n\n\t// Don't search for mergeable cell if direction points out of the table.\n\tif ( ( direction == 'down' && rowIndex === table.childCount - 1 ) || ( direction == 'up' && rowIndex === 0 ) ) {\n\t\treturn;\n\t}\n\n\tconst rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );\n\tconst headingRows = table.getAttribute( 'headingRows' ) || 0;\n\n\tconst isMergeWithBodyCell = direction == 'down' && ( rowIndex + rowspan ) === headingRows;\n\tconst isMergeWithHeadCell = direction == 'up' && rowIndex === headingRows;\n\n\t// Don't search for mergeable cell if direction points out of the current table section.\n\tif ( headingRows && ( isMergeWithBodyCell || isMergeWithHeadCell ) ) {\n\t\treturn;\n\t}\n\n\tconst currentCellRowSpan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );\n\tconst rowOfCellToMerge = direction == 'down' ? rowIndex + currentCellRowSpan : rowIndex;\n\n\tconst tableMap = [ ...new TableWalker( table, { endRow: rowOfCellToMerge } ) ];\n\n\tconst currentCellData = tableMap.find( value => value.cell === tableCell );\n\tconst mergeColumn = currentCellData.column;\n\n\tconst cellToMergeData = tableMap.find( ( { row, cellHeight, column } ) => {\n\t\tif ( column !== mergeColumn ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( direction == 'down' ) {\n\t\t\t// If merging a cell below the mergeRow is already calculated.\n\t\t\treturn row === rowOfCellToMerge;\n\t\t} else {\n\t\t\t// If merging a cell above calculate if it spans to mergeRow.\n\t\t\treturn rowOfCellToMerge === row + cellHeight;\n\t\t}\n\t} );\n\n\treturn cellToMergeData && cellToMergeData.cell;\n}\n\n// Merges two table cells. It will ensure that after merging cells with an empty paragraph, the resulting table cell will only have one\n// paragraph. If one of the merged table cells is empty, the merged table cell will have the contents of the non-empty table cell.\n// If both are empty, the merged table cell will have only one empty paragraph.\n//\n// @param {module:engine/model/element~Element} cellToRemove\n// @param {module:engine/model/element~Element} cellToExpand\n// @param {module:engine/model/writer~Writer} writer\nfunction mergeTableCells( cellToRemove, cellToExpand, writer ) {\n\tif ( !isEmpty( cellToRemove ) ) {\n\t\tif ( isEmpty( cellToExpand ) ) {\n\t\t\twriter.remove( writer.createRangeIn( cellToExpand ) );\n\t\t}\n\n\t\twriter.move( writer.createRangeIn( cellToRemove ), writer.createPositionAt( cellToExpand, 'end' ) );\n\t}\n\n\t// Remove merged table cell.\n\twriter.remove( cellToRemove );\n}\n\n// Checks if the passed table cell contains an empty paragraph.\n//\n// @param {module:engine/model/element~Element} tableCell\n// @returns {Boolean}\nfunction isEmpty( tableCell ) {\n\treturn tableCell.childCount == 1 && tableCell.getChild( 0 ).is( 'element', 'paragraph' ) && tableCell.getChild( 0 ).isEmpty;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/commands/removerowcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\nimport { getRowIndexes, getSelectionAffectedTableCells } from '../utils/selection';\n\n/**\n * The remove row command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'removeTableRow'` editor command.\n *\n * To remove the row containing the selected cell, execute the command:\n *\n *\t\teditor.execute( 'removeTableRow' );\n *\n * @extends module:core/command~Command\n */\nexport default class RemoveRowCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst selectedCells = getSelectionAffectedTableCells( this.editor.model.document.selection );\n\t\tconst firstCell = selectedCells[ 0 ];\n\n\t\tif ( firstCell ) {\n\t\t\tconst table = firstCell.findAncestor( 'table' );\n\t\t\tconst tableRowCount = this.editor.plugins.get( 'TableUtils' ).getRows( table );\n\t\t\tconst lastRowIndex = tableRowCount - 1;\n\n\t\t\tconst selectedRowIndexes = getRowIndexes( selectedCells );\n\n\t\t\tconst areAllRowsSelected = selectedRowIndexes.first === 0 && selectedRowIndexes.last === lastRowIndex;\n\n\t\t\t// Disallow selecting whole table -> delete whole table should be used instead.\n\t\t\tthis.isEnabled = !areAllRowsSelected;\n\t\t} else {\n\t\t\tthis.isEnabled = false;\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst referenceCells = getSelectionAffectedTableCells( model.document.selection );\n\t\tconst removedRowIndexes = getRowIndexes( referenceCells );\n\n\t\tconst firstCell = referenceCells[ 0 ];\n\t\tconst table = firstCell.findAncestor( 'table' );\n\n\t\tconst columnIndexToFocus = this.editor.plugins.get( 'TableUtils' ).getCellLocation( firstCell ).column;\n\n\t\tmodel.change( writer => {\n\t\t\tconst rowsToRemove = removedRowIndexes.last - removedRowIndexes.first + 1;\n\n\t\t\tthis.editor.plugins.get( 'TableUtils' ).removeRows( table, {\n\t\t\t\tat: removedRowIndexes.first,\n\t\t\t\trows: rowsToRemove\n\t\t\t} );\n\n\t\t\tconst cellToFocus = getCellToFocus( table, removedRowIndexes.first, columnIndexToFocus );\n\n\t\t\twriter.setSelection( writer.createPositionAt( cellToFocus, 0 ) );\n\t\t} );\n\t}\n}\n\n// Returns a cell that should be focused before removing the row, belonging to the same column as the currently focused cell.\n// * If the row was not the last one, the cell to focus will be in the row that followed it (before removal).\n// * If the row was the last one, the cell to focus will be in the row that preceded it (before removal).\nfunction getCellToFocus( table, removedRowIndex, columnToFocus ) {\n\tconst row = table.getChild( removedRowIndex ) || table.getChild( table.childCount - 1 );\n\n\t// Default to first table cell.\n\tlet cellToFocus = row.getChild( 0 );\n\tlet column = 0;\n\n\tfor ( const tableCell of row.getChildren() ) {\n\t\tif ( column > columnToFocus ) {\n\t\t\treturn cellToFocus;\n\t\t}\n\n\t\tcellToFocus = tableCell;\n\t\tcolumn += parseInt( tableCell.getAttribute( 'colspan' ) || 1 );\n\t}\n\n\treturn cellToFocus;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/commands/removecolumncommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\nimport TableWalker from '../tablewalker';\nimport { getColumnIndexes, getSelectionAffectedTableCells } from '../utils/selection';\n\n/**\n * The remove column command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'removeTableColumn'` editor command.\n *\n * To remove the column containing the selected cell, execute the command:\n *\n *\t\teditor.execute( 'removeTableColumn' );\n *\n * @extends module:core/command~Command\n */\nexport default class RemoveColumnCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst selectedCells = getSelectionAffectedTableCells( this.editor.model.document.selection );\n\t\tconst firstCell = selectedCells[ 0 ];\n\n\t\tif ( firstCell ) {\n\t\t\tconst table = firstCell.findAncestor( 'table' );\n\t\t\tconst tableColumnCount = this.editor.plugins.get( 'TableUtils' ).getColumns( table );\n\n\t\t\tconst { first, last } = getColumnIndexes( selectedCells );\n\n\t\t\tthis.isEnabled = last - first < ( tableColumnCount - 1 );\n\t\t} else {\n\t\t\tthis.isEnabled = false;\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst [ firstCell, lastCell ] = getBoundaryCells( this.editor.model.document.selection );\n\t\tconst table = firstCell.parent.parent;\n\n\t\t// Cache the table before removing or updating colspans.\n\t\tconst tableMap = [ ...new TableWalker( table ) ];\n\n\t\t// Store column indexes of removed columns.\n\t\tconst removedColumnIndexes = {\n\t\t\tfirst: tableMap.find( value => value.cell === firstCell ).column,\n\t\t\tlast: tableMap.find( value => value.cell === lastCell ).column\n\t\t};\n\n\t\tconst cellToFocus = getCellToFocus( tableMap, firstCell, lastCell, removedColumnIndexes );\n\n\t\tthis.editor.model.change( writer => {\n\t\t\tconst columnsToRemove = removedColumnIndexes.last - removedColumnIndexes.first + 1;\n\n\t\t\tthis.editor.plugins.get( 'TableUtils' ).removeColumns( table, {\n\t\t\t\tat: removedColumnIndexes.first,\n\t\t\t\tcolumns: columnsToRemove\n\t\t\t} );\n\n\t\t\twriter.setSelection( writer.createPositionAt( cellToFocus, 0 ) );\n\t\t} );\n\t}\n}\n\n// Returns a proper table cell to focus after removing a column.\n// - selection is on last table cell it will return previous cell.\nfunction getCellToFocus( tableMap, firstCell, lastCell, removedColumnIndexes ) {\n\tconst colspan = parseInt( lastCell.getAttribute( 'colspan' ) || 1 );\n\n\t// If the table cell is spanned over 2+ columns - it will be truncated so the selection should\n\t// stay in that cell.\n\tif ( colspan > 1 ) {\n\t\treturn lastCell;\n\t}\n\t// Normally, look for the cell in the same row that precedes the first cell to put selection there (\"column on the left\").\n\t// If the deleted column is the first column of the table, there will be no predecessor: use the cell\n\t// from the column that follows then (also in the same row).\n\telse if ( firstCell.previousSibling || lastCell.nextSibling ) {\n\t\treturn lastCell.nextSibling || firstCell.previousSibling;\n\t}\n\t// It can happen that table cells have no siblings in a row, for instance, when there are row spans\n\t// in the table (in the previous row). Then just look for the closest cell that is in a column\n\t// that will not be removed to put the selection there.\n\telse {\n\t\t// Look for any cell in a column that precedes the first removed column.\n\t\tif ( removedColumnIndexes.first ) {\n\t\t\treturn tableMap.reverse().find( ( { column } ) => {\n\t\t\t\treturn column < removedColumnIndexes.first;\n\t\t\t} ).cell;\n\t\t}\n\t\t// If the first removed column is the first column of the table, then\n\t\t// look for any cell that is in a column that follows the last removed column.\n\t\telse {\n\t\t\treturn tableMap.reverse().find( ( { column } ) => {\n\t\t\t\treturn column > removedColumnIndexes.last;\n\t\t\t} ).cell;\n\t\t}\n\t}\n}\n\n// Returns helper object returning the first and the last cell contained in given selection, based on DOM order.\nfunction getBoundaryCells( selection ) {\n\tconst referenceCells = getSelectionAffectedTableCells( selection );\n\tconst firstCell = referenceCells[ 0 ];\n\tconst lastCell = referenceCells.pop();\n\n\tconst returnValue = [ firstCell, lastCell ];\n\n\treturn firstCell.isBefore( lastCell ) ? returnValue : returnValue.reverse();\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/commands/setheaderrowcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\nimport { updateNumericAttribute } from '../utils/common';\nimport { getRowIndexes, getSelectionAffectedTableCells } from '../utils/selection';\nimport { getVerticallyOverlappingCells, splitHorizontally } from '../utils/structure';\n\n/**\n * The header row command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'setTableColumnHeader'` editor command.\n *\n * You can make the row containing the selected cell a [header](https://www.w3.org/TR/html50/tabular-data.html#the-th-element) by executing:\n *\n *\t\teditor.execute( 'setTableRowHeader' );\n *\n * **Note:** All preceding rows will also become headers. If the current row is already a header, executing this command\n * will make it a regular row back again (including the following rows).\n *\n * @extends module:core/command~Command\n */\nexport default class SetHeaderRowCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst selectedCells = getSelectionAffectedTableCells( model.document.selection );\n\t\tconst isInTable = selectedCells.length > 0;\n\n\t\tthis.isEnabled = isInTable;\n\n\t\t/**\n\t\t * Flag indicating whether the command is active. The command is active when the\n\t\t * {@link module:engine/model/selection~Selection} is in a header row.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #value\n\t\t */\n\t\tthis.value = isInTable && selectedCells.every( cell => this._isInHeading( cell, cell.parent.parent ) );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * When the selection is in a non-header row, the command will set the `headingRows` table attribute to cover that row.\n\t *\n\t * When the selection is already in a header row, it will set `headingRows` so the heading section will end before that row.\n\t *\n\t * @fires execute\n\t * @param {Object} options\n\t * @param {Boolean} [options.forceValue] If set, the command will set (`true`) or unset (`false`) the header rows according to\n\t * the `forceValue` parameter instead of the current model state.\n\t */\n\texecute( options = {} ) {\n\t\tif ( options.forceValue === this.value ) {\n\t\t\treturn;\n\t\t}\n\t\tconst model = this.editor.model;\n\t\tconst selectedCells = getSelectionAffectedTableCells( model.document.selection );\n\t\tconst table = selectedCells[ 0 ].findAncestor( 'table' );\n\n\t\tconst { first, last } = getRowIndexes( selectedCells );\n\t\tconst headingRowsToSet = this.value ? first : last + 1;\n\t\tconst currentHeadingRows = table.getAttribute( 'headingRows' ) || 0;\n\n\t\tmodel.change( writer => {\n\t\t\tif ( headingRowsToSet ) {\n\t\t\t\t// Changing heading rows requires to check if any of a heading cell is overlapping vertically the table head.\n\t\t\t\t// Any table cell that has a rowspan attribute > 1 will not exceed the table head so we need to fix it in rows below.\n\t\t\t\tconst startRow = headingRowsToSet > currentHeadingRows ? currentHeadingRows : 0;\n\t\t\t\tconst overlappingCells = getVerticallyOverlappingCells( table, headingRowsToSet, startRow );\n\n\t\t\t\tfor ( const { cell } of overlappingCells ) {\n\t\t\t\t\tsplitHorizontally( cell, headingRowsToSet, writer );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tupdateNumericAttribute( 'headingRows', headingRowsToSet, table, writer, 0 );\n\t\t} );\n\t}\n\n\t/**\n\t * Checks if a table cell is in the heading section.\n\t *\n\t * @param {module:engine/model/element~Element} tableCell\n\t * @param {module:engine/model/element~Element} table\n\t * @returns {Boolean}\n\t * @private\n\t */\n\t_isInHeading( tableCell, table ) {\n\t\tconst headingRows = parseInt( table.getAttribute( 'headingRows' ) || 0 );\n\n\t\treturn !!headingRows && tableCell.parent.index < headingRows;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/commands/setheadercolumncommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\nimport {\n\tisHeadingColumnCell,\n\tupdateNumericAttribute\n} from '../utils/common';\nimport { getColumnIndexes, getSelectionAffectedTableCells } from '../utils/selection';\nimport { getHorizontallyOverlappingCells, splitVertically } from '../utils/structure';\n\n/**\n * The header column command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'setTableColumnHeader'` editor command.\n *\n * You can make the column containing the selected cell a [header](https://www.w3.org/TR/html50/tabular-data.html#the-th-element)\n * by executing:\n *\n *\t\teditor.execute( 'setTableColumnHeader' );\n *\n * **Note:** All preceding columns will also become headers. If the current column is already a header, executing this command\n * will make it a regular column back again (including the following columns).\n *\n * @extends module:core/command~Command\n */\nexport default class SetHeaderColumnCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst selectedCells = getSelectionAffectedTableCells( model.document.selection );\n\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\t\tconst isInTable = selectedCells.length > 0;\n\n\t\tthis.isEnabled = isInTable;\n\n\t\t/**\n\t\t * Flag indicating whether the command is active. The command is active when the\n\t\t * {@link module:engine/model/selection~Selection} is in a header column.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #value\n\t\t */\n\t\tthis.value = isInTable && selectedCells.every( cell => isHeadingColumnCell( tableUtils, cell ) );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * When the selection is in a non-header column, the command will set the `headingColumns` table attribute to cover that column.\n\t *\n\t * When the selection is already in a header column, it will set `headingColumns` so the heading section will end before that column.\n\t *\n\t * @fires execute\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.forceValue] If set, the command will set (`true`) or unset (`false`) the header columns according to\n\t * the `forceValue` parameter instead of the current model state.\n\t */\n\texecute( options = {} ) {\n\t\tif ( options.forceValue === this.value ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst model = this.editor.model;\n\t\tconst selectedCells = getSelectionAffectedTableCells( model.document.selection );\n\t\tconst table = selectedCells[ 0 ].findAncestor( 'table' );\n\n\t\tconst { first, last } = getColumnIndexes( selectedCells );\n\t\tconst headingColumnsToSet = this.value ? first : last + 1;\n\n\t\tmodel.change( writer => {\n\t\t\tif ( headingColumnsToSet ) {\n\t\t\t\t// Changing heading columns requires to check if any of a heading cell is overlapping horizontally the table head.\n\t\t\t\t// Any table cell that has a colspan attribute > 1 will not exceed the table head so we need to fix it in columns before.\n\t\t\t\tconst overlappingCells = getHorizontallyOverlappingCells( table, headingColumnsToSet );\n\n\t\t\t\tfor ( const { cell, column } of overlappingCells ) {\n\t\t\t\t\tsplitVertically( cell, column, headingColumnsToSet, writer );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tupdateNumericAttribute( 'headingColumns', headingColumnsToSet, table, writer, 0 );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableutils\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport TableWalker from './tablewalker';\nimport { createEmptyTableCell, updateNumericAttribute } from './utils/common';\nimport { removeEmptyColumns, removeEmptyRows } from './utils/structure';\n\n/**\n * The table utilities plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableUtils extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableUtils';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tthis.decorate( 'insertColumns' );\n\t\tthis.decorate( 'insertRows' );\n\t}\n\n\t/**\n\t * Returns the table cell location as an object with table row and table column indexes.\n\t *\n\t * For instance, in the table below:\n\t *\n\t *\t\t    0   1   2   3\n\t *\t\t  +---+---+---+---+\n\t *\t\t0 | a     | b | c |\n\t *\t\t  +       +   +---+\n\t *\t\t1 |       |   | d |\n\t *\t\t  +---+---+   +---+\n\t *\t\t2 | e     |   | f |\n\t *\t\t  +---+---+---+---+\n\t *\n\t * the method will return:\n\t *\n\t *\t\tconst cellA = table.getNodeByPath( [ 0, 0 ] );\n\t *\t\teditor.plugins.get( 'TableUtils' ).getCellLocation( cellA );\n\t *\t\t// will return { row: 0, column: 0 }\n\t *\n\t *\t\tconst cellD = table.getNodeByPath( [ 1, 0 ] );\n\t *\t\teditor.plugins.get( 'TableUtils' ).getCellLocation( cellD );\n\t *\t\t// will return { row: 1, column: 3 }\n\t *\n\t * @param {module:engine/model/element~Element} tableCell\n\t * @returns {Object} Returns a `{row, column}` object.\n\t */\n\tgetCellLocation( tableCell ) {\n\t\tconst tableRow = tableCell.parent;\n\t\tconst table = tableRow.parent;\n\n\t\tconst rowIndex = table.getChildIndex( tableRow );\n\n\t\tconst tableWalker = new TableWalker( table, { row: rowIndex } );\n\n\t\tfor ( const { cell, row, column } of tableWalker ) {\n\t\t\tif ( cell === tableCell ) {\n\t\t\t\treturn { row, column };\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates an empty table with a proper structure. The table needs to be inserted into the model,\n\t * for example, by using the {@link module:engine/model/model~Model#insertContent} function.\n\t *\n\t *\t\tmodel.change( ( writer ) => {\n\t *\t\t\t// Create a table of 2 rows and 7 columns:\n\t *\t\t\tconst table = tableUtils.createTable( writer, { rows: 2, columns: 7 } );\n\t *\n\t *\t\t\t// Insert a table to the model at the best position taking the current selection:\n\t *\t\t\tmodel.insertContent( table );\n\t *\t\t}\n\t *\n\t * @param {module:engine/model/writer~Writer} writer The model writer.\n\t * @param {Object} options\n\t * @param {Number} [options.rows=2] The number of rows to create.\n\t * @param {Number} [options.columns=2] The number of columns to create.\n\t * @param {Number} [options.headingRows=0] The number of heading rows.\n\t * @param {Number} [options.headingColumns=0] The number of heading columns.\n\t * @returns {module:engine/model/element~Element} The created table element.\n\t */\n\tcreateTable( writer, options ) {\n\t\tconst table = writer.createElement( 'table' );\n\n\t\tconst rows = parseInt( options.rows ) || 2;\n\t\tconst columns = parseInt( options.columns ) || 2;\n\n\t\tcreateEmptyRows( writer, table, 0, rows, columns );\n\n\t\tif ( options.headingRows ) {\n\t\t\tupdateNumericAttribute( 'headingRows', options.headingRows, table, writer, 0 );\n\t\t}\n\n\t\tif ( options.headingColumns ) {\n\t\t\tupdateNumericAttribute( 'headingColumns', options.headingColumns, table, writer, 0 );\n\t\t}\n\n\t\treturn table;\n\t}\n\n\t/**\n\t * Inserts rows into a table.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).insertRows( table, { at: 1, rows: 2 } );\n\t *\n\t * Assuming the table on the left, the above code will transform it to the table on the right:\n\t *\n\t *\t\trow index\n\t *\t\t  0 +---+---+---+       `at` = 1,      +---+---+---+ 0\n\t *\t\t    | a | b | c |       `rows` = 2,    | a | b | c |\n\t *\t\t  1 +   +---+---+   <-- insert here    +   +---+---+ 1\n\t *\t\t    |   | d | e |                      |   |   |   |\n\t *\t\t  2 +   +---+---+       will give:     +   +---+---+ 2\n\t *\t\t    |   | f | g |                      |   |   |   |\n\t *\t\t  3 +---+---+---+                      +   +---+---+ 3\n\t *\t\t                                       |   | d | e |\n\t *\t\t                                       +   +---+---+ 4\n\t *\t\t                                       +   + f | g |\n\t *\t\t                                       +---+---+---+ 5\n\t *\n\t * @param {module:engine/model/element~Element} table The table model element where the rows will be inserted.\n\t * @param {Object} options\n\t * @param {Number} [options.at=0] The row index at which the rows will be inserted.\n\t * @param {Number} [options.rows=1] The number of rows to insert.\n\t * @param {Boolean|undefined} [options.copyStructureFromAbove] The flag for copying row structure. Note that\n\t * the row structure will not be copied if this option is not provided.\n\t */\n\tinsertRows( table, options = {} ) {\n\t\tconst model = this.editor.model;\n\n\t\tconst insertAt = options.at || 0;\n\t\tconst rowsToInsert = options.rows || 1;\n\t\tconst isCopyStructure = options.copyStructureFromAbove !== undefined;\n\t\tconst copyStructureFrom = options.copyStructureFromAbove ? insertAt - 1 : insertAt;\n\n\t\tconst rows = this.getRows( table );\n\t\tconst columns = this.getColumns( table );\n\n\t\tmodel.change( writer => {\n\t\t\tconst headingRows = table.getAttribute( 'headingRows' ) || 0;\n\n\t\t\t// Inserting rows inside heading section requires to update `headingRows` attribute as the heading section will grow.\n\t\t\tif ( headingRows > insertAt ) {\n\t\t\t\tupdateNumericAttribute( 'headingRows', headingRows + rowsToInsert, table, writer, 0 );\n\t\t\t}\n\n\t\t\t// Inserting at the end or at the beginning of a table doesn't require to calculate anything special.\n\t\t\tif ( !isCopyStructure && ( insertAt === 0 || insertAt === rows ) ) {\n\t\t\t\tcreateEmptyRows( writer, table, insertAt, rowsToInsert, columns );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Iterate over all the rows above the inserted rows in order to check for the row-spanned cells.\n\t\t\tconst walkerEndRow = isCopyStructure ? Math.max( insertAt, copyStructureFrom ) : insertAt;\n\t\t\tconst tableIterator = new TableWalker( table, { endRow: walkerEndRow } );\n\n\t\t\t// Store spans of the reference row to reproduce it's structure. This array is column number indexed.\n\t\t\tconst rowColSpansMap = new Array( columns ).fill( 1 );\n\n\t\t\tfor ( const { row, column, cellHeight, cellWidth, cell } of tableIterator ) {\n\t\t\t\tconst lastCellRow = row + cellHeight - 1;\n\n\t\t\t\tconst isOverlappingInsertedRow = row < insertAt && insertAt <= lastCellRow;\n\t\t\t\tconst isReferenceRow = row <= copyStructureFrom && copyStructureFrom <= lastCellRow;\n\n\t\t\t\t// If the cell is row-spanned and overlaps the inserted row, then reserve space for it in the row map.\n\t\t\t\tif ( isOverlappingInsertedRow ) {\n\t\t\t\t\t// This cell overlaps the inserted rows so we need to expand it further.\n\t\t\t\t\twriter.setAttribute( 'rowspan', cellHeight + rowsToInsert, cell );\n\n\t\t\t\t\t// Mark this cell with negative number to indicate how many cells should be skipped when adding the new cells.\n\t\t\t\t\trowColSpansMap[ column ] = -cellWidth;\n\t\t\t\t}\n\t\t\t\t// Store the colspan from reference row.\n\t\t\t\telse if ( isCopyStructure && isReferenceRow ) {\n\t\t\t\t\trowColSpansMap[ column ] = cellWidth;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( let rowIndex = 0; rowIndex < rowsToInsert; rowIndex++ ) {\n\t\t\t\tconst tableRow = writer.createElement( 'tableRow' );\n\n\t\t\t\twriter.insert( tableRow, table, insertAt );\n\n\t\t\t\tfor ( let cellIndex = 0; cellIndex < rowColSpansMap.length; cellIndex++ ) {\n\t\t\t\t\tconst colspan = rowColSpansMap[ cellIndex ];\n\t\t\t\t\tconst insertPosition = writer.createPositionAt( tableRow, 'end' );\n\n\t\t\t\t\t// Insert the empty cell only if this slot is not row-spanned from any other cell.\n\t\t\t\t\tif ( colspan > 0 ) {\n\t\t\t\t\t\tcreateEmptyTableCell( writer, insertPosition, colspan > 1 ? { colspan } : null );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Skip the col-spanned slots, there won't be any cells.\n\t\t\t\t\tcellIndex += Math.abs( colspan ) - 1;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Inserts columns into a table.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).insertColumns( table, { at: 1, columns: 2 } );\n\t *\n\t * Assuming the table on the left, the above code will transform it to the table on the right:\n\t *\n\t *\t\t0   1   2   3                   0   1   2   3   4   5\n\t *\t\t+---+---+---+                   +---+---+---+---+---+\n\t *\t\t| a     | b |                   | a             | b |\n\t *\t\t+       +---+                   +               +---+\n\t *\t\t|       | c |                   |               | c |\n\t *\t\t+---+---+---+     will give:    +---+---+---+---+---+\n\t *\t\t| d | e | f |                   | d |   |   | e | f |\n\t *\t\t+---+   +---+                   +---+---+---+   +---+\n\t *\t\t| g |   | h |                   | g |   |   |   | h |\n\t *\t\t+---+---+---+                   +---+---+---+---+---+\n\t *\t\t| i         |                   | i                 |\n\t *\t\t+---+---+---+                   +---+---+---+---+---+\n\t *\t\t    ^---- insert here, `at` = 1, `columns` = 2\n\t *\n\t * @param {module:engine/model/element~Element} table The table model element where the columns will be inserted.\n\t * @param {Object} options\n\t * @param {Number} [options.at=0] The column index at which the columns will be inserted.\n\t * @param {Number} [options.columns=1] The number of columns to insert.\n\t */\n\tinsertColumns( table, options = {} ) {\n\t\tconst model = this.editor.model;\n\n\t\tconst insertAt = options.at || 0;\n\t\tconst columnsToInsert = options.columns || 1;\n\n\t\tmodel.change( writer => {\n\t\t\tconst headingColumns = table.getAttribute( 'headingColumns' );\n\n\t\t\t// Inserting columns inside heading section requires to update `headingColumns` attribute as the heading section will grow.\n\t\t\tif ( insertAt < headingColumns ) {\n\t\t\t\twriter.setAttribute( 'headingColumns', headingColumns + columnsToInsert, table );\n\t\t\t}\n\n\t\t\tconst tableColumns = this.getColumns( table );\n\n\t\t\t// Inserting at the end and at the beginning of a table doesn't require to calculate anything special.\n\t\t\tif ( insertAt === 0 || tableColumns === insertAt ) {\n\t\t\t\tfor ( const tableRow of table.getChildren() ) {\n\t\t\t\t\tcreateCells( columnsToInsert, writer, writer.createPositionAt( tableRow, insertAt ? 'end' : 0 ) );\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst tableWalker = new TableWalker( table, { column: insertAt, includeAllSlots: true } );\n\n\t\t\tfor ( const tableSlot of tableWalker ) {\n\t\t\t\tconst { row, cell, cellAnchorColumn, cellAnchorRow, cellWidth, cellHeight } = tableSlot;\n\n\t\t\t\t// When iterating over column the table walker outputs either:\n\t\t\t\t// - cells at given column index (cell \"e\" from method docs),\n\t\t\t\t// - spanned columns (spanned cell from row between cells \"g\" and \"h\" - spanned by \"e\", only if `includeAllSlots: true`),\n\t\t\t\t// - or a cell from the same row which spans over this column (cell \"a\").\n\n\t\t\t\tif ( cellAnchorColumn < insertAt ) {\n\t\t\t\t\t// If cell is anchored in previous column, it is a cell that spans over an inserted column (cell \"a\" & \"i\").\n\t\t\t\t\t// For such cells expand them by a number of columns inserted.\n\t\t\t\t\twriter.setAttribute( 'colspan', cellWidth + columnsToInsert, cell );\n\n\t\t\t\t\t// This cell will overlap cells in rows below so skip them (because of `includeAllSlots` option) - (cell \"a\")\n\t\t\t\t\tconst lastCellRow = cellAnchorRow + cellHeight - 1;\n\n\t\t\t\t\tfor ( let i = row; i <= lastCellRow; i++ ) {\n\t\t\t\t\t\ttableWalker.skipRow( i );\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// It's either cell at this column index or spanned cell by a row-spanned cell from row above.\n\t\t\t\t\t// In table above it's cell \"e\" and a spanned position from row below (empty cell between cells \"g\" and \"h\")\n\t\t\t\t\tcreateCells( columnsToInsert, writer, tableSlot.getPositionBefore() );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Removes rows from the given `table`.\n\t *\n\t * This method re-calculates the table geometry including `rowspan` attribute of table cells overlapping removed rows\n\t * and table headings values.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).removeRows( table, { at: 1, rows: 2 } );\n\t *\n\t * Executing the above code in the context of the table on the left will transform its structure as presented on the right:\n\t *\n\t *\t\trow index\n\t *\t\t    ┌───┬───┬───┐        `at` = 1        ┌───┬───┬───┐\n\t *\t\t  0 │ a │ b │ c │        `rows` = 2      │ a │ b │ c │ 0\n\t *\t\t    │   ├───┼───┤                        │   ├───┼───┤\n\t *\t\t  1 │   │ d │ e │  <-- remove from here  │   │ d │ g │ 1\n\t *\t\t    │   │   ├───┤        will give:      ├───┼───┼───┤\n\t *\t\t  2 │   │   │ f │                        │ h │ i │ j │ 2\n\t *\t\t    │   │   ├───┤                        └───┴───┴───┘\n\t *\t\t  3 │   │   │ g │\n\t *\t\t    ├───┼───┼───┤\n\t *\t\t  4 │ h │ i │ j │\n\t *\t\t    └───┴───┴───┘\n\t *\n\t * @param {module:engine/model/element~Element} table\n\t * @param {Object} options\n\t * @param {Number} options.at The row index at which the removing rows will start.\n\t * @param {Number} [options.rows=1] The number of rows to remove.\n\t */\n\tremoveRows( table, options ) {\n\t\tconst model = this.editor.model;\n\n\t\tconst rowsToRemove = options.rows || 1;\n\t\tconst first = options.at;\n\t\tconst last = first + rowsToRemove - 1;\n\n\t\tmodel.change( writer => {\n\t\t\t// Removing rows from the table require that most calculations to be done prior to changing table structure.\n\t\t\t// Preparations must be done in the same enqueueChange callback to use the current table structure.\n\n\t\t\t// 1. Preparation - get row-spanned cells that have to be modified after removing rows.\n\t\t\tconst { cellsToMove, cellsToTrim } = getCellsToMoveAndTrimOnRemoveRow( table, first, last );\n\n\t\t\t// 2. Execution\n\n\t\t\t// 2a. Move cells from removed rows that extends over a removed section - must be done before removing rows.\n\t\t\t// This will fill any gaps in a rows below that previously were empty because of row-spanned cells.\n\t\t\tif ( cellsToMove.size ) {\n\t\t\t\tconst rowAfterRemovedSection = last + 1;\n\t\t\t\tmoveCellsToRow( table, rowAfterRemovedSection, cellsToMove, writer );\n\t\t\t}\n\n\t\t\t// 2b. Remove all required rows.\n\t\t\tfor ( let i = last; i >= first; i-- ) {\n\t\t\t\twriter.remove( table.getChild( i ) );\n\t\t\t}\n\n\t\t\t// 2c. Update cells from rows above that overlap removed section. Similar to step 2 but does not involve moving cells.\n\t\t\tfor ( const { rowspan, cell } of cellsToTrim ) {\n\t\t\t\tupdateNumericAttribute( 'rowspan', rowspan, cell, writer );\n\t\t\t}\n\n\t\t\t// 2d. Adjust heading rows if removed rows were in a heading section.\n\t\t\tupdateHeadingRows( table, first, last, writer );\n\n\t\t\t// 2e. Remove empty columns (without anchored cells) if there are any.\n\t\t\tif ( !removeEmptyColumns( table, this ) ) {\n\t\t\t\t// If there wasn't any empty columns then we still need to check if this wasn't called\n\t\t\t\t// because of cleaning empty rows and we only removed one of them.\n\t\t\t\tremoveEmptyRows( table, this );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Removes columns from the given `table`.\n\t *\n\t * This method re-calculates the table geometry including the `colspan` attribute of table cells overlapping removed columns\n\t * and table headings values.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).removeColumns( table, { at: 1, columns: 2 } );\n\t *\n\t * Executing the above code in the context of the table on the left will transform its structure as presented on the right:\n\t *\n\t *\t\t  0   1   2   3   4                       0   1   2\n\t *\t\t┌───────────────┬───┐                   ┌───────┬───┐\n\t *\t\t│ a             │ b │                   │ a     │ b │\n\t *\t\t│               ├───┤                   │       ├───┤\n\t *\t\t│               │ c │                   │       │ c │\n\t *\t\t├───┬───┬───┬───┼───┤     will give:    ├───┬───┼───┤\n\t *\t\t│ d │ e │ f │ g │ h │                   │ d │ g │ h │\n\t *\t\t├───┼───┼───┤   ├───┤                   ├───┤   ├───┤\n\t *\t\t│ i │ j │ k │   │ l │                   │ i │   │ l │\n\t *\t\t├───┴───┴───┴───┴───┤                   ├───┴───┴───┤\n\t *\t\t│ m                 │                   │ m         │\n\t *\t\t└───────────────────┘                   └───────────┘\n\t *\t\t      ^---- remove from here, `at` = 1, `columns` = 2\n\t *\n\t * @param {module:engine/model/element~Element} table\n\t * @param {Object} options\n\t * @param {Number} options.at The row index at which the removing columns will start.\n\t * @param {Number} [options.columns=1] The number of columns to remove.\n\t */\n\tremoveColumns( table, options ) {\n\t\tconst model = this.editor.model;\n\t\tconst first = options.at;\n\t\tconst columnsToRemove = options.columns || 1;\n\t\tconst last = options.at + columnsToRemove - 1;\n\n\t\tmodel.change( writer => {\n\t\t\tadjustHeadingColumns( table, { first, last }, writer );\n\n\t\t\tfor ( let removedColumnIndex = last; removedColumnIndex >= first; removedColumnIndex-- ) {\n\t\t\t\tfor ( const { cell, column, cellWidth } of [ ...new TableWalker( table ) ] ) {\n\t\t\t\t\t// If colspaned cell overlaps removed column decrease its span.\n\t\t\t\t\tif ( column <= removedColumnIndex && cellWidth > 1 && column + cellWidth > removedColumnIndex ) {\n\t\t\t\t\t\tupdateNumericAttribute( 'colspan', cellWidth - 1, cell, writer );\n\t\t\t\t\t} else if ( column === removedColumnIndex ) {\n\t\t\t\t\t\t// The cell in removed column has colspan of 1.\n\t\t\t\t\t\twriter.remove( cell );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove empty rows that could appear after removing columns.\n\t\t\tif ( !removeEmptyRows( table, this ) ) {\n\t\t\t\t// If there wasn't any empty rows then we still need to check if this wasn't called\n\t\t\t\t// because of cleaning empty columns and we only removed one of them.\n\t\t\t\tremoveEmptyColumns( table, this );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Divides a table cell vertically into several ones.\n\t *\n\t * The cell will be visually split into more cells by updating colspans of other cells in a column\n\t * and inserting cells (columns) after that cell.\n\t *\n\t * In the table below, if cell \"a\" is split into 3 cells:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | b | c |\n\t *\t\t+---+---+---+\n\t *\t\t| d | e | f |\n\t *\t\t+---+---+---+\n\t *\n\t * it will result in the table below:\n\t *\n\t *\t\t+---+---+---+---+---+\n\t *\t\t| a |   |   | b | c |\n\t *\t\t+---+---+---+---+---+\n\t *\t\t| d         | e | f |\n\t *\t\t+---+---+---+---+---+\n\t *\n\t * So cell \"d\" will get its `colspan` updated to `3` and 2 cells will be added (2 columns will be created).\n\t *\n\t * Splitting a cell that already has a `colspan` attribute set will distribute the cell `colspan` evenly and the remainder\n\t * will be left to the original cell:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a         |\n\t *\t\t+---+---+---+\n\t *\t\t| b | c | d |\n\t *\t\t+---+---+---+\n\t *\n\t * Splitting cell \"a\" with `colspan=3` into 2 cells will create 1 cell with a `colspan=a` and cell \"a\" that will have `colspan=2`:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a     |   |\n\t *\t\t+---+---+---+\n\t *\t\t| b | c | d |\n\t *\t\t+---+---+---+\n\t *\n\t * @param {module:engine/model/element~Element} tableCell\n\t * @param {Number} numberOfCells\n\t */\n\tsplitCellVertically( tableCell, numberOfCells = 2 ) {\n\t\tconst model = this.editor.model;\n\t\tconst tableRow = tableCell.parent;\n\t\tconst table = tableRow.parent;\n\n\t\tconst rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );\n\t\tconst colspan = parseInt( tableCell.getAttribute( 'colspan' ) || 1 );\n\n\t\tmodel.change( writer => {\n\t\t\t// First check - the cell spans over multiple rows so before doing anything else just split this cell.\n\t\t\tif ( colspan > 1 ) {\n\t\t\t\t// Get spans of new (inserted) cells and span to update of split cell.\n\t\t\t\tconst { newCellsSpan, updatedSpan } = breakSpanEvenly( colspan, numberOfCells );\n\n\t\t\t\tupdateNumericAttribute( 'colspan', updatedSpan, tableCell, writer );\n\n\t\t\t\t// Each inserted cell will have the same attributes:\n\t\t\t\tconst newCellsAttributes = {};\n\n\t\t\t\t// Do not store default value in the model.\n\t\t\t\tif ( newCellsSpan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.colspan = newCellsSpan;\n\t\t\t\t}\n\n\t\t\t\t// Copy rowspan of split cell.\n\t\t\t\tif ( rowspan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.rowspan = rowspan;\n\t\t\t\t}\n\n\t\t\t\tconst cellsToInsert = colspan > numberOfCells ? numberOfCells - 1 : colspan - 1;\n\t\t\t\tcreateCells( cellsToInsert, writer, writer.createPositionAfter( tableCell ), newCellsAttributes );\n\t\t\t}\n\n\t\t\t// Second check - the cell has colspan of 1 or we need to create more cells then the currently one spans over.\n\t\t\tif ( colspan < numberOfCells ) {\n\t\t\t\tconst cellsToInsert = numberOfCells - colspan;\n\n\t\t\t\t// First step: expand cells on the same column as split cell.\n\t\t\t\tconst tableMap = [ ...new TableWalker( table ) ];\n\n\t\t\t\t// Get the column index of split cell.\n\t\t\t\tconst { column: splitCellColumn } = tableMap.find( ( { cell } ) => cell === tableCell );\n\n\t\t\t\t// Find cells which needs to be expanded vertically - those on the same column or those that spans over split cell's column.\n\t\t\t\tconst cellsToUpdate = tableMap.filter( ( { cell, cellWidth, column } ) => {\n\t\t\t\t\tconst isOnSameColumn = cell !== tableCell && column === splitCellColumn;\n\t\t\t\t\tconst spansOverColumn = ( column < splitCellColumn && column + cellWidth > splitCellColumn );\n\n\t\t\t\t\treturn isOnSameColumn || spansOverColumn;\n\t\t\t\t} );\n\n\t\t\t\t// Expand cells vertically.\n\t\t\t\tfor ( const { cell, cellWidth } of cellsToUpdate ) {\n\t\t\t\t\twriter.setAttribute( 'colspan', cellWidth + cellsToInsert, cell );\n\t\t\t\t}\n\n\t\t\t\t// Second step: create columns after split cell.\n\n\t\t\t\t// Each inserted cell will have the same attributes:\n\t\t\t\tconst newCellsAttributes = {};\n\n\t\t\t\t// Do not store default value in the model.\n\n\t\t\t\t// Copy rowspan of split cell.\n\t\t\t\tif ( rowspan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.rowspan = rowspan;\n\t\t\t\t}\n\n\t\t\t\tcreateCells( cellsToInsert, writer, writer.createPositionAfter( tableCell ), newCellsAttributes );\n\n\t\t\t\tconst headingColumns = table.getAttribute( 'headingColumns' ) || 0;\n\n\t\t\t\t// Update heading section if split cell is in heading section.\n\t\t\t\tif ( headingColumns > splitCellColumn ) {\n\t\t\t\t\tupdateNumericAttribute( 'headingColumns', headingColumns + cellsToInsert, table, writer );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Divides a table cell horizontally into several ones.\n\t *\n\t * The cell will be visually split into more cells by updating rowspans of other cells in the row and inserting rows with a single cell\n\t * below.\n\t *\n\t * If in the table below cell \"b\" is split into 3 cells:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | b | c |\n\t *\t\t+---+---+---+\n\t *\t\t| d | e | f |\n\t *\t\t+---+---+---+\n\t *\n\t * It will result in the table below:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | b | c |\n\t *\t\t+   +---+   +\n\t *\t\t|   |   |   |\n\t *\t\t+   +---+   +\n\t *\t\t|   |   |   |\n\t *\t\t+---+---+---+\n\t *\t\t| d | e | f |\n\t *\t\t+---+---+---+\n\t *\n\t * So cells \"a\" and \"b\" will get their `rowspan` updated to `3` and 2 rows with a single cell will be added.\n\t *\n\t * Splitting a cell that already has a `rowspan` attribute set will distribute the cell `rowspan` evenly and the remainder\n\t * will be left to the original cell:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | b | c |\n\t *\t\t+   +---+---+\n\t *\t\t|   | d | e |\n\t *\t\t+   +---+---+\n\t *\t\t|   | f | g |\n\t *\t\t+   +---+---+\n\t *\t\t|   | h | i |\n\t *\t\t+---+---+---+\n\t *\n\t * Splitting cell \"a\" with `rowspan=4` into 3 cells will create 2 cells with a `rowspan=1` and cell \"a\" will have `rowspan=2`:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | b | c |\n\t *\t\t+   +---+---+\n\t *\t\t|   | d | e |\n\t *\t\t+---+---+---+\n\t *\t\t|   | f | g |\n\t *\t\t+---+---+---+\n\t *\t\t|   | h | i |\n\t *\t\t+---+---+---+\n\t *\n\t * @param {module:engine/model/element~Element} tableCell\n\t * @param {Number} numberOfCells\n\t */\n\tsplitCellHorizontally( tableCell, numberOfCells = 2 ) {\n\t\tconst model = this.editor.model;\n\n\t\tconst tableRow = tableCell.parent;\n\t\tconst table = tableRow.parent;\n\t\tconst splitCellRow = table.getChildIndex( tableRow );\n\n\t\tconst rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );\n\t\tconst colspan = parseInt( tableCell.getAttribute( 'colspan' ) || 1 );\n\n\t\tmodel.change( writer => {\n\t\t\t// First check - the cell spans over multiple rows so before doing anything else just split this cell.\n\t\t\tif ( rowspan > 1 ) {\n\t\t\t\t// Cache table map before updating table.\n\t\t\t\tconst tableMap = [ ...new TableWalker( table, {\n\t\t\t\t\tstartRow: splitCellRow,\n\t\t\t\t\tendRow: splitCellRow + rowspan - 1,\n\t\t\t\t\tincludeAllSlots: true\n\t\t\t\t} ) ];\n\n\t\t\t\t// Get spans of new (inserted) cells and span to update of split cell.\n\t\t\t\tconst { newCellsSpan, updatedSpan } = breakSpanEvenly( rowspan, numberOfCells );\n\n\t\t\t\tupdateNumericAttribute( 'rowspan', updatedSpan, tableCell, writer );\n\n\t\t\t\tconst { column: cellColumn } = tableMap.find( ( { cell } ) => cell === tableCell );\n\n\t\t\t\t// Each inserted cell will have the same attributes:\n\t\t\t\tconst newCellsAttributes = {};\n\n\t\t\t\t// Do not store default value in the model.\n\t\t\t\tif ( newCellsSpan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.rowspan = newCellsSpan;\n\t\t\t\t}\n\n\t\t\t\t// Copy colspan of split cell.\n\t\t\t\tif ( colspan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.colspan = colspan;\n\t\t\t\t}\n\n\t\t\t\tfor ( const tableSlot of tableMap ) {\n\t\t\t\t\tconst { column, row } = tableSlot;\n\n\t\t\t\t\t// As both newly created cells and the split cell might have rowspan,\n\t\t\t\t\t// the insertion of new cells must go to appropriate rows:\n\t\t\t\t\t//\n\t\t\t\t\t// 1. It's a row after split cell + it's height.\n\t\t\t\t\tconst isAfterSplitCell = row >= splitCellRow + updatedSpan;\n\t\t\t\t\t// 2. Is on the same column.\n\t\t\t\t\tconst isOnSameColumn = column === cellColumn;\n\t\t\t\t\t// 3. And it's row index is after previous cell height.\n\t\t\t\t\tconst isInEvenlySplitRow = ( row + splitCellRow + updatedSpan ) % newCellsSpan === 0;\n\n\t\t\t\t\tif ( isAfterSplitCell && isOnSameColumn && isInEvenlySplitRow ) {\n\t\t\t\t\t\tcreateCells( 1, writer, tableSlot.getPositionBefore(), newCellsAttributes );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Second check - the cell has rowspan of 1 or we need to create more cells than the current cell spans over.\n\t\t\tif ( rowspan < numberOfCells ) {\n\t\t\t\t// We already split the cell in check one so here we split to the remaining number of cells only.\n\t\t\t\tconst cellsToInsert = numberOfCells - rowspan;\n\n\t\t\t\t// This check is needed since we need to check if there are any cells from previous rows than spans over this cell's row.\n\t\t\t\tconst tableMap = [ ...new TableWalker( table, { startRow: 0, endRow: splitCellRow } ) ];\n\n\t\t\t\t// First step: expand cells.\n\t\t\t\tfor ( const { cell, cellHeight, row } of tableMap ) {\n\t\t\t\t\t// Expand rowspan of cells that are either:\n\t\t\t\t\t// - on the same row as current cell,\n\t\t\t\t\t// - or are below split cell row and overlaps that row.\n\t\t\t\t\tif ( cell !== tableCell && row + cellHeight > splitCellRow ) {\n\t\t\t\t\t\tconst rowspanToSet = cellHeight + cellsToInsert;\n\n\t\t\t\t\t\twriter.setAttribute( 'rowspan', rowspanToSet, cell );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Second step: create rows with single cell below split cell.\n\t\t\t\tconst newCellsAttributes = {};\n\n\t\t\t\t// Copy colspan of split cell.\n\t\t\t\tif ( colspan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.colspan = colspan;\n\t\t\t\t}\n\n\t\t\t\tcreateEmptyRows( writer, table, splitCellRow + 1, cellsToInsert, 1, newCellsAttributes );\n\n\t\t\t\t// Update heading section if split cell is in heading section.\n\t\t\t\tconst headingRows = table.getAttribute( 'headingRows' ) || 0;\n\n\t\t\t\tif ( headingRows > splitCellRow ) {\n\t\t\t\t\tupdateNumericAttribute( 'headingRows', headingRows + cellsToInsert, table, writer );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Returns the number of columns for a given table.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).getColumns( table );\n\t *\n\t * @param {module:engine/model/element~Element} table The table to analyze.\n\t * @returns {Number}\n\t */\n\tgetColumns( table ) {\n\t\t// Analyze first row only as all the rows should have the same width.\n\t\tconst row = table.getChild( 0 );\n\n\t\treturn [ ...row.getChildren() ].reduce( ( columns, row ) => {\n\t\t\tconst columnWidth = parseInt( row.getAttribute( 'colspan' ) || 1 );\n\n\t\t\treturn columns + columnWidth;\n\t\t}, 0 );\n\t}\n\n\t/**\n\t * Returns the number of rows for a given table.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).getRows( table );\n\t *\n\t * @param {module:engine/model/element~Element} table The table to analyze.\n\t * @returns {Number}\n\t */\n\tgetRows( table ) {\n\t\t// Simple row counting, not including rowspan due to #6427.\n\t\treturn table.childCount;\n\t}\n}\n\n// Creates empty rows at the given index in an existing table.\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/element~Element} table\n// @param {Number} insertAt The row index of row insertion.\n// @param {Number} rows The number of rows to create.\n// @param {Number} tableCellToInsert The number of cells to insert in each row.\nfunction createEmptyRows( writer, table, insertAt, rows, tableCellToInsert, attributes = {} ) {\n\tfor ( let i = 0; i < rows; i++ ) {\n\t\tconst tableRow = writer.createElement( 'tableRow' );\n\n\t\twriter.insert( tableRow, table, insertAt );\n\n\t\tcreateCells( tableCellToInsert, writer, writer.createPositionAt( tableRow, 'end' ), attributes );\n\t}\n}\n\n// Creates cells at a given position.\n//\n// @param {Number} columns The number of columns to create\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/position~Position} insertPosition\nfunction createCells( cells, writer, insertPosition, attributes = {} ) {\n\tfor ( let i = 0; i < cells; i++ ) {\n\t\tcreateEmptyTableCell( writer, insertPosition, attributes );\n\t}\n}\n\n// Evenly distributes the span of a cell to a number of provided cells.\n// The resulting spans will always be integer values.\n//\n// For instance breaking a span of 7 into 3 cells will return:\n//\n//\t\t{ newCellsSpan: 2, updatedSpan: 3 }\n//\n// as two cells will have a span of 2 and the remainder will go the first cell so its span will change to 3.\n//\n// @param {Number} span The span value do break.\n// @param {Number} numberOfCells The number of resulting spans.\n// @returns {{newCellsSpan: Number, updatedSpan: Number}}\nfunction breakSpanEvenly( span, numberOfCells ) {\n\tif ( span < numberOfCells ) {\n\t\treturn { newCellsSpan: 1, updatedSpan: 1 };\n\t}\n\n\tconst newCellsSpan = Math.floor( span / numberOfCells );\n\tconst updatedSpan = ( span - newCellsSpan * numberOfCells ) + newCellsSpan;\n\n\treturn { newCellsSpan, updatedSpan };\n}\n\n// Updates heading columns attribute if removing a row from head section.\nfunction adjustHeadingColumns( table, removedColumnIndexes, writer ) {\n\tconst headingColumns = table.getAttribute( 'headingColumns' ) || 0;\n\n\tif ( headingColumns && removedColumnIndexes.first < headingColumns ) {\n\t\tconst headingsRemoved = Math.min( headingColumns - 1 /* Other numbers are 0-based */, removedColumnIndexes.last ) -\n\t\t\tremovedColumnIndexes.first + 1;\n\n\t\twriter.setAttribute( 'headingColumns', headingColumns - headingsRemoved, table );\n\t}\n}\n\n// Calculates a new heading rows value for removing rows from heading section.\nfunction updateHeadingRows( table, first, last, writer ) {\n\tconst headingRows = table.getAttribute( 'headingRows' ) || 0;\n\n\tif ( first < headingRows ) {\n\t\tconst newRows = last < headingRows ? headingRows - ( last - first + 1 ) : first;\n\n\t\tupdateNumericAttribute( 'headingRows', newRows, table, writer, 0 );\n\t}\n}\n\n// Finds cells that will be:\n// - trimmed - Cells that are \"above\" removed rows sections and overlap the removed section - their rowspan must be trimmed.\n// - moved - Cells from removed rows section might stick out of. These cells are moved to the next row after a removed section.\n//\n// Sample table with overlapping & sticking out cells:\n//\n//      +----+----+----+----+----+\n//      | 00 | 01 | 02 | 03 | 04 |\n//      +----+    +    +    +    +\n//      | 10 |    |    |    |    |\n//      +----+----+    +    +    +\n//      | 20 | 21 |    |    |    | <-- removed row\n//      +    +    +----+    +    +\n//      |    |    | 32 |    |    | <-- removed row\n//      +----+    +    +----+    +\n//      | 40 |    |    | 43 |    |\n//      +----+----+----+----+----+\n//\n// In a table above:\n// - cells to trim: '02', '03' & '04'.\n// - cells to move: '21' & '32'.\nfunction getCellsToMoveAndTrimOnRemoveRow( table, first, last ) {\n\tconst cellsToMove = new Map();\n\tconst cellsToTrim = [];\n\n\tfor ( const { row, column, cellHeight, cell } of new TableWalker( table, { endRow: last } ) ) {\n\t\tconst lastRowOfCell = row + cellHeight - 1;\n\n\t\tconst isCellStickingOutFromRemovedRows = row >= first && row <= last && lastRowOfCell > last;\n\n\t\tif ( isCellStickingOutFromRemovedRows ) {\n\t\t\tconst rowspanInRemovedSection = last - row + 1;\n\t\t\tconst rowSpanToSet = cellHeight - rowspanInRemovedSection;\n\n\t\t\tcellsToMove.set( column, {\n\t\t\t\tcell,\n\t\t\t\trowspan: rowSpanToSet\n\t\t\t} );\n\t\t}\n\n\t\tconst isCellOverlappingRemovedRows = row < first && lastRowOfCell >= first;\n\n\t\tif ( isCellOverlappingRemovedRows ) {\n\t\t\tlet rowspanAdjustment;\n\n\t\t\t// Cell fully covers removed section - trim it by removed rows count.\n\t\t\tif ( lastRowOfCell >= last ) {\n\t\t\t\trowspanAdjustment = last - first + 1;\n\t\t\t}\n\t\t\t// Cell partially overlaps removed section - calculate cell's span that is in removed section.\n\t\t\telse {\n\t\t\t\trowspanAdjustment = lastRowOfCell - first + 1;\n\t\t\t}\n\n\t\t\tcellsToTrim.push( {\n\t\t\t\tcell,\n\t\t\t\trowspan: cellHeight - rowspanAdjustment\n\t\t\t} );\n\t\t}\n\t}\n\treturn { cellsToMove, cellsToTrim };\n}\n\nfunction moveCellsToRow( table, targetRowIndex, cellsToMove, writer ) {\n\tconst tableWalker = new TableWalker( table, {\n\t\tincludeAllSlots: true,\n\t\trow: targetRowIndex\n\t} );\n\n\tconst tableRowMap = [ ...tableWalker ];\n\tconst row = table.getChild( targetRowIndex );\n\n\tlet previousCell;\n\n\tfor ( const { column, cell, isAnchor } of tableRowMap ) {\n\t\tif ( cellsToMove.has( column ) ) {\n\t\t\tconst { cell: cellToMove, rowspan } = cellsToMove.get( column );\n\n\t\t\tconst targetPosition = previousCell ?\n\t\t\t\twriter.createPositionAfter( previousCell ) :\n\t\t\t\twriter.createPositionAt( row, 0 );\n\n\t\t\twriter.move( writer.createRangeOn( cellToMove ), targetPosition );\n\t\t\tupdateNumericAttribute( 'rowspan', rowspan, cellToMove, writer );\n\n\t\t\tpreviousCell = cellToMove;\n\t\t} else if ( isAnchor ) {\n\t\t\t// If cell is spanned then `cell` holds reference to overlapping cell. See ckeditor/ckeditor5#6502.\n\t\t\tpreviousCell = cell;\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/commands/mergecellscommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport TableUtils from '../tableutils';\nimport { getSelectedTableCells, isSelectionRectangular } from '../utils/selection';\nimport { updateNumericAttribute } from '../utils/common';\nimport { removeEmptyRowsColumns } from '../utils/structure';\n\n/**\n * The merge cells command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'mergeTableCells'` editor command.\n *\n * For example, to merge selected table cells:\n *\n *\t\teditor.execute( 'mergeTableCells' );\n *\n * @extends module:core/command~Command\n */\nexport default class MergeCellsCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst selectedTableCells = getSelectedTableCells( this.editor.model.document.selection );\n\t\tthis.isEnabled = isSelectionRectangular( selectedTableCells, this.editor.plugins.get( TableUtils ) );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst tableUtils = this.editor.plugins.get( TableUtils );\n\n\t\tmodel.change( writer => {\n\t\t\tconst selectedTableCells = getSelectedTableCells( model.document.selection );\n\n\t\t\t// All cells will be merged into the first one.\n\t\t\tconst firstTableCell = selectedTableCells.shift();\n\n\t\t\t// Update target cell dimensions.\n\t\t\tconst { mergeWidth, mergeHeight } = getMergeDimensions( firstTableCell, selectedTableCells, tableUtils );\n\t\t\tupdateNumericAttribute( 'colspan', mergeWidth, firstTableCell, writer );\n\t\t\tupdateNumericAttribute( 'rowspan', mergeHeight, firstTableCell, writer );\n\n\t\t\tfor ( const tableCell of selectedTableCells ) {\n\t\t\t\tmergeTableCells( tableCell, firstTableCell, writer );\n\t\t\t}\n\n\t\t\tconst table = firstTableCell.findAncestor( 'table' );\n\n\t\t\t// Remove rows and columns that become empty (have no anchored cells).\n\t\t\tremoveEmptyRowsColumns( table, tableUtils );\n\n\t\t\twriter.setSelection( firstTableCell, 'in' );\n\t\t} );\n\t}\n}\n\n// Merges two table cells. It will ensure that after merging cells with empty paragraphs the resulting table cell will only have one\n// paragraph. If one of the merged table cells is empty, the merged table cell will have contents of the non-empty table cell.\n// If both are empty, the merged table cell will have only one empty paragraph.\n//\n// @param {module:engine/model/element~Element} cellBeingMerged\n// @param {module:engine/model/element~Element} targetCell\n// @param {module:engine/model/writer~Writer} writer\nfunction mergeTableCells( cellBeingMerged, targetCell, writer ) {\n\tif ( !isEmpty( cellBeingMerged ) ) {\n\t\tif ( isEmpty( targetCell ) ) {\n\t\t\twriter.remove( writer.createRangeIn( targetCell ) );\n\t\t}\n\n\t\twriter.move( writer.createRangeIn( cellBeingMerged ), writer.createPositionAt( targetCell, 'end' ) );\n\t}\n\n\t// Remove merged table cell.\n\twriter.remove( cellBeingMerged );\n}\n\n// Checks if the passed table cell contains an empty paragraph.\n//\n// @param {module:engine/model/element~Element} tableCell\n// @returns {Boolean}\nfunction isEmpty( tableCell ) {\n\treturn tableCell.childCount == 1 && tableCell.getChild( 0 ).is( 'element', 'paragraph' ) && tableCell.getChild( 0 ).isEmpty;\n}\n\nfunction getMergeDimensions( firstTableCell, selectedTableCells, tableUtils ) {\n\tlet maxWidthOffset = 0;\n\tlet maxHeightOffset = 0;\n\n\tfor ( const tableCell of selectedTableCells ) {\n\t\tconst { row, column } = tableUtils.getCellLocation( tableCell );\n\n\t\tmaxWidthOffset = getMaxOffset( tableCell, column, maxWidthOffset, 'colspan' );\n\t\tmaxHeightOffset = getMaxOffset( tableCell, row, maxHeightOffset, 'rowspan' );\n\t}\n\n\t// Update table cell span attribute and merge set selection on a merged contents.\n\tconst { row: firstCellRow, column: firstCellColumn } = tableUtils.getCellLocation( firstTableCell );\n\n\tconst mergeWidth = maxWidthOffset - firstCellColumn;\n\tconst mergeHeight = maxHeightOffset - firstCellRow;\n\n\treturn { mergeWidth, mergeHeight };\n}\n\nfunction getMaxOffset( tableCell, start, currentMaxOffset, which ) {\n\tconst dimensionValue = parseInt( tableCell.getAttribute( which ) || 1 );\n\n\treturn Math.max( currentMaxOffset, start + dimensionValue );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/commands/selectrowcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\nimport { getRowIndexes, getSelectionAffectedTableCells } from '../utils/selection';\n\n/**\n * The select row command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'selectTableRow'` editor command.\n *\n * To select the rows containing the selected cells, execute the command:\n *\n *\t\teditor.execute( 'selectTableRow' );\n *\n * @extends module:core/command~Command\n */\nexport default class SelectRowCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst selectedCells = getSelectionAffectedTableCells( this.editor.model.document.selection );\n\n\t\tthis.isEnabled = selectedCells.length > 0;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst referenceCells = getSelectionAffectedTableCells( model.document.selection );\n\t\tconst rowIndexes = getRowIndexes( referenceCells );\n\n\t\tconst table = referenceCells[ 0 ].findAncestor( 'table' );\n\t\tconst rangesToSelect = [];\n\n\t\tfor ( let rowIndex = rowIndexes.first; rowIndex <= rowIndexes.last; rowIndex++ ) {\n\t\t\tfor ( const cell of table.getChild( rowIndex ).getChildren() ) {\n\t\t\t\trangesToSelect.push( model.createRangeOn( cell ) );\n\t\t\t}\n\t\t}\n\n\t\tmodel.change( writer => {\n\t\t\twriter.setSelection( rangesToSelect );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/commands/selectcolumncommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\nimport TableWalker from '../tablewalker';\nimport { getSelectionAffectedTableCells } from '../utils/selection';\n\n/**\n * The select column command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'selectTableColumn'` editor command.\n *\n * To select the columns containing the selected cells, execute the command:\n *\n *\t\teditor.execute( 'selectTableColumn' );\n *\n * @extends module:core/command~Command\n */\nexport default class SelectColumnCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst selectedCells = getSelectionAffectedTableCells( this.editor.model.document.selection );\n\n\t\tthis.isEnabled = selectedCells.length > 0;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst referenceCells = getSelectionAffectedTableCells( model.document.selection );\n\t\tconst firstCell = referenceCells[ 0 ];\n\t\tconst lastCell = referenceCells.pop();\n\t\tconst table = firstCell.findAncestor( 'table' );\n\n\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\t\tconst startLocation = tableUtils.getCellLocation( firstCell );\n\t\tconst endLocation = tableUtils.getCellLocation( lastCell );\n\n\t\tconst startColumn = Math.min( startLocation.column, endLocation.column );\n\t\tconst endColumn = Math.max( startLocation.column, endLocation.column );\n\n\t\tconst rangesToSelect = [];\n\n\t\tfor ( const cellInfo of new TableWalker( table, { startColumn, endColumn } ) ) {\n\t\t\trangesToSelect.push( model.createRangeOn( cellInfo.cell ) );\n\t\t}\n\n\t\tmodel.change( writer => {\n\t\t\twriter.setSelection( rangesToSelect );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/converters/table-layout-post-fixer\n */\n\nimport TableWalker from './../tablewalker';\nimport { createEmptyTableCell, updateNumericAttribute } from '../utils/common';\n\n/**\n * Injects a table layout post-fixer into the model.\n *\n * The role of the table layout post-fixer is to ensure that the table rows have the correct structure\n * after a {@link module:engine/model/model~Model#change `change()`} block was executed.\n *\n * The correct structure means that:\n *\n * * All table rows have the same size.\n * * None of the table cells extend vertically beyond their section (either header or body).\n * * A table cell has always at least one element as a child.\n *\n * If the table structure is not correct, the post-fixer will automatically correct it in two steps:\n *\n * 1. It will clip table cells that extend beyond their section.\n * 2. It will add empty table cells to the rows that are narrower than the widest table row.\n *\n * ## Clipping overlapping table cells\n *\n * Such situation may occur when pasting a table (or a part of a table) to the editor from external sources.\n *\n * For example, see the following table which has a cell (FOO) with the rowspan attribute (2):\n *\n *\t\t<table headingRows=\"1\">\n *\t\t\t<tableRow>\n *\t\t\t\t<tableCell rowspan=\"2\"><paragraph>FOO</paragraph></tableCell>\n *\t\t\t\t<tableCell colspan=\"2\"><paragraph>BAR</paragraph></tableCell>\n *\t\t\t</tableRow>\n *\t\t\t<tableRow>\n *\t\t\t\t<tableCell><paragraph>BAZ</paragraph></tableCell>\n *\t\t\t\t<tableCell><paragraph>XYZ</paragraph></tableCell>\n *\t\t\t</tableRow>\n *\t\t</table>\n *\n * It will be rendered in the view as:\n *\n *\t\t<table>\n *\t\t\t<thead>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td rowspan=\"2\">FOO</td>\n *\t\t\t\t\t<td colspan=\"2\">BAR</td>\n *\t\t\t\t</tr>\n *\t\t\t</thead>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>BAZ</td>\n *\t\t\t\t\t<td>XYZ</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n *\n * In the above example the table will be rendered as a table with two rows: one in the header and second one in the body.\n * The table cell (FOO) cannot span over multiple rows as it would extend from the header to the body section.\n * The `rowspan` attribute must be changed to (1). The value (1) is the default value of the `rowspan` attribute\n * so the `rowspan` attribute will be removed from the model.\n *\n * The table cell with BAZ in the content will be in the first column of the table.\n *\n * ## Adding missing table cells\n *\n * The table post-fixer will insert empty table cells to equalize table row sizes (the number of columns).\n * The size of a table row is calculated by counting column spans of table cells, both horizontal (from the same row) and\n * vertical (from the rows above).\n *\n * In the above example, the table row in the body section of the table is narrower then the row from the header: it has two cells\n * with the default colspan (1). The header row has one cell with colspan (1) and the second with colspan (2).\n * The table cell (FOO) does not extend beyond the head section (and as such will be fixed in the first step of this post-fixer).\n * The post-fixer will add a missing table cell to the row in the body section of the table.\n *\n * The table from the above example will be fixed and rendered to the view as below:\n *\n *\t\t<table>\n *\t\t\t<thead>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td rowspan=\"2\">FOO</td>\n *\t\t\t\t\t<td colspan=\"2\">BAR</td>\n *\t\t\t\t</tr>\n *\t\t\t</thead>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>BAZ</td>\n *\t\t\t\t\t<td>XYZ</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n *\n * ## Collaboration and undo - Expectations vs post-fixer results\n *\n * The table post-fixer only ensures proper structure without a deeper analysis of the nature of the change. As such, it might lead\n * to a structure which was not intended by the user. In particular, it will also fix undo steps (in conjunction with collaboration)\n * in which the editor content might not return to the original state.\n *\n * This will usually happen when one or more users change the size of the table.\n *\n * As an example see the table below:\n *\n *\t\t<table>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>11</td>\n *\t\t\t\t\t<td>12</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>21</td>\n *\t\t\t\t\t<td>22</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n *\n * and the user actions:\n *\n * 1. Both users have a table with two rows and two columns.\n * 2. User A adds a column at the end of the table. This will insert empty table cells to two rows.\n * 3. User B adds a row at the end of the table. This will insert a row with two empty table cells.\n * 4. Both users will have a table as below:\n *\n *\n *\t\t<table>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>11</td>\n *\t\t\t\t\t<td>12</td>\n *\t\t\t\t\t<td>(empty, inserted by A)</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>21</td>\n *\t\t\t\t\t<td>22</td>\n *\t\t\t\t\t<td>(empty, inserted by A)</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n *\n * The last row is shorter then others so the table post-fixer will add an empty row to the last row:\n *\n *\t\t<table>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>11</td>\n *\t\t\t\t\t<td>12</td>\n *\t\t\t\t\t<td>(empty, inserted by A)</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>21</td>\n *\t\t\t\t\t<td>22</td>\n *\t\t\t\t\t<td>(empty, inserted by A)</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by the post-fixer)</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n *\n * Unfortunately undo does not know the nature of the changes and depending on which user applies the post-fixer changes, undoing them\n * might lead to a broken table. If User B undoes inserting the column to the table, the undo engine will undo only the operations of\n * inserting empty cells to rows from the initial table state (row 1 and 2) but the cell in the post-fixed row will remain:\n *\n *\t\t<table>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>11</td>\n *\t\t\t\t\t<td>12</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>21</td>\n *\t\t\t\t\t<td>22</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by a post-fixer)</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n *\n * After undo, the table post-fixer will detect that two rows are shorter than others and will fix the table to:\n *\n *\t\t<table>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>11</td>\n *\t\t\t\t\t<td>12</td>\n *\t\t\t\t\t<td>(empty, inserted by a post-fixer after undo)</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>21</td>\n *\t\t\t\t\t<td>22</td>\n *\t\t\t\t\t<td>(empty, inserted by a post-fixer after undo)</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by a post-fixer)</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n * @param {module:engine/model/model~Model} model\n */\nexport default function injectTableLayoutPostFixer( model ) {\n\tmodel.document.registerPostFixer( writer => tableLayoutPostFixer( writer, model ) );\n}\n\n// The table layout post-fixer.\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/model~Model} model\nfunction tableLayoutPostFixer( writer, model ) {\n\tconst changes = model.document.differ.getChanges();\n\n\tlet wasFixed = false;\n\n\t// Do not analyze the same table more then once - may happen for multiple changes in the same table.\n\tconst analyzedTables = new Set();\n\n\tfor ( const entry of changes ) {\n\t\tlet table;\n\n\t\tif ( entry.name == 'table' && entry.type == 'insert' ) {\n\t\t\ttable = entry.position.nodeAfter;\n\t\t}\n\n\t\t// Fix table on adding/removing table cells and rows.\n\t\tif ( entry.name == 'tableRow' || entry.name == 'tableCell' ) {\n\t\t\ttable = entry.position.findAncestor( 'table' );\n\t\t}\n\n\t\t// Fix table on any table's attribute change - including attributes of table cells.\n\t\tif ( isTableAttributeEntry( entry ) ) {\n\t\t\ttable = entry.range.start.findAncestor( 'table' );\n\t\t}\n\n\t\tif ( table && !analyzedTables.has( table ) ) {\n\t\t\t// Step 1: correct rowspans of table cells if necessary.\n\t\t\t// The wasFixed flag should be true if any of tables in batch was fixed - might be more then one.\n\t\t\twasFixed = fixTableCellsRowspan( table, writer ) || wasFixed;\n\t\t\t// Step 2: fix table rows sizes.\n\t\t\twasFixed = fixTableRowsSizes( table, writer ) || wasFixed;\n\n\t\t\tanalyzedTables.add( table );\n\t\t}\n\t}\n\n\treturn wasFixed;\n}\n\n// Fixes the invalid value of the `rowspan` attribute because a table cell cannot vertically extend beyond the table section it belongs to.\n//\n// @param {module:engine/model/element~Element} table\n// @param {module:engine/model/writer~Writer} writer\n// @returns {Boolean} Returns `true` if the table was fixed.\nfunction fixTableCellsRowspan( table, writer ) {\n\tlet wasFixed = false;\n\n\tconst cellsToTrim = findCellsToTrim( table );\n\n\tif ( cellsToTrim.length ) {\n\t\t// @if CK_DEBUG_TABLE // console.log( `Post-fixing table: trimming cells row-spans (${ cellsToTrim.length }).` );\n\n\t\twasFixed = true;\n\n\t\tfor ( const data of cellsToTrim ) {\n\t\t\tupdateNumericAttribute( 'rowspan', data.rowspan, data.cell, writer, 1 );\n\t\t}\n\t}\n\n\treturn wasFixed;\n}\n\n// Makes all table rows in a table the same size.\n//\n// @param {module:engine/model/element~Element} table\n// @param {module:engine/model/writer~Writer} writer\n// @returns {Boolean} Returns `true` if the table was fixed.\nfunction fixTableRowsSizes( table, writer ) {\n\tlet wasFixed = false;\n\n\tconst rowsLengths = getRowsLengths( table );\n\tconst rowsToRemove = [];\n\n\t// Find empty rows.\n\tfor ( const [ rowIndex, size ] of rowsLengths.entries() ) {\n\t\tif ( !size ) {\n\t\t\trowsToRemove.push( rowIndex );\n\t\t}\n\t}\n\n\t// Remove empty rows.\n\tif ( rowsToRemove.length ) {\n\t\t// @if CK_DEBUG_TABLE // console.log( `Post-fixing table: remove empty rows (${ rowsToRemove.length }).` );\n\n\t\twasFixed = true;\n\n\t\tfor ( const rowIndex of rowsToRemove.reverse() ) {\n\t\t\twriter.remove( table.getChild( rowIndex ) );\n\t\t\trowsLengths.splice( rowIndex, 1 );\n\t\t}\n\t}\n\n\t// Verify if all the rows have the same number of columns.\n\tconst tableSize = rowsLengths[ 0 ];\n\tconst isValid = rowsLengths.every( length => length === tableSize );\n\n\tif ( !isValid ) {\n\t\t// @if CK_DEBUG_TABLE // console.log( 'Post-fixing table: adding missing cells.' );\n\n\t\t// Find the maximum number of columns.\n\t\tconst maxColumns = rowsLengths.reduce( ( prev, current ) => current > prev ? current : prev, 0 );\n\n\t\tfor ( const [ rowIndex, size ] of rowsLengths.entries() ) {\n\t\t\tconst columnsToInsert = maxColumns - size;\n\n\t\t\tif ( columnsToInsert ) {\n\t\t\t\tfor ( let i = 0; i < columnsToInsert; i++ ) {\n\t\t\t\t\tcreateEmptyTableCell( writer, writer.createPositionAt( table.getChild( rowIndex ), 'end' ) );\n\t\t\t\t}\n\n\t\t\t\twasFixed = true;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn wasFixed;\n}\n\n// Searches for table cells that extend beyond the table section to which they belong to. It will return an array of objects\n// that stores table cells to be trimmed and the correct value of the `rowspan` attribute to set.\n//\n// @param {module:engine/model/element~Element} table\n// @returns {Array.<{{cell, rowspan}}>}\nfunction findCellsToTrim( table ) {\n\tconst headingRows = parseInt( table.getAttribute( 'headingRows' ) || 0 );\n\tconst maxRows = table.childCount;\n\n\tconst cellsToTrim = [];\n\n\tfor ( const { row, cell, cellHeight } of new TableWalker( table ) ) {\n\t\t// Skip cells that do not expand over its row.\n\t\tif ( cellHeight < 2 ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst isInHeader = row < headingRows;\n\n\t\t// Row limit is either end of header section or whole table as table body is after the header.\n\t\tconst rowLimit = isInHeader ? headingRows : maxRows;\n\n\t\t// If table cell expands over its limit reduce it height to proper value.\n\t\tif ( row + cellHeight > rowLimit ) {\n\t\t\tconst newRowspan = rowLimit - row;\n\n\t\t\tcellsToTrim.push( { cell, rowspan: newRowspan } );\n\t\t}\n\t}\n\n\treturn cellsToTrim;\n}\n\n// Returns an array with lengths of rows assigned to the corresponding row index.\n//\n// @param {module:engine/model/element~Element} table\n// @returns {Array.<Number>}\nfunction getRowsLengths( table ) {\n\t// TableWalker will not provide items for the empty rows, we need to pre-fill this array.\n\tconst lengths = new Array( table.childCount ).fill( 0 );\n\n\tfor ( const { row } of new TableWalker( table, { includeAllSlots: true } ) ) {\n\t\tlengths[ row ]++;\n\t}\n\n\treturn lengths;\n}\n\n// Checks if the differ entry for an attribute change is one of the table's attributes.\n//\n// @param entry\n// @returns {Boolean}\nfunction isTableAttributeEntry( entry ) {\n\tconst isAttributeType = entry.type === 'attribute';\n\tconst key = entry.attributeKey;\n\n\treturn isAttributeType && ( key === 'headingRows' || key === 'colspan' || key === 'rowspan' );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/converters/table-cell-paragraph-post-fixer\n */\n\n/**\n * Injects a table cell post-fixer into the model which inserts a `paragraph` element into empty table cells.\n *\n * A table cell must contain at least one block element as a child. An empty table cell will have an empty `paragraph` as a child.\n *\n *\t\t<table>\n *\t\t\t<tableRow>\n *\t\t\t\t<tableCell></tableCell>\n *\t\t\t</tableRow>\n *\t\t</table>\n *\n * Will be fixed to:\n *\n *\t\t<table>\n *\t\t\t<tableRow>\n *\t\t\t\t<tableCell><paragraph></paragraph></tableCell>\n *\t\t\t</tableRow>\n *\t\t</table>\n *\n * @param {module:engine/model/model~Model} model\n */\nexport default function injectTableCellParagraphPostFixer( model ) {\n\tmodel.document.registerPostFixer( writer => tableCellContentsPostFixer( writer, model ) );\n}\n\n// The table cell contents post-fixer.\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/model~Model} model\nfunction tableCellContentsPostFixer( writer, model ) {\n\tconst changes = model.document.differ.getChanges();\n\n\tlet wasFixed = false;\n\n\tfor ( const entry of changes ) {\n\t\tif ( entry.type == 'insert' && entry.name == 'table' ) {\n\t\t\twasFixed = fixTable( entry.position.nodeAfter, writer ) || wasFixed;\n\t\t}\n\n\t\tif ( entry.type == 'insert' && entry.name == 'tableRow' ) {\n\t\t\twasFixed = fixTableRow( entry.position.nodeAfter, writer ) || wasFixed;\n\t\t}\n\n\t\tif ( entry.type == 'insert' && entry.name == 'tableCell' ) {\n\t\t\twasFixed = fixTableCellContent( entry.position.nodeAfter, writer ) || wasFixed;\n\t\t}\n\n\t\tif ( checkTableCellChange( entry ) ) {\n\t\t\twasFixed = fixTableCellContent( entry.position.parent, writer ) || wasFixed;\n\t\t}\n\t}\n\n\treturn wasFixed;\n}\n\n// Fixes all table cells in a table.\n//\n// @param {module:engine/model/element~Element} table\n// @param {module:engine/model/writer~Writer} writer\nfunction fixTable( table, writer ) {\n\tlet wasFixed = false;\n\n\tfor ( const row of table.getChildren() ) {\n\t\twasFixed = fixTableRow( row, writer ) || wasFixed;\n\t}\n\n\treturn wasFixed;\n}\n\n// Fixes all table cells in a table row.\n//\n// @param {module:engine/model/element~Element} tableRow\n// @param {module:engine/model/writer~Writer} writer\nfunction fixTableRow( tableRow, writer ) {\n\tlet wasFixed = false;\n\n\tfor ( const tableCell of tableRow.getChildren() ) {\n\t\twasFixed = fixTableCellContent( tableCell, writer ) || wasFixed;\n\t}\n\n\treturn wasFixed;\n}\n\n// Fixes all table cell content by:\n// - Adding a paragraph to a table cell without any child.\n// - Wrapping direct $text in a `<paragraph>`.\n//\n// @param {module:engine/model/element~Element} table\n// @param {module:engine/model/writer~Writer} writer\n// @returns {Boolean}\nfunction fixTableCellContent( tableCell, writer ) {\n\t// Insert paragraph to an empty table cell.\n\tif ( tableCell.childCount == 0 ) {\n\t\t// @if CK_DEBUG_TABLE // console.log( 'Post-fixing table: insert paragraph in empty cell.' );\n\n\t\twriter.insertElement( 'paragraph', tableCell );\n\n\t\treturn true;\n\t}\n\n\t// Check table cell children for directly placed text nodes.\n\t// Temporary solution. See https://github.com/ckeditor/ckeditor5/issues/1464.\n\tconst textNodes = Array.from( tableCell.getChildren() ).filter( child => child.is( '$text' ) );\n\n\t// @if CK_DEBUG_TABLE // textNodes.length && console.log( 'Post-fixing table: wrap cell content with paragraph.' );\n\n\tfor ( const child of textNodes ) {\n\t\twriter.wrap( writer.createRangeOn( child ), 'paragraph' );\n\t}\n\n\t// Return true when there were text nodes to fix.\n\treturn !!textNodes.length;\n}\n\n// Checks if a differ change should fix the table cell. This happens on:\n// - Removing content from the table cell (i.e. `tableCell` can be left empty).\n// - Adding a text node directly into a table cell.\n//\n// @param {Object} differ change entry\n// @returns {Boolean}\nfunction checkTableCellChange( entry ) {\n\tif ( !entry.position || !entry.position.parent.is( 'element', 'tableCell' ) ) {\n\t\treturn false;\n\t}\n\n\treturn entry.type == 'insert' && entry.name == '$text' || entry.type == 'remove';\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/converters/table-cell-refresh-post-fixer\n */\n\nimport { isSingleParagraphWithoutAttributes } from './downcast';\n\n/**\n * Injects a table cell post-fixer into the model which marks the table cell in the differ to have it re-rendered.\n *\n * Model `paragraph` inside a table cell can be rendered as `<span>` or `<p>`. It is rendered as `<span>` if this is the only block\n * element in that table cell and it does not have any attributes. It is rendered as `<p>` otherwise.\n *\n * When table cell content changes, for example a second `paragraph` element is added, we need to ensure that the first `paragraph` is\n * re-rendered so it changes from `<span>` to `<p>`. The easiest way to do it is to re-render the entire table cell.\n *\n * @param {module:engine/model/model~Model} model\n * @param {module:engine/conversion/mapper~Mapper} mapper\n */\nexport default function injectTableCellRefreshPostFixer( model, mapper ) {\n\tmodel.document.registerPostFixer( () => tableCellRefreshPostFixer( model.document.differ, mapper ) );\n}\n\nfunction tableCellRefreshPostFixer( differ, mapper ) {\n\t// Stores cells to be refreshed, so the table cell will be refreshed once for multiple changes.\n\n\t// 1. Gather all changes inside table cell.\n\tconst cellsToCheck = new Set();\n\n\tfor ( const change of differ.getChanges() ) {\n\t\tconst parent = change.type == 'attribute' ? change.range.start.parent : change.position.parent;\n\n\t\tif ( parent.is( 'element', 'tableCell' ) ) {\n\t\t\tcellsToCheck.add( parent );\n\t\t}\n\t}\n\n\t// @if CK_DEBUG_TABLE // console.log( `Post-fixing table: Checking table cell to refresh (${ cellsToCheck.size }).` );\n\t// @if CK_DEBUG_TABLE // let paragraphsRefreshed = 0;\n\n\tfor ( const tableCell of cellsToCheck.values() ) {\n\t\tfor ( const paragraph of [ ...tableCell.getChildren() ].filter( child => shouldRefresh( child, mapper ) ) ) {\n\t\t\t// @if CK_DEBUG_TABLE // console.log( `Post-fixing table: refreshing paragraph in table cell (${++paragraphsRefreshed}).` );\n\t\t\tdiffer.refreshItem( paragraph );\n\t\t}\n\t}\n\n\t// Always return false to prevent the refresh post-fixer from re-running on the same set of changes and going into an infinite loop.\n\t// This \"post-fixer\" does not change the model structure so there shouldn't be need to run other post-fixers again.\n\t// See https://github.com/ckeditor/ckeditor5/issues/1936 & https://github.com/ckeditor/ckeditor5/issues/8200.\n\treturn false;\n}\n\n// Check if given model element needs refreshing.\n//\n// @param {module:engine/model/element~Element} modelElement\n// @param {module:engine/conversion/mapper~Mapper} mapper\n// @returns {Boolean}\nfunction shouldRefresh( child, mapper ) {\n\tif ( !child.is( 'element', 'paragraph' ) ) {\n\t\treturn false;\n\t}\n\n\tconst viewElement = mapper.toViewElement( child );\n\n\tif ( !viewElement ) {\n\t\treturn false;\n\t}\n\n\treturn isSingleParagraphWithoutAttributes( child ) !== viewElement.is( 'element', 'span' );\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/converters/table-heading-rows-refresh-post-fixer\n */\n\n/**\n * Injects a table post-fixer into the model which marks the table in the differ to have it re-rendered.\n *\n * Table heading rows are represented in the model by a `headingRows` attribute. However, in the view, it's represented as separate\n * sections of the table (`<thead>` or `<tbody>`) and changing `headingRows` attribute requires moving table rows between two sections.\n * This causes problems with structural changes in a table (like adding and removing rows) thus atomic converters cannot be used.\n *\n * When table `headingRows` attribute changes, the entire table is re-rendered.\n *\n * @param {module:engine/model/model~Model} model\n */\nexport default function injectTableHeadingRowsRefreshPostFixer( model ) {\n\tmodel.document.registerPostFixer( () => tableHeadingRowsRefreshPostFixer( model ) );\n}\n\nfunction tableHeadingRowsRefreshPostFixer( model ) {\n\tconst differ = model.document.differ;\n\n\t// Stores tables to be refreshed so the table will be refreshed once for multiple changes.\n\tconst tablesToRefresh = new Set();\n\n\tfor ( const change of differ.getChanges() ) {\n\t\tif ( change.type != 'attribute' ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst element = change.range.start.nodeAfter;\n\n\t\tif ( element && element.is( 'element', 'table' ) && change.attributeKey == 'headingRows' ) {\n\t\t\ttablesToRefresh.add( element );\n\t\t}\n\t}\n\n\tif ( tablesToRefresh.size ) {\n\t\t// @if CK_DEBUG_TABLE // console.log( `Post-fixing table: refreshing heading rows (${ tablesToRefresh.size }).` );\n\n\t\tfor ( const table of tablesToRefresh.values() ) {\n\t\t\t// Should be handled by a `triggerBy` configuration. See: https://github.com/ckeditor/ckeditor5/issues/8138.\n\t\t\tdiffer.refreshItem( table );\n\t\t}\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport upcastTable, { skipEmptyTableRow } from './converters/upcasttable';\nimport {\n\tconvertParagraphInTableCell,\n\tdowncastInsertCell,\n\tdowncastInsertRow,\n\tdowncastInsertTable,\n\tdowncastRemoveRow,\n\tdowncastTableHeadingColumnsChange\n} from './converters/downcast';\n\nimport InsertTableCommand from './commands/inserttablecommand';\nimport InsertRowCommand from './commands/insertrowcommand';\nimport InsertColumnCommand from './commands/insertcolumncommand';\nimport SplitCellCommand from './commands/splitcellcommand';\nimport MergeCellCommand from './commands/mergecellcommand';\nimport RemoveRowCommand from './commands/removerowcommand';\nimport RemoveColumnCommand from './commands/removecolumncommand';\nimport SetHeaderRowCommand from './commands/setheaderrowcommand';\nimport SetHeaderColumnCommand from './commands/setheadercolumncommand';\nimport MergeCellsCommand from './commands/mergecellscommand';\nimport SelectRowCommand from './commands/selectrowcommand';\nimport SelectColumnCommand from './commands/selectcolumncommand';\nimport TableUtils from '../src/tableutils';\n\nimport injectTableLayoutPostFixer from './converters/table-layout-post-fixer';\nimport injectTableCellParagraphPostFixer from './converters/table-cell-paragraph-post-fixer';\nimport injectTableCellRefreshPostFixer from './converters/table-cell-refresh-post-fixer';\nimport injectTableHeadingRowsRefreshPostFixer from './converters/table-heading-rows-refresh-post-fixer';\n\nimport '../theme/tableediting.css';\n\n/**\n * The table editing feature.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst schema = model.schema;\n\t\tconst conversion = editor.conversion;\n\n\t\tschema.register( 'table', {\n\t\t\tallowWhere: '$block',\n\t\t\tallowAttributes: [ 'headingRows', 'headingColumns' ],\n\t\t\tisObject: true,\n\t\t\tisBlock: true\n\t\t} );\n\n\t\tschema.register( 'tableRow', {\n\t\t\tallowIn: 'table',\n\t\t\tisLimit: true\n\t\t} );\n\n\t\tschema.register( 'tableCell', {\n\t\t\tallowIn: 'tableRow',\n\t\t\tallowAttributes: [ 'colspan', 'rowspan' ],\n\t\t\tisLimit: true,\n\t\t\tisSelectable: true\n\t\t} );\n\n\t\t// Allow all $block content inside a table cell.\n\t\tschema.extend( '$block', { allowIn: 'tableCell' } );\n\n\t\t// Disallow a table in a table.\n\t\tschema.addChildCheck( ( context, childDefinition ) => {\n\t\t\tif ( childDefinition.name == 'table' && Array.from( context.getNames() ).includes( 'table' ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} );\n\n\t\t// Table conversion.\n\t\tconversion.for( 'upcast' ).add( upcastTable() );\n\n\t\tconversion.for( 'editingDowncast' ).add( downcastInsertTable( { asWidget: true } ) );\n\t\tconversion.for( 'dataDowncast' ).add( downcastInsertTable() );\n\n\t\t// Table row conversion.\n\t\tconversion.for( 'upcast' ).elementToElement( { model: 'tableRow', view: 'tr' } );\n\t\tconversion.for( 'upcast' ).add( skipEmptyTableRow() );\n\n\t\tconversion.for( 'editingDowncast' ).add( downcastInsertRow() );\n\t\tconversion.for( 'editingDowncast' ).add( downcastRemoveRow() );\n\n\t\t// Table cell conversion.\n\t\tconversion.for( 'upcast' ).elementToElement( { model: 'tableCell', view: 'td' } );\n\t\tconversion.for( 'upcast' ).elementToElement( { model: 'tableCell', view: 'th' } );\n\n\t\tconversion.for( 'editingDowncast' ).add( downcastInsertCell() );\n\n\t\t// Duplicates code - needed to properly refresh paragraph inside a table cell.\n\t\teditor.conversion.for( 'editingDowncast' ).elementToElement( {\n\t\t\tmodel: 'paragraph',\n\t\t\tview: convertParagraphInTableCell,\n\t\t\tconverterPriority: 'high'\n\t\t} );\n\n\t\t// Table attributes conversion.\n\t\tconversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );\n\t\tconversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );\n\n\t\t// Table heading columns conversion (a change of heading rows requires a reconversion of the whole table).\n\t\tconversion.for( 'editingDowncast' ).add( downcastTableHeadingColumnsChange() );\n\n\t\t// Define all the commands.\n\t\teditor.commands.add( 'insertTable', new InsertTableCommand( editor ) );\n\t\teditor.commands.add( 'insertTableRowAbove', new InsertRowCommand( editor, { order: 'above' } ) );\n\t\teditor.commands.add( 'insertTableRowBelow', new InsertRowCommand( editor, { order: 'below' } ) );\n\t\teditor.commands.add( 'insertTableColumnLeft', new InsertColumnCommand( editor, { order: 'left' } ) );\n\t\teditor.commands.add( 'insertTableColumnRight', new InsertColumnCommand( editor, { order: 'right' } ) );\n\n\t\teditor.commands.add( 'removeTableRow', new RemoveRowCommand( editor ) );\n\t\teditor.commands.add( 'removeTableColumn', new RemoveColumnCommand( editor ) );\n\n\t\teditor.commands.add( 'splitTableCellVertically', new SplitCellCommand( editor, { direction: 'vertically' } ) );\n\t\teditor.commands.add( 'splitTableCellHorizontally', new SplitCellCommand( editor, { direction: 'horizontally' } ) );\n\n\t\teditor.commands.add( 'mergeTableCells', new MergeCellsCommand( editor ) );\n\n\t\teditor.commands.add( 'mergeTableCellRight', new MergeCellCommand( editor, { direction: 'right' } ) );\n\t\teditor.commands.add( 'mergeTableCellLeft', new MergeCellCommand( editor, { direction: 'left' } ) );\n\t\teditor.commands.add( 'mergeTableCellDown', new MergeCellCommand( editor, { direction: 'down' } ) );\n\t\teditor.commands.add( 'mergeTableCellUp', new MergeCellCommand( editor, { direction: 'up' } ) );\n\n\t\teditor.commands.add( 'setTableColumnHeader', new SetHeaderColumnCommand( editor ) );\n\t\teditor.commands.add( 'setTableRowHeader', new SetHeaderRowCommand( editor ) );\n\n\t\teditor.commands.add( 'selectTableRow', new SelectRowCommand( editor ) );\n\t\teditor.commands.add( 'selectTableColumn', new SelectColumnCommand( editor ) );\n\n\t\tinjectTableHeadingRowsRefreshPostFixer( model );\n\t\tinjectTableLayoutPostFixer( model );\n\t\tinjectTableCellRefreshPostFixer( model, editor.editing.mapper );\n\t\tinjectTableCellParagraphPostFixer( model );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableUtils ];\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/dropdown/button/splitbuttonview\n */\n\nimport View from '../../view';\nimport ButtonView from '../../button/buttonview';\n\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\n\nimport dropdownArrowIcon from '../../../theme/icons/dropdown-arrow.svg';\n\nimport '../../../theme/components/dropdown/splitbutton.css';\n\n/**\n * The split button view class.\n *\n *\t\tconst view = new SplitButtonView();\n *\n *\t\tview.set( {\n *\t\t\tlabel: 'A button',\n *\t\t\tkeystroke: 'Ctrl+B',\n *\t\t\ttooltip: true\n *\t\t} );\n *\n *\t\tview.render();\n *\n *\t\tdocument.body.append( view.element );\n *\n * Also see the {@link module:ui/dropdown/utils~createDropdown `createDropdown()` util}.\n *\n * @implements module:ui/dropdown/button/dropdownbutton~DropdownButton\n * @extends module:ui/view~View\n */\nexport default class SplitButtonView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t// Implement the Button interface.\n\t\tthis.set( 'icon' );\n\t\tthis.set( 'isEnabled', true );\n\t\tthis.set( 'isOn', false );\n\t\tthis.set( 'isToggleable', false );\n\t\tthis.set( 'isVisible', true );\n\t\tthis.set( 'keystroke' );\n\t\tthis.set( 'label' );\n\t\tthis.set( 'tabindex', -1 );\n\t\tthis.set( 'tooltip' );\n\t\tthis.set( 'tooltipPosition', 's' );\n\t\tthis.set( 'type', 'button' );\n\t\tthis.set( 'withText', false );\n\n\t\t/**\n\t\t * Collection of the child views inside of the split button {@link #element}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\n\t\t/**\n\t\t * A main button of split button.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.actionView = this._createActionView();\n\n\t\t/**\n\t\t * A secondary button of split button that opens dropdown.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.arrowView = this._createArrowView();\n\n\t\t/**\n\t\t * Instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}. It manages\n\t\t * keystrokes of the split button:\n\t\t *\n\t\t * * <kbd>▶</kbd> moves focus to arrow view when action view is focused,\n\t\t * * <kbd>◀</kbd> moves focus to action view when arrow view is focused.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * Tracks information about DOM focus in the dropdown.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-splitbutton',\n\t\t\t\t\tbind.if( 'isVisible', 'ck-hidden', value => !value ),\n\t\t\t\t\tthis.arrowView.bindTemplate.if( 'isOn', 'ck-splitbutton_open' )\n\t\t\t\t]\n\t\t\t},\n\n\t\t\tchildren: this.children\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.children.add( this.actionView );\n\t\tthis.children.add( this.arrowView );\n\n\t\tthis.focusTracker.add( this.actionView.element );\n\t\tthis.focusTracker.add( this.arrowView.element );\n\n\t\tthis.keystrokes.listenTo( this.element );\n\n\t\t// Overrides toolbar focus cycling behavior.\n\t\tthis.keystrokes.set( 'arrowright', ( evt, cancel ) => {\n\t\t\tif ( this.focusTracker.focusedElement === this.actionView.element ) {\n\t\t\t\tthis.arrowView.focus();\n\n\t\t\t\tcancel();\n\t\t\t}\n\t\t} );\n\n\t\t// Overrides toolbar focus cycling behavior.\n\t\tthis.keystrokes.set( 'arrowleft', ( evt, cancel ) => {\n\t\t\tif ( this.focusTracker.focusedElement === this.arrowView.element ) {\n\t\t\t\tthis.actionView.focus();\n\n\t\t\t\tcancel();\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Focuses the {@link #actionView#element} of the action part of split button.\n\t */\n\tfocus() {\n\t\tthis.actionView.focus();\n\t}\n\n\t/**\n\t * Creates a {@link module:ui/button/buttonview~ButtonView} instance as {@link #actionView} and binds it with main split button\n\t * attributes.\n\t *\n\t * @private\n\t * @returns {module:ui/button/buttonview~ButtonView}\n\t */\n\t_createActionView() {\n\t\tconst actionView = new ButtonView();\n\n\t\tactionView.bind(\n\t\t\t'icon',\n\t\t\t'isEnabled',\n\t\t\t'isOn',\n\t\t\t'isToggleable',\n\t\t\t'keystroke',\n\t\t\t'label',\n\t\t\t'tabindex',\n\t\t\t'tooltip',\n\t\t\t'tooltipPosition',\n\t\t\t'type',\n\t\t\t'withText'\n\t\t).to( this );\n\n\t\tactionView.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-splitbutton__action'\n\t\t\t}\n\t\t} );\n\n\t\tactionView.delegate( 'execute' ).to( this );\n\n\t\treturn actionView;\n\t}\n\n\t/**\n\t * Creates a {@link module:ui/button/buttonview~ButtonView} instance as {@link #arrowView} and binds it with main split button\n\t * attributes.\n\t *\n\t * @private\n\t * @returns {module:ui/button/buttonview~ButtonView}\n\t */\n\t_createArrowView() {\n\t\tconst arrowView = new ButtonView();\n\t\tconst bind = arrowView.bindTemplate;\n\n\t\tarrowView.icon = dropdownArrowIcon;\n\n\t\tarrowView.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-splitbutton__arrow',\n\t\t\t\t'aria-haspopup': true,\n\t\t\t\t'aria-expanded': bind.to( 'isOn', value => String( value ) )\n\t\t\t}\n\t\t} );\n\n\t\tarrowView.bind( 'isEnabled' ).to( this );\n\n\t\tarrowView.delegate( 'execute' ).to( this, 'open' );\n\n\t\treturn arrowView;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/ui/inserttableview\n */\n\nimport View from '@ckeditor/ckeditor5-ui/src/view';\n\nimport './../../theme/inserttable.css';\n\n/**\n * The table size view.\n *\n * It renders a 10x10 grid to choose the inserted table size.\n *\n * @extends module:ui/view~View\n * @implements module:ui/dropdown/dropdownpanelfocusable~DropdownPanelFocusable\n */\nexport default class InsertTableView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * A collection of table size box items.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.items = this._createGridCollection();\n\n\t\t/**\n\t\t * The currently selected number of rows of the new table.\n\t\t *\n\t\t * @observable\n\t\t * @member {Number} #rows\n\t\t */\n\t\tthis.set( 'rows', 0 );\n\n\t\t/**\n\t\t * The currently selected number of columns of the new table.\n\t\t *\n\t\t * @observable\n\t\t * @member {Number} #columns\n\t\t */\n\t\tthis.set( 'columns', 0 );\n\n\t\t/**\n\t\t * The label text displayed under the boxes.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #label\n\t\t */\n\t\tthis.bind( 'label' )\n\t\t\t.to( this, 'columns', this, 'rows', ( columns, rows ) => `${ rows } × ${ columns }` );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [ 'ck' ]\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [ 'ck-insert-table-dropdown__grid' ]\n\t\t\t\t\t},\n\t\t\t\t\ton: {\n\t\t\t\t\t\t'mouseover@.ck-insert-table-dropdown-grid-box': bind.to( 'boxover' )\n\t\t\t\t\t},\n\t\t\t\t\tchildren: this.items\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttag: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [ 'ck-insert-table-dropdown__label' ]\n\t\t\t\t\t},\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttext: bind.to( 'label' )\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t],\n\n\t\t\ton: {\n\t\t\t\tmousedown: bind.to( evt => {\n\t\t\t\t\tevt.preventDefault();\n\t\t\t\t} ),\n\n\t\t\t\tclick: bind.to( () => {\n\t\t\t\t\tthis.fire( 'execute' );\n\t\t\t\t} )\n\t\t\t}\n\t\t} );\n\n\t\tthis.on( 'boxover', ( evt, domEvt ) => {\n\t\t\tconst { row, column } = domEvt.target.dataset;\n\n\t\t\t// As row & column indexes are zero-based transform it to number of selected rows & columns.\n\t\t\tthis.set( {\n\t\t\t\trows: parseInt( row ),\n\t\t\t\tcolumns: parseInt( column )\n\t\t\t} );\n\t\t} );\n\n\t\tthis.on( 'change:columns', () => {\n\t\t\tthis._highlightGridBoxes();\n\t\t} );\n\n\t\tthis.on( 'change:rows', () => {\n\t\t\tthis._highlightGridBoxes();\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tfocus() {\n\t\t// The dropdown panel expects DropdownPanelFocusable interface on views passed to dropdown panel. See #30.\n\t\t// The method should be implemented while working on keyboard support for this view. See #22.\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tfocusLast() {\n\t\t// The dropdown panel expects DropdownPanelFocusable interface on views passed to dropdown panel. See #30.\n\t\t// The method should be implemented while working on keyboard support for this view. See #22.\n\t}\n\n\t/**\n\t * Highlights grid boxes depending on rows and columns selected.\n\t *\n\t * @private\n\t */\n\t_highlightGridBoxes() {\n\t\tconst rows = this.rows;\n\t\tconst columns = this.columns;\n\n\t\tthis.items.map( ( boxView, index ) => {\n\t\t\t// Translate box index to the row & column index.\n\t\t\tconst itemRow = Math.floor( index / 10 );\n\t\t\tconst itemColumn = index % 10;\n\n\t\t\t// Grid box is highlighted when its row & column index belongs to selected number of rows & columns.\n\t\t\tconst isOn = itemRow < rows && itemColumn < columns;\n\n\t\t\tboxView.set( 'isOn', isOn );\n\t\t} );\n\t}\n\n\t/**\n\t * @private\n\t * @returns {module:ui/viewcollection~ViewCollection} A view collection containing boxes to be placed in a table grid.\n\t */\n\t_createGridCollection() {\n\t\tconst boxes = [];\n\n\t\t// Add grid boxes to table selection view.\n\t\tfor ( let index = 0; index < 100; index++ ) {\n\t\t\tconst row = Math.floor( index / 10 );\n\t\t\tconst column = index % 10;\n\n\t\t\tboxes.push( new TableSizeGridBoxView( this.locale, row + 1, column + 1 ) );\n\t\t}\n\n\t\treturn this.createCollection( boxes );\n\t}\n\n\t/**\n\t * Fired when the mouse hover over one of the {@link #items child grid boxes}.\n\t *\n\t * @event boxover\n\t */\n}\n\n/**\n * A single grid box view element.\n *\n * This class is used to render the table size selection grid in {@link module:table/ui/inserttableview~InsertTableView}.\n *\n * @private\n */\nclass TableSizeGridBoxView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale, row, column ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * Controls whether the grid box view is \"on\".\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isOn\n\t\t */\n\t\tthis.set( 'isOn', false );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck-insert-table-dropdown-grid-box',\n\t\t\t\t\tbind.if( 'isOn', 'ck-on' )\n\t\t\t\t],\n\t\t\t\t'data-row': row,\n\t\t\t\t'data-column': column\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableui\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport { addListToDropdown, createDropdown } from '@ckeditor/ckeditor5-ui/src/dropdown/utils';\nimport SplitButtonView from '@ckeditor/ckeditor5-ui/src/dropdown/button/splitbuttonview';\nimport Model from '@ckeditor/ckeditor5-ui/src/model';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\n\nimport InsertTableView from './ui/inserttableview';\n\nimport tableIcon from './../theme/icons/table.svg';\nimport tableColumnIcon from './../theme/icons/table-column.svg';\nimport tableRowIcon from './../theme/icons/table-row.svg';\nimport tableMergeCellIcon from './../theme/icons/table-merge-cell.svg';\n\n/**\n * The table UI plugin. It introduces:\n *\n * * The `'insertTable'` dropdown,\n * * The `'tableColumn'` dropdown,\n * * The `'tableRow'` dropdown,\n * * The `'mergeTableCells'` split button.\n *\n * The `'tableColumn'`, `'tableRow'` and `'mergeTableCells'` dropdowns work best with {@link module:table/tabletoolbar~TableToolbar}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = this.editor.t;\n\t\tconst contentLanguageDirection = editor.locale.contentLanguageDirection;\n\t\tconst isContentLtr = contentLanguageDirection === 'ltr';\n\n\t\teditor.ui.componentFactory.add( 'insertTable', locale => {\n\t\t\tconst command = editor.commands.get( 'insertTable' );\n\t\t\tconst dropdownView = createDropdown( locale );\n\n\t\t\tdropdownView.bind( 'isEnabled' ).to( command );\n\n\t\t\t// Decorate dropdown's button.\n\t\t\tdropdownView.buttonView.set( {\n\t\t\t\ticon: tableIcon,\n\t\t\t\tlabel: t( 'Insert table' ),\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tlet insertTableView;\n\n\t\t\tdropdownView.on( 'change:isOpen', () => {\n\t\t\t\tif ( insertTableView ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Prepare custom view for dropdown's panel.\n\t\t\t\tinsertTableView = new InsertTableView( locale );\n\t\t\t\tdropdownView.panelView.children.add( insertTableView );\n\n\t\t\t\tinsertTableView.delegate( 'execute' ).to( dropdownView );\n\n\t\t\t\tdropdownView.buttonView.on( 'open', () => {\n\t\t\t\t\t// Reset the chooser before showing it to the user.\n\t\t\t\t\tinsertTableView.rows = 0;\n\t\t\t\t\tinsertTableView.columns = 0;\n\t\t\t\t} );\n\n\t\t\t\tdropdownView.on( 'execute', () => {\n\t\t\t\t\teditor.execute( 'insertTable', { rows: insertTableView.rows, columns: insertTableView.columns } );\n\t\t\t\t\teditor.editing.view.focus();\n\t\t\t\t} );\n\t\t\t} );\n\n\t\t\treturn dropdownView;\n\t\t} );\n\n\t\teditor.ui.componentFactory.add( 'tableColumn', locale => {\n\t\t\tconst options = [\n\t\t\t\t{\n\t\t\t\t\ttype: 'switchbutton',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'setTableColumnHeader',\n\t\t\t\t\t\tlabel: t( 'Header column' ),\n\t\t\t\t\t\tbindIsOn: true\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ type: 'separator' },\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: isContentLtr ? 'insertTableColumnLeft' : 'insertTableColumnRight',\n\t\t\t\t\t\tlabel: t( 'Insert column left' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: isContentLtr ? 'insertTableColumnRight' : 'insertTableColumnLeft',\n\t\t\t\t\t\tlabel: t( 'Insert column right' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'removeTableColumn',\n\t\t\t\t\t\tlabel: t( 'Delete column' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'selectTableColumn',\n\t\t\t\t\t\tlabel: t( 'Select column' )\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t];\n\n\t\t\treturn this._prepareDropdown( t( 'Column' ), tableColumnIcon, options, locale );\n\t\t} );\n\n\t\teditor.ui.componentFactory.add( 'tableRow', locale => {\n\t\t\tconst options = [\n\t\t\t\t{\n\t\t\t\t\ttype: 'switchbutton',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'setTableRowHeader',\n\t\t\t\t\t\tlabel: t( 'Header row' ),\n\t\t\t\t\t\tbindIsOn: true\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ type: 'separator' },\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'insertTableRowAbove',\n\t\t\t\t\t\tlabel: t( 'Insert row above' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'insertTableRowBelow',\n\t\t\t\t\t\tlabel: t( 'Insert row below' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'removeTableRow',\n\t\t\t\t\t\tlabel: t( 'Delete row' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'selectTableRow',\n\t\t\t\t\t\tlabel: t( 'Select row' )\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t];\n\n\t\t\treturn this._prepareDropdown( t( 'Row' ), tableRowIcon, options, locale );\n\t\t} );\n\n\t\teditor.ui.componentFactory.add( 'mergeTableCells', locale => {\n\t\t\tconst options = [\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'mergeTableCellUp',\n\t\t\t\t\t\tlabel: t( 'Merge cell up' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: isContentLtr ? 'mergeTableCellRight' : 'mergeTableCellLeft',\n\t\t\t\t\t\tlabel: t( 'Merge cell right' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'mergeTableCellDown',\n\t\t\t\t\t\tlabel: t( 'Merge cell down' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: isContentLtr ? 'mergeTableCellLeft' : 'mergeTableCellRight',\n\t\t\t\t\t\tlabel: t( 'Merge cell left' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ type: 'separator' },\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'splitTableCellVertically',\n\t\t\t\t\t\tlabel: t( 'Split cell vertically' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'splitTableCellHorizontally',\n\t\t\t\t\t\tlabel: t( 'Split cell horizontally' )\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t];\n\n\t\t\treturn this._prepareMergeSplitButtonDropdown( t( 'Merge cells' ), tableMergeCellIcon, options, locale );\n\t\t} );\n\t}\n\n\t/**\n\t * Creates a dropdown view from a set of options.\n\t *\n\t * @private\n\t * @param {String} label The dropdown button label.\n\t * @param {String} icon An icon for the dropdown button.\n\t * @param {Array.<module:ui/dropdown/utils~ListDropdownItemDefinition>} options The list of options for the dropdown.\n\t * @param {module:utils/locale~Locale} locale\n\t * @returns {module:ui/dropdown/dropdownview~DropdownView}\n\t */\n\t_prepareDropdown( label, icon, options, locale ) {\n\t\tconst editor = this.editor;\n\t\tconst dropdownView = createDropdown( locale );\n\t\tconst commands = this._fillDropdownWithListOptions( dropdownView, options );\n\n\t\t// Decorate dropdown's button.\n\t\tdropdownView.buttonView.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true\n\t\t} );\n\n\t\t// Make dropdown button disabled when all options are disabled.\n\t\tdropdownView.bind( 'isEnabled' ).toMany( commands, 'isEnabled', ( ...areEnabled ) => {\n\t\t\treturn areEnabled.some( isEnabled => isEnabled );\n\t\t} );\n\n\t\tthis.listenTo( dropdownView, 'execute', evt => {\n\t\t\teditor.execute( evt.source.commandName );\n\t\t\teditor.editing.view.focus();\n\t\t} );\n\n\t\treturn dropdownView;\n\t}\n\n\t/**\n\t * Creates a dropdown view with a {@link module:ui/dropdown/button/splitbuttonview~SplitButtonView} for\n\t * merge (and split)–related commands.\n\t *\n\t * @private\n\t * @param {String} label The dropdown button label.\n\t * @param {String} icon An icon for the dropdown button.\n\t * @param {Array.<module:ui/dropdown/utils~ListDropdownItemDefinition>} options The list of options for the dropdown.\n\t * @param {module:utils/locale~Locale} locale\n\t * @returns {module:ui/dropdown/dropdownview~DropdownView}\n\t */\n\t_prepareMergeSplitButtonDropdown( label, icon, options, locale ) {\n\t\tconst editor = this.editor;\n\t\tconst dropdownView = createDropdown( locale, SplitButtonView );\n\t\tconst mergeCommandName = 'mergeTableCells';\n\n\t\tthis._fillDropdownWithListOptions( dropdownView, options );\n\n\t\tdropdownView.buttonView.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true,\n\t\t\tisEnabled: true\n\t\t} );\n\n\t\t// Merge selected table cells when the main part of the split button is clicked.\n\t\tthis.listenTo( dropdownView.buttonView, 'execute', () => {\n\t\t\teditor.execute( mergeCommandName );\n\t\t\teditor.editing.view.focus();\n\t\t} );\n\n\t\t// Execute commands for events coming from the list in the dropdown panel.\n\t\tthis.listenTo( dropdownView, 'execute', evt => {\n\t\t\teditor.execute( evt.source.commandName );\n\t\t\teditor.editing.view.focus();\n\t\t} );\n\n\t\treturn dropdownView;\n\t}\n\n\t/**\n\t * Injects a {@link module:ui/list/listview~ListView} into the passed dropdown with buttons\n\t * which execute editor commands as configured in passed options.\n\t *\n\t * @private\n\t * @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView\n\t * @param {Array.<module:ui/dropdown/utils~ListDropdownItemDefinition>} options The list of options for the dropdown.\n\t * @returns {Array.<module:core/command~Command>} Commands the list options are interacting with.\n\t */\n\t_fillDropdownWithListOptions( dropdownView, options ) {\n\t\tconst editor = this.editor;\n\t\tconst commands = [];\n\t\tconst itemDefinitions = new Collection();\n\n\t\tfor ( const option of options ) {\n\t\t\taddListOption( option, editor, commands, itemDefinitions );\n\t\t}\n\n\t\taddListToDropdown( dropdownView, itemDefinitions, editor.ui.componentFactory );\n\n\t\treturn commands;\n\t}\n}\n\n// Adds an option to a list view.\n//\n// @param {module:table/tableui~DropdownOption} option A configuration option.\n// @param {module:core/editor/editor~Editor} editor\n// @param {Array.<module:core/command~Command>} commands The list of commands to update.\n// @param {Iterable.<module:ui/dropdown/utils~ListDropdownItemDefinition>} itemDefinitions\n// A collection of dropdown items to update with the given option.\nfunction addListOption( option, editor, commands, itemDefinitions ) {\n\tconst model = option.model = new Model( option.model );\n\tconst { commandName, bindIsOn } = option.model;\n\n\tif ( option.type === 'button' || option.type === 'switchbutton' ) {\n\t\tconst command = editor.commands.get( commandName );\n\n\t\tcommands.push( command );\n\n\t\tmodel.set( { commandName } );\n\n\t\tmodel.bind( 'isEnabled' ).to( command );\n\n\t\tif ( bindIsOn ) {\n\t\t\tmodel.bind( 'isOn' ).to( command, 'value' );\n\t\t}\n\t}\n\n\tmodel.set( {\n\t\twithText: true\n\t} );\n\n\titemDefinitions.add( option );\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M3 6v3h4V6H3zm0 4v3h4v-3H3zm0 4v3h4v-3H3zm5 3h4v-3H8v3zm5 0h4v-3h-4v3zm4-4v-3h-4v3h4zm0-4V6h-4v3h4zm1.5 8a1.5 1.5 0 0 1-1.5 1.5H3A1.5 1.5 0 0 1 1.5 17V4c.222-.863 1.068-1.5 2-1.5h13c.932 0 1.778.637 2 1.5v13zM12 13v-3H8v3h4zm0-4V6H8v3h4z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2.5 1h15A1.5 1.5 0 0 1 19 2.5v15a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 1 17.5v-15A1.5 1.5 0 0 1 2.5 1zM2 2v16h16V2H2z\\\" opacity=\\\".6\\\"/><path d=\\\"M18 7v1H2V7h16zm0 5v1H2v-1h16z\\\" opacity=\\\".6\\\"/><path d=\\\"M14 1v18a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1zm-2 1H8v4h4V2zm0 6H8v4h4V8zm0 6H8v4h4v-4z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2.5 1h15A1.5 1.5 0 0 1 19 2.5v15a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 1 17.5v-15A1.5 1.5 0 0 1 2.5 1zM2 2v16h16V2H2z\\\" opacity=\\\".6\\\"/><path d=\\\"M7 2h1v16H7V2zm5 0h1v16h-1V2z\\\" opacity=\\\".6\\\"/><path d=\\\"M1 6h18a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm1 2v4h4V8H2zm6 0v4h4V8H8zm6 0v4h4V8h-4z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2.5 1h15A1.5 1.5 0 0 1 19 2.5v15a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 1 17.5v-15A1.5 1.5 0 0 1 2.5 1zM2 2v16h16V2H2z\\\" opacity=\\\".6\\\"/><path d=\\\"M7 2h1v16H7V2zm5 0h1v7h-1V2zm6 5v1H2V7h16zM8 12v1H2v-1h6z\\\" opacity=\\\".6\\\"/><path d=\\\"M7 7h12a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1zm1 2v9h10V9H8z\\\"/></svg>\";","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableselection\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport first from '@ckeditor/ckeditor5-utils/src/first';\n\nimport TableWalker from './tablewalker';\nimport TableUtils from './tableutils';\n\nimport { cropTableToDimensions, adjustLastRowIndex, adjustLastColumnIndex } from './utils/structure';\nimport { getColumnIndexes, getRowIndexes, getSelectedTableCells, isSelectionRectangular } from './utils/selection';\n\nimport '../theme/tableselection.css';\n\n/**\n * This plugin enables the advanced table cells, rows and columns selection.\n * It is loaded automatically by the {@link module:table/table~Table} plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableSelection extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableSelection';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableUtils ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\n\t\tthis.listenTo( model, 'deleteContent', ( evt, args ) => this._handleDeleteContent( evt, args ), { priority: 'high' } );\n\n\t\tthis._defineSelectionConverter();\n\t\tthis._enablePluginDisabling(); // sic!\n\t}\n\n\t/**\n\t * Returns the currently selected table cells or `null` if it is not a table cells selection.\n\t *\n\t * @returns {Array.<module:engine/model/element~Element>|null}\n\t */\n\tgetSelectedTableCells() {\n\t\tconst selection = this.editor.model.document.selection;\n\n\t\tconst selectedCells = getSelectedTableCells( selection );\n\n\t\tif ( selectedCells.length == 0 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// This should never happen, but let's know if it ever happens.\n\t\t// @if CK_DEBUG //\t/* istanbul ignore next */\n\t\t// @if CK_DEBUG //\tif ( selectedCells.length != selection.rangeCount ) {\n\t\t// @if CK_DEBUG //\t\tconsole.warn( 'Mixed selection warning. The selection contains table cells and some other ranges.' );\n\t\t// @if CK_DEBUG //\t}\n\n\t\treturn selectedCells;\n\t}\n\n\t/**\n\t * Returns the selected table fragment as a document fragment.\n\t *\n\t * @returns {module:engine/model/documentfragment~DocumentFragment|null}\n\t */\n\tgetSelectionAsFragment() {\n\t\tconst selectedCells = this.getSelectedTableCells();\n\n\t\tif ( !selectedCells ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.editor.model.change( writer => {\n\t\t\tconst documentFragment = writer.createDocumentFragment();\n\t\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\n\t\t\tconst { first: firstColumn, last: lastColumn } = getColumnIndexes( selectedCells );\n\t\t\tconst { first: firstRow, last: lastRow } = getRowIndexes( selectedCells );\n\n\t\t\tconst sourceTable = selectedCells[ 0 ].findAncestor( 'table' );\n\n\t\t\tlet adjustedLastRow = lastRow;\n\t\t\tlet adjustedLastColumn = lastColumn;\n\n\t\t\t// If the selection is rectangular there could be a case of all cells in the last row/column spanned over\n\t\t\t// next row/column so the real lastRow/lastColumn should be updated.\n\t\t\tif ( isSelectionRectangular( selectedCells, tableUtils ) ) {\n\t\t\t\tconst dimensions = {\n\t\t\t\t\tfirstColumn,\n\t\t\t\t\tlastColumn,\n\t\t\t\t\tfirstRow,\n\t\t\t\t\tlastRow\n\t\t\t\t};\n\n\t\t\t\tadjustedLastRow = adjustLastRowIndex( sourceTable, dimensions );\n\t\t\t\tadjustedLastColumn = adjustLastColumnIndex( sourceTable, dimensions );\n\t\t\t}\n\n\t\t\tconst cropDimensions = {\n\t\t\t\tstartRow: firstRow,\n\t\t\t\tstartColumn: firstColumn,\n\t\t\t\tendRow: adjustedLastRow,\n\t\t\t\tendColumn: adjustedLastColumn\n\t\t\t};\n\n\t\t\tconst table = cropTableToDimensions( sourceTable, cropDimensions, writer );\n\n\t\t\twriter.insert( table, documentFragment, 0 );\n\n\t\t\treturn documentFragment;\n\t\t} );\n\t}\n\n\t/**\n\t * Sets the model selection based on given anchor and target cells (can be the same cell).\n\t * Takes care of setting the backward flag.\n\t *\n\t *\t\tconst modelRoot = editor.model.document.getRoot();\n\t *\t\tconst firstCell = modelRoot.getNodeByPath( [ 0, 0, 0 ] );\n\t *\t\tconst lastCell = modelRoot.getNodeByPath( [ 0, 0, 1 ] );\n\t *\n\t *\t\tconst tableSelection = editor.plugins.get( 'TableSelection' );\n\t *\t\ttableSelection.setCellSelection( firstCell, lastCell );\n\t *\n\t * @param {module:engine/model/element~Element} anchorCell\n\t * @param {module:engine/model/element~Element} targetCell\n\t */\n\tsetCellSelection( anchorCell, targetCell ) {\n\t\tconst cellsToSelect = this._getCellsToSelect( anchorCell, targetCell );\n\n\t\tthis.editor.model.change( writer => {\n\t\t\twriter.setSelection(\n\t\t\t\tcellsToSelect.cells.map( cell => writer.createRangeOn( cell ) ),\n\t\t\t\t{ backward: cellsToSelect.backward }\n\t\t\t);\n\t\t} );\n\t}\n\n\t/**\n\t * Returns the focus cell from the current selection.\n\t *\n\t * @returns {module:engine/model/element~Element}\n\t */\n\tgetFocusCell() {\n\t\tconst selection = this.editor.model.document.selection;\n\t\tconst focusCellRange = [ ...selection.getRanges() ].pop();\n\t\tconst element = focusCellRange.getContainedElement();\n\n\t\tif ( element && element.is( 'element', 'tableCell' ) ) {\n\t\t\treturn element;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns the anchor cell from the current selection.\n\t *\n\t * @returns {module:engine/model/element~Element} anchorCell\n\t */\n\tgetAnchorCell() {\n\t\tconst selection = this.editor.model.document.selection;\n\t\tconst anchorCellRange = first( selection.getRanges() );\n\t\tconst element = anchorCellRange.getContainedElement();\n\n\t\tif ( element && element.is( 'element', 'tableCell' ) ) {\n\t\t\treturn element;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Defines a selection converter which marks the selected cells with a specific class.\n\t *\n\t * The real DOM selection is put in the last cell. Since the order of ranges is dependent on whether the\n\t * selection is backward or not, the last cell will usually be close to the \"focus\" end of the selection\n\t * (a selection has anchor and focus).\n\t *\n\t * The real DOM selection is then hidden with CSS.\n\t *\n\t * @private\n\t */\n\t_defineSelectionConverter() {\n\t\tconst editor = this.editor;\n\t\tconst highlighted = new Set();\n\n\t\teditor.conversion.for( 'editingDowncast' ).add( dispatcher => dispatcher.on( 'selection', ( evt, data, conversionApi ) => {\n\t\t\tconst viewWriter = conversionApi.writer;\n\n\t\t\tclearHighlightedTableCells( viewWriter );\n\n\t\t\tconst selectedCells = this.getSelectedTableCells();\n\n\t\t\tif ( !selectedCells ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor ( const tableCell of selectedCells ) {\n\t\t\t\tconst viewElement = conversionApi.mapper.toViewElement( tableCell );\n\n\t\t\t\tviewWriter.addClass( 'ck-editor__editable_selected', viewElement );\n\t\t\t\thighlighted.add( viewElement );\n\t\t\t}\n\n\t\t\tconst lastViewCell = conversionApi.mapper.toViewElement( selectedCells[ selectedCells.length - 1 ] );\n\t\t\tviewWriter.setSelection( lastViewCell, 0 );\n\t\t}, { priority: 'lowest' } ) );\n\n\t\tfunction clearHighlightedTableCells( writer ) {\n\t\t\tfor ( const previouslyHighlighted of highlighted ) {\n\t\t\t\twriter.removeClass( 'ck-editor__editable_selected', previouslyHighlighted );\n\t\t\t}\n\n\t\t\thighlighted.clear();\n\t\t}\n\t}\n\n\t/**\n\t * Creates a listener that reacts to changes in {@link #isEnabled} and, if the plugin was disabled,\n\t * it collapses the multi-cell selection to a regular selection placed inside a table cell.\n\t *\n\t * This listener helps features that disable the table selection plugin bring the selection\n\t * to a clear state they can work with (for instance, because they don't support multiple cell selection).\n\t */\n\t_enablePluginDisabling() {\n\t\tconst editor = this.editor;\n\n\t\tthis.on( 'change:isEnabled', () => {\n\t\t\tif ( !this.isEnabled ) {\n\t\t\t\tconst selectedCells = this.getSelectedTableCells();\n\n\t\t\t\tif ( !selectedCells ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\tconst position = writer.createPositionAt( selectedCells[ 0 ], 0 );\n\t\t\t\t\tconst range = editor.model.schema.getNearestSelectionRange( position );\n\n\t\t\t\t\twriter.setSelection( range );\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Overrides the default `model.deleteContent()` behavior over a selected table fragment.\n\t *\n\t * @private\n\t * @param {module:utils/eventinfo~EventInfo} event\n\t * @param {Array.<*>} args Delete content method arguments.\n\t */\n\t_handleDeleteContent( event, args ) {\n\t\tconst [ selection, options ] = args;\n\t\tconst model = this.editor.model;\n\t\tconst isBackward = !options || options.direction == 'backward';\n\t\tconst selectedTableCells = getSelectedTableCells( selection );\n\n\t\tif ( !selectedTableCells.length ) {\n\t\t\treturn;\n\t\t}\n\n\t\tevent.stop();\n\n\t\tmodel.change( writer => {\n\t\t\tconst tableCellToSelect = selectedTableCells[ isBackward ? selectedTableCells.length - 1 : 0 ];\n\n\t\t\tmodel.change( writer => {\n\t\t\t\tfor ( const tableCell of selectedTableCells ) {\n\t\t\t\t\tmodel.deleteContent( writer.createSelection( tableCell, 'in' ) );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tconst rangeToSelect = model.schema.getNearestSelectionRange( writer.createPositionAt( tableCellToSelect, 0 ) );\n\n\t\t\t// Note: we ignore the case where rangeToSelect may be null because deleteContent() will always (unless someone broke it)\n\t\t\t// create an empty paragraph to accommodate the selection.\n\n\t\t\tif ( selection.is( 'documentSelection' ) ) {\n\t\t\t\twriter.setSelection( rangeToSelect );\n\t\t\t} else {\n\t\t\t\tselection.setTo( rangeToSelect );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Returns an array of table cells that should be selected based on the\n\t * given anchor cell and target (focus) cell.\n\t *\n\t * The cells are returned in a reverse direction if the selection is backward.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} anchorCell\n\t * @param {module:engine/model/element~Element} targetCell\n\t * @returns {Array.<module:engine/model/element~Element>}\n\t */\n\t_getCellsToSelect( anchorCell, targetCell ) {\n\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\t\tconst startLocation = tableUtils.getCellLocation( anchorCell );\n\t\tconst endLocation = tableUtils.getCellLocation( targetCell );\n\n\t\tconst startRow = Math.min( startLocation.row, endLocation.row );\n\t\tconst endRow = Math.max( startLocation.row, endLocation.row );\n\n\t\tconst startColumn = Math.min( startLocation.column, endLocation.column );\n\t\tconst endColumn = Math.max( startLocation.column, endLocation.column );\n\n\t\t// 2-dimensional array of the selected cells to ease flipping the order of cells for backward selections.\n\t\tconst selectionMap = new Array( endRow - startRow + 1 ).fill( null ).map( () => [] );\n\n\t\tconst walkerOptions = {\n\t\t\tstartRow,\n\t\t\tendRow,\n\t\t\tstartColumn,\n\t\t\tendColumn\n\t\t};\n\n\t\tfor ( const { row, cell } of new TableWalker( anchorCell.findAncestor( 'table' ), walkerOptions ) ) {\n\t\t\tselectionMap[ row - startRow ].push( cell );\n\t\t}\n\n\t\tconst flipVertically = endLocation.row < startLocation.row;\n\t\tconst flipHorizontally = endLocation.column < startLocation.column;\n\n\t\tif ( flipVertically ) {\n\t\t\tselectionMap.reverse();\n\t\t}\n\n\t\tif ( flipHorizontally ) {\n\t\t\tselectionMap.forEach( row => row.reverse() );\n\t\t}\n\n\t\treturn {\n\t\t\tcells: selectionMap.flat(),\n\t\t\tbackward: flipVertically || flipHorizontally\n\t\t};\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableclipboard\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport TableSelection from './tableselection';\nimport TableWalker from './tablewalker';\nimport TableUtils from './tableutils';\nimport { getColumnIndexes, getRowIndexes, getSelectionAffectedTableCells, isSelectionRectangular, sortRanges } from './utils/selection';\nimport {\n\tcropTableToDimensions,\n\tgetHorizontallyOverlappingCells,\n\tgetVerticallyOverlappingCells,\n\tremoveEmptyRowsColumns,\n\tsplitHorizontally,\n\tsplitVertically,\n\ttrimTableCellIfNeeded,\n\tadjustLastRowIndex,\n\tadjustLastColumnIndex\n} from './utils/structure';\n\n/**\n * This plugin adds support for copying/cutting/pasting fragments of tables.\n * It is loaded automatically by the {@link module:table/table~Table} plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableClipboard extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableClipboard';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableSelection, TableUtils ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst viewDocument = editor.editing.view.document;\n\n\t\tthis.listenTo( viewDocument, 'copy', ( evt, data ) => this._onCopyCut( evt, data ) );\n\t\tthis.listenTo( viewDocument, 'cut', ( evt, data ) => this._onCopyCut( evt, data ) );\n\t\tthis.listenTo( editor.model, 'insertContent', ( evt, args ) => this._onInsertContent( evt, ...args ), { priority: 'high' } );\n\n\t\tthis.decorate( '_replaceTableSlotCell' );\n\t}\n\n\t/**\n\t * Copies table content to a clipboard on \"copy\" & \"cut\" events.\n\t *\n\t * @private\n\t * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the handled event.\n\t * @param {Object} data Clipboard event data.\n\t */\n\t_onCopyCut( evt, data ) {\n\t\tconst tableSelection = this.editor.plugins.get( TableSelection );\n\n\t\tif ( !tableSelection.getSelectedTableCells() ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( evt.name == 'cut' && this.editor.isReadOnly ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdata.preventDefault();\n\t\tevt.stop();\n\n\t\tconst dataController = this.editor.data;\n\t\tconst viewDocument = this.editor.editing.view.document;\n\n\t\tconst content = dataController.toView( tableSelection.getSelectionAsFragment() );\n\n\t\tviewDocument.fire( 'clipboardOutput', {\n\t\t\tdataTransfer: data.dataTransfer,\n\t\t\tcontent,\n\t\t\tmethod: evt.name\n\t\t} );\n\t}\n\n\t/**\n\t * Overrides default {@link module:engine/model/model~Model#insertContent `model.insertContent()`} method to handle pasting table inside\n\t * selected table fragment.\n\t *\n\t * Depending on selected table fragment:\n\t * - If a selected table fragment is smaller than paste table it will crop pasted table to match dimensions.\n\t * - If dimensions are equal it will replace selected table fragment with a pasted table contents.\n\t *\n\t * @private\n\t * @param evt\n\t * @param {module:engine/model/documentfragment~DocumentFragment|module:engine/model/item~Item} content The content to insert.\n\t * @param {module:engine/model/selection~Selectable} [selectable=model.document.selection]\n\t * The selection into which the content should be inserted. If not provided the current model document selection will be used.\n\t */\n\t_onInsertContent( evt, content, selectable ) {\n\t\tif ( selectable && !selectable.is( 'documentSelection' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst model = this.editor.model;\n\t\tconst tableUtils = this.editor.plugins.get( TableUtils );\n\n\t\t// We might need to crop table before inserting so reference might change.\n\t\tlet pastedTable = getTableIfOnlyTableInContent( content, model );\n\n\t\tif ( !pastedTable ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst selectedTableCells = getSelectionAffectedTableCells( model.document.selection );\n\n\t\tif ( !selectedTableCells.length ) {\n\t\t\tremoveEmptyRowsColumns( pastedTable, tableUtils );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Override default model.insertContent() handling at this point.\n\t\tevt.stop();\n\n\t\tmodel.change( writer => {\n\t\t\tconst pastedDimensions = {\n\t\t\t\twidth: tableUtils.getColumns( pastedTable ),\n\t\t\t\theight: tableUtils.getRows( pastedTable )\n\t\t\t};\n\n\t\t\t// Prepare the table for pasting.\n\t\t\tconst selection = prepareTableForPasting( selectedTableCells, pastedDimensions, writer, tableUtils );\n\n\t\t\t// Beyond this point we operate on a fixed content table with rectangular selection and proper last row/column values.\n\n\t\t\tconst selectionHeight = selection.lastRow - selection.firstRow + 1;\n\t\t\tconst selectionWidth = selection.lastColumn - selection.firstColumn + 1;\n\n\t\t\t// Crop pasted table if:\n\t\t\t// - Pasted table dimensions exceeds selection area.\n\t\t\t// - Pasted table has broken layout (ie some cells sticks out by the table dimensions established by the first and last row).\n\t\t\t//\n\t\t\t// Note: The table dimensions are established by the width of the first row and the total number of rows.\n\t\t\t// It is possible to programmatically create a table that has rows which would have cells anchored beyond first row width but\n\t\t\t// such table will not be created by other editing solutions.\n\t\t\tconst cropDimensions = {\n\t\t\t\tstartRow: 0,\n\t\t\t\tstartColumn: 0,\n\t\t\t\tendRow: Math.min( selectionHeight, pastedDimensions.height ) - 1,\n\t\t\t\tendColumn: Math.min( selectionWidth, pastedDimensions.width ) - 1\n\t\t\t};\n\n\t\t\tpastedTable = cropTableToDimensions( pastedTable, cropDimensions, writer );\n\n\t\t\t// Content table to which we insert a pasted table.\n\t\t\tconst selectedTable = selectedTableCells[ 0 ].findAncestor( 'table' );\n\n\t\t\tconst cellsToSelect = this._replaceSelectedCellsWithPasted( pastedTable, pastedDimensions, selectedTable, selection, writer );\n\n\t\t\tif ( this.editor.plugins.get( 'TableSelection' ).isEnabled ) {\n\t\t\t\t// Selection ranges must be sorted because the first and last selection ranges are considered\n\t\t\t\t// as anchor/focus cell ranges for multi-cell selection.\n\t\t\t\tconst selectionRanges = sortRanges( cellsToSelect.map( cell => writer.createRangeOn( cell ) ) );\n\n\t\t\t\twriter.setSelection( selectionRanges );\n\t\t\t} else {\n\t\t\t\t// Set selection inside first cell if multi-cell selection is disabled.\n\t\t\t\twriter.setSelection( cellsToSelect[ 0 ], 0 );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Replaces the part of selectedTable with pastedTable.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} pastedTable\n\t * @param {Object} pastedDimensions\n\t * @param {Number} pastedDimensions.height\n\t * @param {Number} pastedDimensions.width\n\t * @param {module:engine/model/element~Element} selectedTable\n\t * @param {Object} selection\n\t * @param {Number} selection.firstColumn\n\t * @param {Number} selection.firstRow\n\t * @param {Number} selection.lastColumn\n\t * @param {Number} selection.lastRow\n\t * @param {module:engine/model/writer~Writer} writer\n\t * @returns {Array.<module:engine/model/element~Element>}\n\t */\n\t_replaceSelectedCellsWithPasted( pastedTable, pastedDimensions, selectedTable, selection, writer ) {\n\t\tconst { width: pastedWidth, height: pastedHeight } = pastedDimensions;\n\n\t\t// Holds two-dimensional array that is addressed by [ row ][ column ] that stores cells anchored at given location.\n\t\tconst pastedTableLocationMap = createLocationMap( pastedTable, pastedWidth, pastedHeight );\n\n\t\tconst selectedTableMap = [ ...new TableWalker( selectedTable, {\n\t\t\tstartRow: selection.firstRow,\n\t\t\tendRow: selection.lastRow,\n\t\t\tstartColumn: selection.firstColumn,\n\t\t\tendColumn: selection.lastColumn,\n\t\t\tincludeAllSlots: true\n\t\t} ) ];\n\n\t\t// Selection must be set to pasted cells (some might be removed or new created).\n\t\tconst cellsToSelect = [];\n\n\t\t// Store next cell insert position.\n\t\tlet insertPosition;\n\n\t\t// Content table replace cells algorithm iterates over a selected table fragment and:\n\t\t//\n\t\t// - Removes existing table cells at current slot (location).\n\t\t// - Inserts cell from a pasted table for a matched slots.\n\t\t//\n\t\t// This ensures proper table geometry after the paste\n\t\tfor ( const tableSlot of selectedTableMap ) {\n\t\t\tconst { row, column } = tableSlot;\n\n\t\t\t// Save the insert position for current row start.\n\t\t\tif ( column === selection.firstColumn ) {\n\t\t\t\tinsertPosition = tableSlot.getPositionBefore();\n\t\t\t}\n\n\t\t\t// Map current table slot location to an pasted table slot location.\n\t\t\tconst pastedRow = row - selection.firstRow;\n\t\t\tconst pastedColumn = column - selection.firstColumn;\n\t\t\tconst pastedCell = pastedTableLocationMap[ pastedRow % pastedHeight ][ pastedColumn % pastedWidth ];\n\n\t\t\t// Clone cell to insert (to duplicate its attributes and children).\n\t\t\t// Cloning is required to support repeating pasted table content when inserting to a bigger selection.\n\t\t\tconst cellToInsert = pastedCell ? writer.cloneElement( pastedCell ) : null;\n\n\t\t\t// Replace the cell from the current slot with new table cell.\n\t\t\tconst newTableCell = this._replaceTableSlotCell( tableSlot, cellToInsert, insertPosition, writer );\n\n\t\t\t// The cell was only removed.\n\t\t\tif ( !newTableCell ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Trim the cell if it's row/col-spans would exceed selection area.\n\t\t\ttrimTableCellIfNeeded( newTableCell, row, column, selection.lastRow, selection.lastColumn, writer );\n\n\t\t\tcellsToSelect.push( newTableCell );\n\n\t\t\tinsertPosition = writer.createPositionAfter( newTableCell );\n\t\t}\n\n\t\t// If there are any headings, all the cells that overlap from heading must be splitted.\n\t\tconst headingRows = parseInt( selectedTable.getAttribute( 'headingRows' ) || 0 );\n\t\tconst headingColumns = parseInt( selectedTable.getAttribute( 'headingColumns' ) || 0 );\n\n\t\tconst areHeadingRowsIntersectingSelection = selection.firstRow < headingRows && headingRows <= selection.lastRow;\n\t\tconst areHeadingColumnsIntersectingSelection = selection.firstColumn < headingColumns && headingColumns <= selection.lastColumn;\n\n\t\tif ( areHeadingRowsIntersectingSelection ) {\n\t\t\tconst columnsLimit = { first: selection.firstColumn, last: selection.lastColumn };\n\t\t\tconst newCells = doHorizontalSplit( selectedTable, headingRows, columnsLimit, writer, selection.firstRow );\n\n\t\t\tcellsToSelect.push( ...newCells );\n\t\t}\n\n\t\tif ( areHeadingColumnsIntersectingSelection ) {\n\t\t\tconst rowsLimit = { first: selection.firstRow, last: selection.lastRow };\n\t\t\tconst newCells = doVerticalSplit( selectedTable, headingColumns, rowsLimit, writer );\n\n\t\t\tcellsToSelect.push( ...newCells );\n\t\t}\n\n\t\treturn cellsToSelect;\n\t}\n\n\t/**\n\t * Replaces a single table slot.\n\t *\n\t * @private\n\t * @param {module:table/tablewalker~TableSlot} tableSlot\n\t * @param {module:engine/model/element~Element} cellToInsert\n\t * @param {module:engine/model/position~Position} insertPosition\n\t * @param {module:engine/model/writer~Writer} writer\n\t * @returns {module:engine/model/element~Element|null} Inserted table cell or null if slot should remain empty.\n\t */\n\t_replaceTableSlotCell( tableSlot, cellToInsert, insertPosition, writer ) {\n\t\tconst { cell, isAnchor } = tableSlot;\n\n\t\t// If the slot is occupied by a cell in a selected table - remove it.\n\t\t// The slot of this cell will be either:\n\t\t// - Replaced by a pasted table cell.\n\t\t// - Spanned by a previously pasted table cell.\n\t\tif ( isAnchor ) {\n\t\t\twriter.remove( cell );\n\t\t}\n\n\t\t// There is no cell to insert (might be spanned by other cell in a pasted table) - advance to the next content table slot.\n\t\tif ( !cellToInsert ) {\n\t\t\treturn null;\n\t\t}\n\n\t\twriter.insert( cellToInsert, insertPosition );\n\n\t\treturn cellToInsert;\n\t}\n}\n\n/**\n * Extract table for pasting into table.\n *\n * @private\n * @param {module:engine/model/documentfragment~DocumentFragment|module:engine/model/item~Item} content The content to insert.\n * @param {module:engine/model/model~Model} model The editor model.\n * @returns {module:engine/model/element~Element|null}\n */\nexport function getTableIfOnlyTableInContent( content, model ) {\n\tif ( !content.is( 'documentFragment' ) && !content.is( 'element' ) ) {\n\t\treturn null;\n\t}\n\n\t// Table passed directly.\n\tif ( content.is( 'element', 'table' ) ) {\n\t\treturn content;\n\t}\n\n\t// We do not support mixed content when pasting table into table.\n\t// See: https://github.com/ckeditor/ckeditor5/issues/6817.\n\tif ( content.childCount == 1 && content.getChild( 0 ).is( 'element', 'table' ) ) {\n\t\treturn content.getChild( 0 );\n\t}\n\n\t// If there are only whitespaces around a table then use that table for pasting.\n\n\tconst contentRange = model.createRangeIn( content );\n\n\tfor ( const element of contentRange.getItems() ) {\n\t\tif ( element.is( 'element', 'table' ) ) {\n\t\t\t// Stop checking if there is some content before table.\n\t\t\tconst rangeBefore = model.createRange( contentRange.start, model.createPositionBefore( element ) );\n\n\t\t\tif ( model.hasContent( rangeBefore, { ignoreWhitespaces: true } ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Stop checking if there is some content after table.\n\t\t\tconst rangeAfter = model.createRange( model.createPositionAfter( element ), contentRange.end );\n\n\t\t\tif ( model.hasContent( rangeAfter, { ignoreWhitespaces: true } ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// There wasn't any content neither before nor after.\n\t\t\treturn element;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n// Prepares a table for pasting and returns adjusted selection dimensions.\n//\n// @param {Array.<module:engine/model/element~Element>} selectedTableCells\n// @param {Object} pastedDimensions\n// @param {Number} pastedDimensions.height\n// @param {Number} pastedDimensions.width\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:table/tableutils~TableUtils} tableUtils\n// @returns {Object} selection\n// @returns {Number} selection.firstColumn\n// @returns {Number} selection.firstRow\n// @returns {Number} selection.lastColumn\n// @returns {Number} selection.lastRow\nfunction prepareTableForPasting( selectedTableCells, pastedDimensions, writer, tableUtils ) {\n\tconst selectedTable = selectedTableCells[ 0 ].findAncestor( 'table' );\n\n\tconst columnIndexes = getColumnIndexes( selectedTableCells );\n\tconst rowIndexes = getRowIndexes( selectedTableCells );\n\n\tconst selection = {\n\t\tfirstColumn: columnIndexes.first,\n\t\tlastColumn: columnIndexes.last,\n\t\tfirstRow: rowIndexes.first,\n\t\tlastRow: rowIndexes.last\n\t};\n\n\t// Single cell selected - expand selection to pasted table dimensions.\n\tconst shouldExpandSelection = selectedTableCells.length === 1;\n\n\tif ( shouldExpandSelection ) {\n\t\tselection.lastRow += pastedDimensions.height - 1;\n\t\tselection.lastColumn += pastedDimensions.width - 1;\n\n\t\texpandTableSize( selectedTable, selection.lastRow + 1, selection.lastColumn + 1, tableUtils );\n\t}\n\n\t// In case of expanding selection we do not reset the selection so in this case we will always try to fix selection\n\t// like in the case of a non-rectangular area. This might be fixed by re-setting selected cells array but this shortcut is safe.\n\tif ( shouldExpandSelection || !isSelectionRectangular( selectedTableCells, tableUtils ) ) {\n\t\t// For a non-rectangular selection (ie in which some cells sticks out from a virtual selection rectangle) we need to create\n\t\t// a table layout that has a rectangular selection. This will split cells so the selection become rectangular.\n\t\t// Beyond this point we will operate on fixed content table.\n\t\tsplitCellsToRectangularSelection( selectedTable, selection, writer );\n\t}\n\t// However a selected table fragment might be invalid if examined alone. Ie such table fragment:\n\t//\n\t//    +---+---+---+---+\n\t//  0 | a | b | c | d |\n\t//    +   +   +---+---+\n\t//  1 |   | e | f | g |\n\t//    +   +---+   +---+\n\t//  2 |   | h |   | i | <- last row, each cell has rowspan = 2,\n\t//    +   +   +   +   +    so we need to return 3, not 2\n\t//  3 |   |   |   |   |\n\t//    +---+---+---+---+\n\t//\n\t// is invalid as the cells \"h\" and \"i\" have rowspans.\n\t// This case needs only adjusting the selection dimension as the rest of the algorithm operates on empty slots also.\n\telse {\n\t\tselection.lastRow = adjustLastRowIndex( selectedTable, selection );\n\t\tselection.lastColumn = adjustLastColumnIndex( selectedTable, selection );\n\t}\n\n\treturn selection;\n}\n\n// Expand table (in place) to expected size.\nfunction expandTableSize( table, expectedHeight, expectedWidth, tableUtils ) {\n\tconst tableWidth = tableUtils.getColumns( table );\n\tconst tableHeight = tableUtils.getRows( table );\n\n\tif ( expectedWidth > tableWidth ) {\n\t\ttableUtils.insertColumns( table, {\n\t\t\tat: tableWidth,\n\t\t\tcolumns: expectedWidth - tableWidth\n\t\t} );\n\t}\n\n\tif ( expectedHeight > tableHeight ) {\n\t\ttableUtils.insertRows( table, {\n\t\t\tat: tableHeight,\n\t\t\trows: expectedHeight - tableHeight\n\t\t} );\n\t}\n}\n\n// Returns two-dimensional array that is addressed by [ row ][ column ] that stores cells anchored at given location.\n//\n// At given row & column location it might be one of:\n//\n// * cell - cell from pasted table anchored at this location.\n// * null - if no cell is anchored at this location.\n//\n// For instance, from a table below:\n//\n//\t\t+----+----+----+----+\n//\t\t| 00 | 01 | 02 | 03 |\n//\t\t+    +----+----+----+\n//\t\t|    | 11      | 13 |\n//\t\t+----+         +----+\n//\t\t| 20 |         | 23 |\n//\t\t+----+----+----+----+\n//\n// The method will return an array (numbers represents cell element):\n//\n//\tconst map = [\n//\t\t[ '00', '01', '02', '03' ],\n//\t\t[ null, '11', null, '13' ],\n//\t\t[ '20', null, null, '23' ]\n//\t]\n//\n// This allows for a quick access to table at give row & column. For instance to access table cell \"13\" from pasted table call:\n//\n//\t\tconst cell = map[ 1 ][ 3 ]\n//\nfunction createLocationMap( table, width, height ) {\n\t// Create height x width (row x column) two-dimensional table to store cells.\n\tconst map = new Array( height ).fill( null )\n\t\t.map( () => new Array( width ).fill( null ) );\n\n\tfor ( const { column, row, cell } of new TableWalker( table ) ) {\n\t\tmap[ row ][ column ] = cell;\n\t}\n\n\treturn map;\n}\n\n// Make selected cells rectangular by splitting the cells that stand out from a rectangular selection.\n//\n// In the table below a selection is shown with \"::\" and slots with anchor cells are named.\n//\n// +----+----+----+----+----+                    +----+----+----+----+----+\n// | 00 | 01 | 02 | 03      |                    | 00 | 01 | 02 | 03      |\n// +    +----+    +----+----+                    |    ::::::::::::::::----+\n// |    | 11 |    | 13 | 14 |                    |    ::11 |    | 13:: 14 |    <- first row\n// +----+----+    +    +----+                    +----::---|    |   ::----+\n// | 20 | 21 |    |    | 24 |   select cells:    | 20 ::21 |    |   :: 24 |\n// +----+----+    +----+----+     11 -> 33       +----::---|    |---::----+\n// | 30      |    | 33 | 34 |                    | 30 ::   |    | 33:: 34 |    <- last row\n// +         +    +----+    +                    |    ::::::::::::::::    +\n// |         |    | 43 |    |                    |         |    | 43 |    |\n// +----+----+----+----+----+                    +----+----+----+----+----+\n//                                                      ^          ^\n//                                                     first & last columns\n//\n// Will update table to:\n//\n//                       +----+----+----+----+----+\n//                       | 00 | 01 | 02 | 03      |\n//                       +    +----+----+----+----+\n//                       |    | 11 |    | 13 | 14 |\n//                       +----+----+    +    +----+\n//                       | 20 | 21 |    |    | 24 |\n//                       +----+----+    +----+----+\n//                       | 30 |    |    | 33 | 34 |\n//                       +    +----+----+----+    +\n//                       |    |    |    | 43 |    |\n//                       +----+----+----+----+----+\n//\n// In th example above:\n// - Cell \"02\" which have `rowspan = 4` must be trimmed at first and at after last row.\n// - Cell \"03\" which have `rowspan = 2` and `colspan = 2` must be trimmed at first column and after last row.\n// - Cells \"00\", \"03\" & \"30\" which cannot be cut by this algorithm as they are outside the trimmed area.\n// - Cell \"13\" cannot be cut as it is inside the trimmed area.\nfunction splitCellsToRectangularSelection( table, dimensions, writer ) {\n\tconst { firstRow, lastRow, firstColumn, lastColumn } = dimensions;\n\n\tconst rowIndexes = { first: firstRow, last: lastRow };\n\tconst columnIndexes = { first: firstColumn, last: lastColumn };\n\n\t// 1. Split cells vertically in two steps as first step might create cells that needs to split again.\n\tdoVerticalSplit( table, firstColumn, rowIndexes, writer );\n\tdoVerticalSplit( table, lastColumn + 1, rowIndexes, writer );\n\n\t// 2. Split cells horizontally in two steps as first step might create cells that needs to split again.\n\tdoHorizontalSplit( table, firstRow, columnIndexes, writer );\n\tdoHorizontalSplit( table, lastRow + 1, columnIndexes, writer, firstRow );\n}\n\nfunction doHorizontalSplit( table, splitRow, limitColumns, writer, startRow = 0 ) {\n\t// If selection starts at first row then no split is needed.\n\tif ( splitRow < 1 ) {\n\t\treturn;\n\t}\n\n\tconst overlappingCells = getVerticallyOverlappingCells( table, splitRow, startRow );\n\n\t// Filter out cells that are not touching insides of the rectangular selection.\n\tconst cellsToSplit = overlappingCells.filter( ( { column, cellWidth } ) => isAffectedBySelection( column, cellWidth, limitColumns ) );\n\n\treturn cellsToSplit.map( ( { cell } ) => splitHorizontally( cell, splitRow, writer ) );\n}\n\nfunction doVerticalSplit( table, splitColumn, limitRows, writer ) {\n\t// If selection starts at first column then no split is needed.\n\tif ( splitColumn < 1 ) {\n\t\treturn;\n\t}\n\n\tconst overlappingCells = getHorizontallyOverlappingCells( table, splitColumn );\n\n\t// Filter out cells that are not touching insides of the rectangular selection.\n\tconst cellsToSplit = overlappingCells.filter( ( { row, cellHeight } ) => isAffectedBySelection( row, cellHeight, limitRows ) );\n\n\treturn cellsToSplit.map( ( { cell, column } ) => splitVertically( cell, column, splitColumn, writer ) );\n}\n\n// Checks if cell at given row (column) is affected by a rectangular selection defined by first/last column (row).\n//\n// The same check is used for row as for column.\nfunction isAffectedBySelection( index, span, limit ) {\n\tconst endIndex = index + span - 1;\n\tconst { first, last } = limit;\n\n\tconst isInsideSelection = index >= first && index <= last;\n\tconst overlapsSelectionFromOutside = index < first && endIndex >= first;\n\n\treturn isInsideSelection || overlapsSelectionFromOutside;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tablekeyboard\n */\n\nimport TableSelection from './tableselection';\nimport TableWalker from './tablewalker';\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport priorities from '@ckeditor/ckeditor5-utils/src/priorities';\nimport {\n\tisArrowKeyCode,\n\tgetLocalizedArrowKeyCodeDirection\n} from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport { getSelectedTableCells, getTableCellsContainingSelection } from './utils/selection';\n\n/**\n * This plugin enables keyboard navigation for tables.\n * It is loaded automatically by the {@link module:table/table~Table} plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableKeyboard extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableKeyboard';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableSelection ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst view = this.editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\t// Handle Tab key navigation.\n\t\tthis.editor.keystrokes.set( 'Tab', ( ...args ) => this._handleTabOnSelectedTable( ...args ), { priority: 'low' } );\n\t\tthis.editor.keystrokes.set( 'Tab', this._getTabHandler( true ), { priority: 'low' } );\n\t\tthis.editor.keystrokes.set( 'Shift+Tab', this._getTabHandler( false ), { priority: 'low' } );\n\n\t\t// Note: This listener has the \"high-10\" priority because it should allow the Widget plugin to handle the default\n\t\t// behavior first (\"high\") but it should not be \"prevent–defaulted\" by the Widget plugin (\"high-20\") because of\n\t\t// the fake selection retention on the fully selected widget.\n\t\tthis.listenTo( viewDocument, 'keydown', ( ...args ) => this._onKeydown( ...args ), { priority: priorities.get( 'high' ) - 10 } );\n\t}\n\n\t/**\n\t * Handles {@link module:engine/view/document~Document#event:keydown keydown} events for the <kbd>Tab</kbd> key executed\n\t * when the table widget is selected.\n\t *\n\t * @private\n\t * @param {module:engine/view/observer/keyobserver~KeyEventData} data Key event data.\n\t * @param {Function} cancel The stop/stopPropagation/preventDefault function.\n\t */\n\t_handleTabOnSelectedTable( data, cancel ) {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\t\tconst selectedElement = selection.getSelectedElement();\n\n\t\tif ( !selectedElement || !selectedElement.is( 'element', 'table' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tcancel();\n\n\t\teditor.model.change( writer => {\n\t\t\twriter.setSelection( writer.createRangeIn( selectedElement.getChild( 0 ).getChild( 0 ) ) );\n\t\t} );\n\t}\n\n\t/**\n\t * Returns a handler for {@link module:engine/view/document~Document#event:keydown keydown} events for the <kbd>Tab</kbd> key executed\n\t * inside table cells.\n\t *\n\t * @private\n\t * @param {Boolean} isForward Whether this handler will move the selection to the next or the previous cell.\n\t */\n\t_getTabHandler( isForward ) {\n\t\tconst editor = this.editor;\n\n\t\treturn ( domEventData, cancel ) => {\n\t\t\tconst selection = editor.model.document.selection;\n\t\t\tlet tableCell = getTableCellsContainingSelection( selection )[ 0 ];\n\n\t\t\tif ( !tableCell ) {\n\t\t\t\ttableCell = this.editor.plugins.get( 'TableSelection' ).getFocusCell();\n\t\t\t}\n\n\t\t\tif ( !tableCell ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcancel();\n\n\t\t\tconst tableRow = tableCell.parent;\n\t\t\tconst table = tableRow.parent;\n\n\t\t\tconst currentRowIndex = table.getChildIndex( tableRow );\n\t\t\tconst currentCellIndex = tableRow.getChildIndex( tableCell );\n\n\t\t\tconst isFirstCellInRow = currentCellIndex === 0;\n\n\t\t\tif ( !isForward && isFirstCellInRow && currentRowIndex === 0 ) {\n\t\t\t\t// Set the selection over the whole table if the selection was in the first table cell.\n\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\twriter.setSelection( writer.createRangeOn( table ) );\n\t\t\t\t} );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst isLastCellInRow = currentCellIndex === tableRow.childCount - 1;\n\t\t\tconst isLastRow = currentRowIndex === table.childCount - 1;\n\n\t\t\tif ( isForward && isLastRow && isLastCellInRow ) {\n\t\t\t\teditor.execute( 'insertTableRowBelow' );\n\n\t\t\t\t// Check if the command actually added a row. If `insertTableRowBelow` execution didn't add a row (because it was disabled\n\t\t\t\t// or it got overwritten) set the selection over the whole table to mirror the first cell case.\n\t\t\t\tif ( currentRowIndex === table.childCount - 1 ) {\n\t\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\t\twriter.setSelection( writer.createRangeOn( table ) );\n\t\t\t\t\t} );\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet cellToFocus;\n\n\t\t\t// Move to the first cell in the next row.\n\t\t\tif ( isForward && isLastCellInRow ) {\n\t\t\t\tconst nextRow = table.getChild( currentRowIndex + 1 );\n\n\t\t\t\tcellToFocus = nextRow.getChild( 0 );\n\t\t\t}\n\t\t\t// Move to the last cell in the previous row.\n\t\t\telse if ( !isForward && isFirstCellInRow ) {\n\t\t\t\tconst previousRow = table.getChild( currentRowIndex - 1 );\n\n\t\t\t\tcellToFocus = previousRow.getChild( previousRow.childCount - 1 );\n\t\t\t}\n\t\t\t// Move to the next/previous cell.\n\t\t\telse {\n\t\t\t\tcellToFocus = tableRow.getChild( currentCellIndex + ( isForward ? 1 : -1 ) );\n\t\t\t}\n\n\t\t\teditor.model.change( writer => {\n\t\t\t\twriter.setSelection( writer.createRangeIn( cellToFocus ) );\n\t\t\t} );\n\t\t};\n\t}\n\n\t/**\n\t * Handles {@link module:engine/view/document~Document#event:keydown keydown} events.\n\t *\n\t * @private\n\t * @param {module:utils/eventinfo~EventInfo} eventInfo\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData\n\t */\n\t_onKeydown( eventInfo, domEventData ) {\n\t\tconst editor = this.editor;\n\t\tconst keyCode = domEventData.keyCode;\n\n\t\tif ( !isArrowKeyCode( keyCode ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst direction = getLocalizedArrowKeyCodeDirection( keyCode, editor.locale.contentLanguageDirection );\n\t\tconst wasHandled = this._handleArrowKeys( direction, domEventData.shiftKey );\n\n\t\tif ( wasHandled ) {\n\t\t\tdomEventData.preventDefault();\n\t\t\tdomEventData.stopPropagation();\n\t\t\teventInfo.stop();\n\t\t}\n\t}\n\n\t/**\n\t * Handles arrow keys to move the selection around the table.\n\t *\n\t * @private\n\t * @param {'left'|'up'|'right'|'down'} direction The direction of the arrow key.\n\t * @param {Boolean} expandSelection If the current selection should be expanded.\n\t * @returns {Boolean} Returns `true` if key was handled.\n\t */\n\t_handleArrowKeys( direction, expandSelection ) {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst isForward = [ 'right', 'down' ].includes( direction );\n\n\t\t// In case one or more table cells are selected (from outside),\n\t\t// move the selection to a cell adjacent to the selected table fragment.\n\t\tconst selectedCells = getSelectedTableCells( selection );\n\n\t\tif ( selectedCells.length ) {\n\t\t\tlet focusCell;\n\n\t\t\tif ( expandSelection ) {\n\t\t\t\tfocusCell = this.editor.plugins.get( 'TableSelection' ).getFocusCell();\n\t\t\t} else {\n\t\t\t\tfocusCell = isForward ? selectedCells[ selectedCells.length - 1 ] : selectedCells[ 0 ];\n\t\t\t}\n\n\t\t\tthis._navigateFromCellInDirection( focusCell, direction, expandSelection );\n\n\t\t\treturn true;\n\t\t}\n\n\t\t// Abort if we're not in a table cell.\n\t\tconst tableCell = selection.focus.findAncestor( 'tableCell' );\n\n\t\tif ( !tableCell ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Navigation is in the opposite direction than the selection direction so this is shrinking of the selection.\n\t\t// Selection for sure will not approach cell edge.\n\t\tif ( expandSelection && !selection.isCollapsed && selection.isBackward == isForward ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Let's check if the selection is at the beginning/end of the cell.\n\t\tif ( this._isSelectionAtCellEdge( selection, tableCell, isForward ) ) {\n\t\t\tthis._navigateFromCellInDirection( tableCell, direction, expandSelection );\n\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Returns `true` if the selection is at the boundary of a table cell according to the navigation direction.\n\t *\n\t * @private\n\t * @param {module:engine/model/selection~Selection} selection The current selection.\n\t * @param {module:engine/model/element~Element} tableCell The current table cell element.\n\t * @param {Boolean} isForward The expected navigation direction.\n\t * @returns {Boolean}\n\t */\n\t_isSelectionAtCellEdge( selection, tableCell, isForward ) {\n\t\tconst model = this.editor.model;\n\t\tconst schema = this.editor.model.schema;\n\n\t\tconst focus = isForward ? selection.getLastPosition() : selection.getFirstPosition();\n\n\t\t// If the current limit element is not table cell we are for sure not at the cell edge.\n\t\t// Also `modifySelection` will not let us out of it.\n\t\tif ( !schema.getLimitElement( focus ).is( 'element', 'tableCell' ) ) {\n\t\t\tconst boundaryPosition = model.createPositionAt( tableCell, isForward ? 'end' : 0 );\n\n\t\t\treturn boundaryPosition.isTouching( focus );\n\t\t}\n\n\t\tconst probe = model.createSelection( focus );\n\n\t\tmodel.modifySelection( probe, { direction: isForward ? 'forward' : 'backward' } );\n\n\t\t// If there was no change in the focus position, then it's not possible to move the selection there.\n\t\treturn focus.isEqual( probe.focus );\n\t}\n\n\t/**\n\t * Moves the selection from the given table cell in the specified direction.\n\t *\n\t * @protected\n\t * @param {module:engine/model/element~Element} focusCell The table cell that is current multi-cell selection focus.\n\t * @param {'left'|'up'|'right'|'down'} direction Direction in which selection should move.\n\t * @param {Boolean} [expandSelection=false] If the current selection should be expanded.\n\t */\n\t_navigateFromCellInDirection( focusCell, direction, expandSelection = false ) {\n\t\tconst model = this.editor.model;\n\n\t\tconst table = focusCell.findAncestor( 'table' );\n\t\tconst tableMap = [ ...new TableWalker( table, { includeAllSlots: true } ) ];\n\t\tconst { row: lastRow, column: lastColumn } = tableMap[ tableMap.length - 1 ];\n\n\t\tconst currentCellInfo = tableMap.find( ( { cell } ) => cell == focusCell );\n\t\tlet { row, column } = currentCellInfo;\n\n\t\tswitch ( direction ) {\n\t\t\tcase 'left':\n\t\t\t\tcolumn--;\n\t\t\t\tbreak;\n\n\t\t\tcase 'up':\n\t\t\t\trow--;\n\t\t\t\tbreak;\n\n\t\t\tcase 'right':\n\t\t\t\tcolumn += currentCellInfo.cellWidth;\n\t\t\t\tbreak;\n\n\t\t\tcase 'down':\n\t\t\t\trow += currentCellInfo.cellHeight;\n\t\t\t\tbreak;\n\t\t}\n\n\t\tconst isOutsideVertically = row < 0 || row > lastRow;\n\t\tconst isBeforeFirstCell = column < 0 && row <= 0;\n\t\tconst isAfterLastCell = column > lastColumn && row >= lastRow;\n\n\t\t// Note that if the table cell at the end of a row is row-spanned then isAfterLastCell will never be true.\n\t\t// However, we don't know if user was navigating on the last row or not, so let's stay in the table.\n\n\t\tif ( isOutsideVertically || isBeforeFirstCell || isAfterLastCell ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\twriter.setSelection( writer.createRangeOn( table ) );\n\t\t\t} );\n\n\t\t\treturn;\n\t\t}\n\n\t\tif ( column < 0 ) {\n\t\t\tcolumn = expandSelection ? 0 : lastColumn;\n\t\t\trow--;\n\t\t} else if ( column > lastColumn ) {\n\t\t\tcolumn = expandSelection ? lastColumn : 0;\n\t\t\trow++;\n\t\t}\n\n\t\tconst cellToSelect = tableMap.find( cellInfo => cellInfo.row == row && cellInfo.column == column ).cell;\n\t\tconst isForward = [ 'right', 'down' ].includes( direction );\n\t\tconst tableSelection = this.editor.plugins.get( 'TableSelection' );\n\n\t\tif ( expandSelection && tableSelection.isEnabled ) {\n\t\t\tconst anchorCell = tableSelection.getAnchorCell() || focusCell;\n\n\t\t\ttableSelection.setCellSelection( anchorCell, cellToSelect );\n\t\t} else {\n\t\t\tconst positionToSelect = model.createPositionAt( cellToSelect, isForward ? 0 : 'end' );\n\n\t\t\tmodel.change( writer => {\n\t\t\t\twriter.setSelection( positionToSelect );\n\t\t\t} );\n\t\t}\n\t}\n}\n\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableselection/mouseeventsobserver\n */\n\nimport DomEventObserver from '@ckeditor/ckeditor5-engine/src/view/observer/domeventobserver';\n\n/**\n * The mouse selection event observer.\n *\n * It registers listeners for the following DOM events:\n *\n * - `'mousemove'`\n * - `'mouseup'`\n * - `'mouseleave'`\n *\n * Note that this observer is disabled by default. To enable this observer, it needs to be added to\n * {@link module:engine/view/view~View} using the {@link module:engine/view/view~View#addObserver} method.\n *\n * The observer is registered by the {@link module:table/tableselection~TableSelection} plugin.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class MouseEventsObserver extends DomEventObserver {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = [ 'mousemove', 'mouseup', 'mouseleave' ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tonDomEvent( domEvent ) {\n\t\tthis.fire( domEvent.type, domEvent );\n\t}\n}\n\n/**\n * Fired when the mouse button is released over one of the editables.\n *\n * Introduced by {@link module:table/tableselection/mouseeventsobserver~MouseEventsObserver}.\n *\n * Note that this event is not available by default. To make it available,\n * {@link module:table/tableselection/mouseeventsobserver~MouseEventsObserver} needs to be added\n * to {@link module:engine/view/view~View} using the {@link module:engine/view/view~View#addObserver} method.\n *\n * @see module:table/tableselection/mouseeventsobserver~MouseEventsObserver\n * @event module:engine/view/document~Document#event:mouseup\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n\n/**\n * Fired when the mouse is moved over one of the editables.\n *\n * Introduced by {@link module:table/tableselection/mouseeventsobserver~MouseEventsObserver}.\n *\n * Note that this event is not available by default. To make it available,\n * {@link module:table/tableselection/mouseeventsobserver~MouseEventsObserver} needs to be added\n * to {@link module:engine/view/view~View} using the {@link module:engine/view/view~View#addObserver} method.\n *\n * @see module:table/tableselection/mouseeventsobserver~MouseEventsObserver\n * @event module:engine/view/document~Document#event:mousemove\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n\n/**\n * Fired when the mouse is moved out of one of the editables.\n *\n * Introduced by {@link module:table/tableselection/mouseeventsobserver~MouseEventsObserver}.\n *\n * Note that this event is not available by default. To make it available,\n * {@link module:table/tableselection/mouseeventsobserver~MouseEventsObserver} needs to be added\n * to {@link module:engine/view/view~View} using the {@link module:engine/view/view~View#addObserver} method.\n *\n * @see module:table/tableselection/mouseeventsobserver~MouseEventsObserver\n * @event module:engine/view/document~Document#event:mouseleave\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tablemouse\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport TableSelection from './tableselection';\nimport MouseEventsObserver from './tablemouse/mouseeventsobserver';\n\nimport { getTableCellsContainingSelection } from './utils/selection';\n\n/**\n * This plugin enables a table cells' selection with the mouse.\n * It is loaded automatically by the {@link module:table/table~Table} plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableMouse extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableMouse';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableSelection ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Currently the MouseObserver only handles `mouseup` events.\n\t\t// TODO move to the engine?\n\t\teditor.editing.view.addObserver( MouseEventsObserver );\n\n\t\tthis._enableShiftClickSelection();\n\t\tthis._enableMouseDragSelection();\n\t}\n\n\t/**\n\t * Enables making cells selection by <kbd>Shift</kbd>+click. Creates a selection from the cell which previously held\n\t * the selection to the cell which was clicked. It can be the same cell, in which case it selects a single cell.\n\t *\n\t * @private\n\t */\n\t_enableShiftClickSelection() {\n\t\tconst editor = this.editor;\n\t\tlet blockSelectionChange = false;\n\n\t\tconst tableSelection = editor.plugins.get( TableSelection );\n\n\t\tthis.listenTo( editor.editing.view.document, 'mousedown', ( evt, domEventData ) => {\n\t\t\tif ( !this.isEnabled || !tableSelection.isEnabled ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( !domEventData.domEvent.shiftKey ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst anchorCell = tableSelection.getAnchorCell() || getTableCellsContainingSelection( editor.model.document.selection )[ 0 ];\n\n\t\t\tif ( !anchorCell ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst targetCell = this._getModelTableCellFromDomEvent( domEventData );\n\n\t\t\tif ( targetCell && haveSameTableParent( anchorCell, targetCell ) ) {\n\t\t\t\tblockSelectionChange = true;\n\t\t\t\ttableSelection.setCellSelection( anchorCell, targetCell );\n\n\t\t\t\tdomEventData.preventDefault();\n\t\t\t}\n\t\t} );\n\n\t\tthis.listenTo( editor.editing.view.document, 'mouseup', () => {\n\t\t\tblockSelectionChange = false;\n\t\t} );\n\n\t\t// We need to ignore a `selectionChange` event that is fired after we render our new table cells selection.\n\t\t// When downcasting table cells selection to the view, we put the view selection in the last selected cell\n\t\t// in a place that may not be natively a \"correct\" location. This is – we put it directly in the `<td>` element.\n\t\t// All browsers fire the native `selectionchange` event.\n\t\t// However, all browsers except Safari return the selection in the exact place where we put it\n\t\t// (even though it's visually normalized). Safari returns `<td><p>^foo` that makes our selection observer\n\t\t// fire our `selectionChange` event (because the view selection that we set in the first step differs from the DOM selection).\n\t\t// Since `selectionChange` is fired, we automatically update the model selection that moves it that paragraph.\n\t\t// This breaks our dear cells selection.\n\t\t//\n\t\t// Theoretically this issue concerns only Safari that is the only browser that do normalize the selection.\n\t\t// However, to avoid code branching and to have a good coverage for this event blocker, I enabled it for all browsers.\n\t\t//\n\t\t// Note: I'm keeping the `blockSelectionChange` state separately for shift+click and mouse drag (exact same logic)\n\t\t// so I don't have to try to analyze whether they don't overlap in some weird cases. Probably they don't.\n\t\t// But I have other things to do, like writing this comment.\n\t\tthis.listenTo( editor.editing.view.document, 'selectionChange', evt => {\n\t\t\tif ( blockSelectionChange ) {\n\t\t\t\t// @if CK_DEBUG // console.log( 'Blocked selectionChange to avoid breaking table cells selection.' );\n\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: 'highest' } );\n\t}\n\n\t/**\n\t * Enables making cells selection by dragging.\n\t *\n\t * The selection is made only on mousemove. Mouse tracking is started on mousedown.\n\t * However, the cells selection is enabled only after the mouse cursor left the anchor cell.\n\t * Thanks to that normal text selection within one cell works just fine. However, you can still select\n\t * just one cell by leaving the anchor cell and moving back to it.\n\t *\n\t * @private\n\t */\n\t_enableMouseDragSelection() {\n\t\tconst editor = this.editor;\n\t\tlet anchorCell, targetCell;\n\t\tlet beganCellSelection = false;\n\t\tlet blockSelectionChange = false;\n\n\t\tconst tableSelection = editor.plugins.get( TableSelection );\n\n\t\tthis.listenTo( editor.editing.view.document, 'mousedown', ( evt, domEventData ) => {\n\t\t\tif ( !this.isEnabled || !tableSelection.isEnabled ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Make sure to not conflict with the shift+click listener and any other possible handler.\n\t\t\tif ( domEventData.domEvent.shiftKey || domEventData.domEvent.ctrlKey || domEventData.domEvent.altKey ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tanchorCell = this._getModelTableCellFromDomEvent( domEventData );\n\t\t} );\n\n\t\tthis.listenTo( editor.editing.view.document, 'mousemove', ( evt, domEventData ) => {\n\t\t\tif ( !domEventData.domEvent.buttons ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( !anchorCell ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst newTargetCell = this._getModelTableCellFromDomEvent( domEventData );\n\n\t\t\tif ( newTargetCell && haveSameTableParent( anchorCell, newTargetCell ) ) {\n\t\t\t\ttargetCell = newTargetCell;\n\n\t\t\t\t// Switch to the cell selection mode after the mouse cursor left the anchor cell.\n\t\t\t\t// Switch off only on mouseup (makes selecting a single cell possible).\n\t\t\t\tif ( !beganCellSelection && targetCell != anchorCell ) {\n\t\t\t\t\tbeganCellSelection = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Yep, not making a cell selection yet. See method docs.\n\t\t\tif ( !beganCellSelection ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tblockSelectionChange = true;\n\t\t\ttableSelection.setCellSelection( anchorCell, targetCell );\n\n\t\t\tdomEventData.preventDefault();\n\t\t} );\n\n\t\tthis.listenTo( editor.editing.view.document, 'mouseup', () => {\n\t\t\tbeganCellSelection = false;\n\t\t\tblockSelectionChange = false;\n\t\t\tanchorCell = null;\n\t\t\ttargetCell = null;\n\t\t} );\n\n\t\t// See the explanation in `_enableShiftClickSelection()`.\n\t\tthis.listenTo( editor.editing.view.document, 'selectionChange', evt => {\n\t\t\tif ( blockSelectionChange ) {\n\t\t\t\t// @if CK_DEBUG // console.log( 'Blocked selectionChange to avoid breaking table cells selection.' );\n\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: 'highest' } );\n\t}\n\n\t/**\n\t * Returns the model table cell element based on the target element of the passed DOM event.\n\t *\n\t * @private\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData\n\t * @returns {module:engine/model/element~Element|undefined} Returns the table cell or `undefined`.\n\t */\n\t_getModelTableCellFromDomEvent( domEventData ) {\n\t\t// Note: Work with positions (not element mapping) because the target element can be an attribute or other non-mapped element.\n\t\tconst viewTargetElement = domEventData.target;\n\t\tconst viewPosition = this.editor.editing.view.createPositionAt( viewTargetElement, 0 );\n\t\tconst modelPosition = this.editor.editing.mapper.toModelPosition( viewPosition );\n\t\tconst modelElement = modelPosition.parent;\n\n\t\treturn modelElement.findAncestor( 'tableCell', { includeSelf: true } );\n\t}\n}\n\nfunction haveSameTableParent( cellA, cellB ) {\n\treturn cellA.parent.parent == cellB.parent.parent;\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/utils/ui/widget\n */\n\nimport { isWidget } from '@ckeditor/ckeditor5-widget/src/utils';\n\n/**\n * Returns a table widget editing view element if one is selected.\n *\n * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} selection\n * @returns {module:engine/view/element~Element|null}\n */\nexport function getSelectedTableWidget( selection ) {\n\tconst viewElement = selection.getSelectedElement();\n\n\tif ( viewElement && isTableWidget( viewElement ) ) {\n\t\treturn viewElement;\n\t}\n\n\treturn null;\n}\n\n/**\n * Returns a table widget editing view element if one is among the selection's ancestors.\n *\n * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} selection\n * @returns {module:engine/view/element~Element|null}\n */\nexport function getTableWidgetAncestor( selection ) {\n\tconst parentTable = findAncestor( 'table', selection.getFirstPosition() );\n\n\tif ( parentTable && isTableWidget( parentTable.parent ) ) {\n\t\treturn parentTable.parent;\n\t}\n\n\treturn null;\n}\n\n// Checks if a given view element is a table widget.\n//\n// @param {module:engine/view/element~Element} viewElement\n// @returns {Boolean}\nfunction isTableWidget( viewElement ) {\n\treturn !!viewElement.getCustomProperty( 'table' ) && isWidget( viewElement );\n}\n\nfunction findAncestor( parentName, positionOrElement ) {\n\tlet parent = positionOrElement.parent;\n\n\twhile ( parent ) {\n\t\tif ( parent.name === parentName ) {\n\t\t\treturn parent;\n\t\t}\n\n\t\tparent = parent.parent;\n\t}\n}\n","import toString from './toString.js';\n\n/**\n * Used to match `RegExp`\n * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).\n */\nvar reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g,\n    reHasRegExpChar = RegExp(reRegExpChar.source);\n\n/**\n * Escapes the `RegExp` special characters \"^\", \"$\", \"\\\", \".\", \"*\", \"+\",\n * \"?\", \"(\", \")\", \"[\", \"]\", \"{\", \"}\", and \"|\" in `string`.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to escape.\n * @returns {string} Returns the escaped string.\n * @example\n *\n * _.escapeRegExp('[lodash](https://lodash.com/)');\n * // => '\\[lodash\\]\\(https://lodash\\.com/\\)'\n */\nfunction escapeRegExp(string) {\n  string = toString(string);\n  return (string && reHasRegExpChar.test(string))\n    ? string.replace(reRegExpChar, '\\\\$&')\n    : string;\n}\n\nexport default escapeRegExp;\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/texttransformation\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport TextWatcher from './textwatcher';\nimport { escapeRegExp } from 'lodash-es';\n\n// All named transformations.\nconst TRANSFORMATIONS = {\n\t// Common symbols:\n\tcopyright: { from: '(c)', to: '©' },\n\tregisteredTrademark: { from: '(r)', to: '®' },\n\ttrademark: { from: '(tm)', to: '™' },\n\n\t// Mathematical:\n\toneHalf: { from: '1/2', to: '½' },\n\toneThird: { from: '1/3', to: '⅓' },\n\ttwoThirds: { from: '2/3', to: '⅔' },\n\toneForth: { from: '1/4', to: '¼' },\n\tthreeQuarters: { from: '3/4', to: '¾' },\n\tlessThanOrEqual: { from: '<=', to: '≤' },\n\tgreaterThanOrEqual: { from: '>=', to: '≥' },\n\tnotEqual: { from: '!=', to: '≠' },\n\tarrowLeft: { from: '<-', to: '←' },\n\tarrowRight: { from: '->', to: '→' },\n\n\t// Typography:\n\thorizontalEllipsis: { from: '...', to: '…' },\n\tenDash: { from: /(^| )(--)( )$/, to: [ null, '–', null ] },\n\temDash: { from: /(^| )(---)( )$/, to: [ null, '—', null ] },\n\t// Quotations:\n\t// English, US\n\tquotesPrimary: { from: buildQuotesRegExp( '\"' ), to: [ null, '“', null, '”' ] },\n\tquotesSecondary: { from: buildQuotesRegExp( '\\'' ), to: [ null, '‘', null, '’' ] },\n\n\t// English, UK\n\tquotesPrimaryEnGb: { from: buildQuotesRegExp( '\\'' ), to: [ null, '‘', null, '’' ] },\n\tquotesSecondaryEnGb: { from: buildQuotesRegExp( '\"' ), to: [ null, '“', null, '”' ] },\n\n\t// Polish\n\tquotesPrimaryPl: { from: buildQuotesRegExp( '\"' ), to: [ null, '„', null, '”' ] },\n\tquotesSecondaryPl: { from: buildQuotesRegExp( '\\'' ), to: [ null, '‚', null, '’' ] }\n};\n\n// Transformation groups.\nconst TRANSFORMATION_GROUPS = {\n\tsymbols: [ 'copyright', 'registeredTrademark', 'trademark' ],\n\tmathematical: [\n\t\t'oneHalf', 'oneThird', 'twoThirds', 'oneForth', 'threeQuarters',\n\t\t'lessThanOrEqual', 'greaterThanOrEqual', 'notEqual',\n\t\t'arrowLeft', 'arrowRight'\n\t],\n\ttypography: [ 'horizontalEllipsis', 'enDash', 'emDash' ],\n\tquotes: [ 'quotesPrimary', 'quotesSecondary' ]\n};\n\n// A set of default transformations provided by the feature.\nconst DEFAULT_TRANSFORMATIONS = [\n\t'symbols',\n\t'mathematical',\n\t'typography',\n\t'quotes'\n];\n\n/**\n * The text transformation plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TextTransformation extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TextTransformation';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( 'typing', {\n\t\t\ttransformations: {\n\t\t\t\tinclude: DEFAULT_TRANSFORMATIONS\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst model = this.editor.model;\n\t\tconst modelSelection = model.document.selection;\n\n\t\tmodelSelection.on( 'change:range', () => {\n\t\t\t// Disable plugin when selection is inside a code block.\n\t\t\tthis.isEnabled = !modelSelection.anchor.parent.is( 'element', 'codeBlock' );\n\t\t} );\n\n\t\tthis._enableTransformationWatchers();\n\t}\n\n\t/**\n\t * Create new TextWatcher listening to the editor for typing and selection events.\n\t *\n\t * @private\n\t */\n\t_enableTransformationWatchers() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst input = editor.plugins.get( 'Input' );\n\t\tconst normalizedTransformations = normalizeTransformations( editor.config.get( 'typing.transformations' ) );\n\n\t\tconst testCallback = text => {\n\t\t\tfor ( const normalizedTransformation of normalizedTransformations ) {\n\t\t\t\tconst from = normalizedTransformation.from;\n\t\t\t\tconst match = from.test( text );\n\n\t\t\t\tif ( match ) {\n\t\t\t\t\treturn { normalizedTransformation };\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tconst watcherCallback = ( evt, data ) => {\n\t\t\tif ( !input.isInput( data.batch ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst { from, to } = data.normalizedTransformation;\n\n\t\t\tconst matches = from.exec( data.text );\n\t\t\tconst replaces = to( matches.slice( 1 ) );\n\n\t\t\tconst matchedRange = data.range;\n\n\t\t\tlet changeIndex = matches.index;\n\n\t\t\tmodel.enqueueChange( writer => {\n\t\t\t\tfor ( let i = 1; i < matches.length; i++ ) {\n\t\t\t\t\tconst match = matches[ i ];\n\t\t\t\t\tconst replaceWith = replaces[ i - 1 ];\n\n\t\t\t\t\tif ( replaceWith == null ) {\n\t\t\t\t\t\tchangeIndex += match.length;\n\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst replacePosition = matchedRange.start.getShiftedBy( changeIndex );\n\t\t\t\t\tconst replaceRange = model.createRange( replacePosition, replacePosition.getShiftedBy( match.length ) );\n\t\t\t\t\tconst attributes = getTextAttributesAfterPosition( replacePosition );\n\n\t\t\t\t\tmodel.insertContent( writer.createText( replaceWith, attributes ), replaceRange );\n\n\t\t\t\t\tchangeIndex += replaceWith.length;\n\t\t\t\t}\n\t\t\t} );\n\t\t};\n\n\t\tconst watcher = new TextWatcher( editor.model, testCallback );\n\n\t\twatcher.on( 'matched:data', watcherCallback );\n\t\twatcher.bind( 'isEnabled' ).to( this );\n\t}\n}\n\n// Normalizes the configuration `from` parameter value.\n// The normalized value for the `from` parameter is a RegExp instance. If the passed `from` is already a RegExp instance,\n// it is returned unchanged.\n//\n// @param {String|RegExp} from\n// @returns {RegExp}\nfunction normalizeFrom( from ) {\n\tif ( typeof from == 'string' ) {\n\t\treturn new RegExp( `(${ escapeRegExp( from ) })$` );\n\t}\n\n\t// `from` is already a regular expression.\n\treturn from;\n}\n\n// Normalizes the configuration `to` parameter value.\n// The normalized value for the `to` parameter is a function that takes an array and returns an array. See more in the\n// configuration description. If the passed `to` is already a function, it is returned unchanged.\n//\n// @param {String|Array.<null|String>|Function} to\n// @returns {Function}\nfunction normalizeTo( to ) {\n\tif ( typeof to == 'string' ) {\n\t\treturn () => [ to ];\n\t} else if ( to instanceof Array ) {\n\t\treturn () => to;\n\t}\n\n\t// `to` is already a function.\n\treturn to;\n}\n\n// For given `position` returns attributes for the text that is after that position.\n// The text can be in the same text node as the position (`foo[]bar`) or in the next text node (`foo[]<$text bold=\"true\">bar</$text>`).\n//\n// @param {module:engine/model/position~Position} position\n// @returns {Iterable.<*>}\nfunction getTextAttributesAfterPosition( position ) {\n\tconst textNode = position.textNode ? position.textNode : position.nodeAfter;\n\n\treturn textNode.getAttributes();\n}\n\n// Returns a RegExp pattern string that detects a sentence inside a quote.\n//\n// @param {String} quoteCharacter The character to create a pattern for.\n// @returns {String}\nfunction buildQuotesRegExp( quoteCharacter ) {\n\treturn new RegExp( `(^|\\\\s)(${ quoteCharacter })([^${ quoteCharacter }]*)(${ quoteCharacter })$` );\n}\n\n// Reads text transformation config and returns normalized array of transformations objects.\n//\n// @param {module:typing/texttransformation~TextTransformationDescription} config\n// @returns {Array.<{from:String,to:Function}>}\nfunction normalizeTransformations( config ) {\n\tconst extra = config.extra || [];\n\tconst remove = config.remove || [];\n\tconst isNotRemoved = transformation => !remove.includes( transformation );\n\n\tconst configured = config.include.concat( extra ).filter( isNotRemoved );\n\n\treturn expandGroupsAndRemoveDuplicates( configured )\n\t\t.filter( isNotRemoved ) // Filter out 'remove' transformations as they might be set in group\n\t\t.map( transformation => TRANSFORMATIONS[ transformation ] || transformation )\n\t\t.map( transformation => ( {\n\t\t\tfrom: normalizeFrom( transformation.from ),\n\t\t\tto: normalizeTo( transformation.to )\n\t\t} ) );\n}\n\n// Reads definitions and expands named groups if needed to transformation names.\n// This method also removes duplicated named transformations if any.\n//\n// @param {Array.<String|Object>} definitions\n// @returns {Array.<String|Object>}\nfunction expandGroupsAndRemoveDuplicates( definitions ) {\n\t// Set is using to make sure that transformation names are not duplicated.\n\tconst definedTransformations = new Set();\n\n\tfor ( const transformationOrGroup of definitions ) {\n\t\tif ( TRANSFORMATION_GROUPS[ transformationOrGroup ] ) {\n\t\t\tfor ( const transformation of TRANSFORMATION_GROUPS[ transformationOrGroup ] ) {\n\t\t\t\tdefinedTransformations.add( transformation );\n\t\t\t}\n\t\t} else {\n\t\t\tdefinedTransformations.add( transformationOrGroup );\n\t\t}\n\t}\n\n\treturn Array.from( definedTransformations );\n}\n\n/**\n * The text transformation definition object. It describes what should be replaced with what.\n *\n * The input value (`from`) can be passed either as a string or as a regular expression.\n *\n * * If a string is passed, it will be simply checked if the end of the input matches it.\n * * If a regular expression is passed, its entire length must be covered with capturing groups (e.g. `/(foo)(bar)$/`).\n * Also, since it is compared against the end of the input, it has to end with  `$` to be correctly matched.\n * See examples below.\n *\n * The output value (`to`) can be passed as a string, as an array or as a function.\n *\n * * If a string is passed, it will be used as a replacement value as-is. Note that a string output value can be used only if\n * the input value is a string, too.\n * * If an array is passed, it has to have the same number of elements as there are capturing groups in the input value regular expression.\n * Each capture group will be replaced with a corresponding string from the passed array. If a given capturing group should not be replaced,\n * use `null` instead of passing a string.\n * * If a function is used, it should return an array as described above. The function is passed one parameter &mdash; an array with matches\n * by the regular expression. See the examples below.\n *\n * A simple string-to-string replacement:\n *\n *\t\t{ from: '(c)', to: '©' }\n *\n * Change quote styles using a regular expression. Note how all the parts are in separate capturing groups and the space at the beginning\n * and the text inside quotes are not replaced (`null` passed as the first and the third value in the `to` parameter):\n *\n *\t\t{\n *\t\t\tfrom: /(^|\\s)(\")([^\"]*)(\")$/,\n *\t\t\tto: [ null, '“', null, '”' ]\n *\t\t}\n *\n * Automatic uppercase after a dot using a callback:\n *\n *\t\t{\n *\t\t\tfrom: /(\\. )([a-z])$/,\n *\t\t\tto: matches => [ null, matches[ 1 ].toUpperCase() ]\n *\t\t}\n *\n * @typedef {Object} module:typing/texttransformation~TextTransformationDescription\n * @property {String|RegExp} from The string or regular expression to transform.\n * @property {String} to The text to transform compatible with `String.replace()`.\n */\n\n/**\n * The configuration of the {@link module:typing/texttransformation~TextTransformation} feature.\n *\n * Read more in {@link module:typing/texttransformation~TextTransformationConfig}.\n *\n * @member {module:typing/texttransformation~TextTransformationConfig} module:typing/typing~TypingConfig#transformations\n */\n\n/**\n * The configuration of the text transformation feature.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\ttyping: {\n *\t\t\t\t\ttransformations: ... // Text transformation feature options.\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * By default, the feature comes pre-configured\n * (via {@link module:typing/texttransformation~TextTransformationConfig#include `config.typing.transformations.include`}) with the\n * following groups of transformations:\n *\n * * Typography (group name: `typography`)\n *   - `ellipsis`: transforms `...` to `…`\n *   - `enDash`: transforms ` -- ` to ` – `\n *   - `emDash`: transforms ` --- ` to ` — `\n * * Quotations (group name: `quotes`)\n *   - `quotesPrimary`: transforms `\"Foo bar\"` to `“Foo bar”`\n *   - `quotesSecondary`: transforms `'Foo bar'` to `‘Foo bar’`\n * * Symbols (group name: `symbols`)\n *   - `trademark`: transforms `(tm)` to `™`\n *   - `registeredTrademark`: transforms `(r)` to `®`\n *   - `copyright`: transforms `(c)` to `©`\n * * Mathematical (group name: `mathematical`)\n *   - `oneHalf`: transforms `1/2` to: `½`\n *   - `oneThird`: transforms `1/3` to: `⅓`\n *   - `twoThirds`: transforms `2/3` to: `⅔`\n *   - `oneForth`: transforms `1/4` to: `¼`\n *   - `threeQuarters`: transforms `3/4` to: `¾`\n *   - `lessThanOrEqual`: transforms `<=` to: `≤`\n *   - `greaterThanOrEqual`: transforms `>=` to: `≥`\n *   - `notEqual`: transforms `!=` to: `≠`\n *   - `arrowLeft`: transforms `<-` to: `←`\n *   - `arrowRight`: transforms `->` to: `→`\n * * Misc:\n *   - `quotesPrimaryEnGb`: transforms `'Foo bar'` to `‘Foo bar’`\n *   - `quotesSecondaryEnGb`: transforms `\"Foo bar\"` to `“Foo bar”`\n *   - `quotesPrimaryPl`: transforms `\"Foo bar\"` to `„Foo bar”`\n *   - `quotesSecondaryPl`:  transforms `'Foo bar'` to `‚Foo bar’`\n *\n * In order to load additional transformations, use the\n * {@link module:typing/texttransformation~TextTransformationConfig#extra `transformations.extra` option}.\n *\n * In order to narrow down the list of transformations, use the\n * {@link module:typing/texttransformation~TextTransformationConfig#remove `transformations.remove` option}.\n *\n * In order to completely override the supported transformations, use the\n * {@link module:typing/texttransformation~TextTransformationConfig#include `transformations.include` option}.\n *\n * Examples:\n *\n *\t\tconst transformationsConfig = {\n *\t\t\tinclude: [\n *\t\t\t\t// Use only the 'quotes' and 'typography' groups.\n *\t\t\t\t'quotes',\n *\t\t\t\t'typography',\n *\n *\t\t\t\t// Plus, some custom transformation.\n *\t\t\t\t{ from: 'CKE', to: 'CKEditor' }\n *\t\t\t]\n *\t\t};\n *\n *\t\tconst transformationsConfig = {\n *\t\t\t// Remove the 'ellipsis' transformation loaded by the 'typography' group.\n *\t\t\tremove: [ 'ellipsis' ]\n *\t\t}\n *\n * @interface TextTransformationConfig\n */\n\n/* eslint-disable max-len */\n/**\n * The standard list of text transformations supported by the editor. By default it comes pre-configured with a couple dozen of them\n * (see {@link module:typing/texttransformation~TextTransformationConfig} for the full list). You can override this list completely\n * by setting this option or use the other two options\n * ({@link module:typing/texttransformation~TextTransformationConfig#extra `transformations.extra`},\n * {@link module:typing/texttransformation~TextTransformationConfig#remove `transformations.remove`}) to fine-tune the default list.\n *\n * @member {Array.<module:typing/texttransformation~TextTransformationDescription>} module:typing/texttransformation~TextTransformationConfig#include\n */\n\n/**\n * Additional text transformations that are added to the transformations defined in\n * {@link module:typing/texttransformation~TextTransformationConfig#include `transformations.include`}.\n *\n *\t\tconst transformationsConfig = {\n *\t\t\textra: [\n *\t\t\t\t{ from: 'CKE', to: 'CKEditor' }\n *\t\t\t]\n *\t\t};\n *\n * @member {Array.<module:typing/texttransformation~TextTransformationDescription>} module:typing/texttransformation~TextTransformationConfig#extra\n */\n\n/**\n * The text transformation names that are removed from transformations defined in\n * {@link module:typing/texttransformation~TextTransformationConfig#include `transformations.include`} or\n * {@link module:typing/texttransformation~TextTransformationConfig#extra `transformations.extra`}.\n *\n *\t\tconst transformationsConfig = {\n *\t\t\tremove: [\n *\t\t\t\t'ellipsis',    // Remove only 'ellipsis' from the 'typography' group.\n *\t\t\t\t'mathematical' // Remove all transformations from the 'mathematical' group.\n *\t\t\t]\n *\t\t}\n *\n * @member {Array.<module:typing/texttransformation~TextTransformationDescription>} module:typing/texttransformation~TextTransformationConfig#remove\n */\n/* eslint-enable max-len */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n// The editor creator to use.\nimport ClassicEditorBase from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';\n\nimport Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';\nimport UploadAdapter from '@ckeditor/ckeditor5-adapter-ckfinder/src/uploadadapter';\nimport Autoformat from '@ckeditor/ckeditor5-autoformat/src/autoformat';\nimport Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';\nimport Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';\nimport BlockQuote from '@ckeditor/ckeditor5-block-quote/src/blockquote';\nimport CKFinder from '@ckeditor/ckeditor5-ckfinder/src/ckfinder';\nimport EasyImage from '@ckeditor/ckeditor5-easy-image/src/easyimage';\nimport Heading from '@ckeditor/ckeditor5-heading/src/heading';\nimport Image from '@ckeditor/ckeditor5-image/src/image';\nimport ImageCaption from '@ckeditor/ckeditor5-image/src/imagecaption';\nimport ImageStyle from '@ckeditor/ckeditor5-image/src/imagestyle';\nimport ImageToolbar from '@ckeditor/ckeditor5-image/src/imagetoolbar';\nimport ImageUpload from '@ckeditor/ckeditor5-image/src/imageupload';\nimport Indent from '@ckeditor/ckeditor5-indent/src/indent';\nimport Link from '@ckeditor/ckeditor5-link/src/link';\nimport List from '@ckeditor/ckeditor5-list/src/list';\nimport MediaEmbed from '@ckeditor/ckeditor5-media-embed/src/mediaembed';\nimport Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';\nimport PasteFromOffice from '@ckeditor/ckeditor5-paste-from-office/src/pastefromoffice';\nimport Table from '@ckeditor/ckeditor5-table/src/table';\nimport TableToolbar from '@ckeditor/ckeditor5-table/src/tabletoolbar';\nimport TextTransformation from '@ckeditor/ckeditor5-typing/src/texttransformation';\n\nexport default class ClassicEditor extends ClassicEditorBase {}\n\n// Plugins to include in the build.\nClassicEditor.builtinPlugins = [\n\tEssentials,\n\tUploadAdapter,\n\tAutoformat,\n\tBold,\n\tItalic,\n\tBlockQuote,\n\tCKFinder,\n\tEasyImage,\n\tHeading,\n\tImage,\n\tImageCaption,\n\tImageStyle,\n\tImageToolbar,\n\tImageUpload,\n\tIndent,\n\tLink,\n\tList,\n\tMediaEmbed,\n\tParagraph,\n\tPasteFromOffice,\n\tTable,\n\tTableToolbar,\n\tTextTransformation\n];\n\n// Editor configuration.\nClassicEditor.defaultConfig = {\n\ttoolbar: {\n\t\titems: [\n\t\t\t'heading',\n\t\t\t'|',\n\t\t\t'bold',\n\t\t\t'italic',\n\t\t\t'link',\n\t\t\t'bulletedList',\n\t\t\t'numberedList',\n\t\t\t'|',\n\t\t\t'indent',\n\t\t\t'outdent',\n\t\t\t'|',\n\t\t\t'imageUpload',\n\t\t\t'blockQuote',\n\t\t\t'insertTable',\n\t\t\t'mediaEmbed',\n\t\t\t'undo',\n\t\t\t'redo'\n\t\t]\n\t},\n\timage: {\n\t\ttoolbar: [\n\t\t\t'imageStyle:full',\n\t\t\t'imageStyle:side',\n\t\t\t'|',\n\t\t\t'imageTextAlternative'\n\t\t]\n\t},\n\ttable: {\n\t\tcontentToolbar: [\n\t\t\t'tableColumn',\n\t\t\t'tableRow',\n\t\t\t'mergeTableCells'\n\t\t]\n\t},\n\t// This value must be kept in sync with the language defined in webpack.config.js.\n\tlanguage: 'en'\n};\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module essentials/essentials\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';\nimport Enter from '@ckeditor/ckeditor5-enter/src/enter';\nimport ShiftEnter from '@ckeditor/ckeditor5-enter/src/shiftenter';\nimport SelectAll from '@ckeditor/ckeditor5-select-all/src/selectall';\nimport Typing from '@ckeditor/ckeditor5-typing/src/typing';\nimport Undo from '@ckeditor/ckeditor5-undo/src/undo';\n\n/**\n * A plugin including all essential editing features. It represents a set of features that enables similar functionalities\n * to a `<textarea>` element.\n *\n * It includes:\n *\n * * {@link module:clipboard/clipboard~Clipboard},\n * * {@link module:enter/enter~Enter},\n * * {@link module:select-all/selectall~SelectAll},\n * * {@link module:enter/shiftenter~ShiftEnter},\n * * {@link module:typing/typing~Typing},\n * * {@link module:undo/undo~Undo}.\n *\n * This plugin set does not define any block-level containers (such as {@link module:paragraph/paragraph~Paragraph}).\n * If your editor is supposed to handle block content, make sure to include it.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Essentials extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ Clipboard, Enter, SelectAll, ShiftEnter, Typing, Undo ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Essentials';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/bold\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport BoldEditing from './bold/boldediting';\nimport BoldUI from './bold/boldui';\n\n/**\n * The bold feature.\n *\n * For a detailed overview check the {@glink features/basic-styles Basic styles feature documentation}\n * and the {@glink api/basic-styles package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:basic-styles/bold/boldediting~BoldEditing bold editing feature}\n * and {@link module:basic-styles/bold/boldui~BoldUI bold UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Bold extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ BoldEditing, BoldUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Bold';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/italic\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ItalicEditing from './italic/italicediting';\nimport ItalicUI from './italic/italicui';\n\n/**\n * The italic feature.\n *\n * For a detailed overview check the {@glink features/basic-styles Basic styles feature documentation}\n * and the {@glink api/basic-styles package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:basic-styles/italic/italicediting~ItalicEditing} and\n * {@link module:basic-styles/italic/italicui~ItalicUI} plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Italic extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ItalicEditing, ItalicUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Italic';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module block-quote/blockquote\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport BlockQuoteEditing from './blockquoteediting';\nimport BlockQuoteUI from './blockquoteui';\n\n/**\n * The block quote plugin.\n *\n * For more information about this feature check the {@glink api/block-quote package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:block-quote/blockquoteediting~BlockQuoteEditing block quote editing feature}\n * and {@link module:block-quote/blockquoteui~BlockQuoteUI block quote UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class BlockQuote extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ BlockQuoteEditing, BlockQuoteUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'BlockQuote';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ckfinder/ckfinder\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport CKFinderUI from './ckfinderui';\nimport CKFinderEditing from './ckfinderediting';\nimport CKFinderUploadAdapter from '@ckeditor/ckeditor5-adapter-ckfinder/src/uploadadapter';\n\n/**\n * The CKFinder feature, a bridge between the CKEditor 5 WYSIWYG editor and the\n * [CKFinder](https://ckeditor.com/ckfinder) file manager and uploader.\n *\n * This is a \"glue\" plugin which enables:\n *\n * * {@link module:ckfinder/ckfinderediting~CKFinderEditing},\n * * {@link module:ckfinder/ckfinderui~CKFinderUI},\n * * {@link module:adapter-ckfinder/uploadadapter~CKFinderUploadAdapter}.\n *\n * See the {@glink features/image-upload/ckfinder \"CKFinder integration\" guide} to learn how to configure\n * and use this feature.\n *\n * Check out the {@glink features/image-upload/image-upload comprehensive \"Image upload\" guide} to learn about\n * other ways to upload images into CKEditor 5.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class CKFinder extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'CKFinder';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ CKFinderEditing, CKFinderUI, CKFinderUploadAdapter ];\n\t}\n}\n\n/**\n * The configuration of the {@link module:ckfinder/ckfinder~CKFinder CKFinder feature}.\n *\n * Read more in {@link module:ckfinder/ckfinder~CKFinderConfig}.\n *\n * @member {module:ckfinder/ckfinder~CKFinderConfig} module:core/editor/editorconfig~EditorConfig#ckfinder\n */\n\n/**\n * The configuration of the {@link module:ckfinder/ckfinder~CKFinder CKFinder feature}\n * and its {@link module:adapter-ckfinder/uploadadapter~CKFinderUploadAdapter upload adapter}.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tckfinder: {\n *\t\t\t\t\toptions: {\n *\t\t\t\t\t\tresourceType: 'Images'\n *\t\t\t\t\t}\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface CKFinderConfig\n */\n\n/**\n * The configuration options passed to the CKFinder file manager instance.\n *\n * Check the file manager [documentation](https://ckeditor.com/docs/ckfinder/ckfinder3/#!/api/CKFinder.Config-cfg-language)\n * for the complete list of options.\n *\n * @member {Object} module:ckfinder/ckfinder~CKFinderConfig#options\n */\n\n/**\n * The type of the CKFinder opener method.\n *\n * Supported types are:\n *\n * * `'modal'` &ndash; Opens CKFinder in a modal,\n * * `'popup'` &ndash; Opens CKFinder in a new \"pop-up\" window.\n *\n * Defaults to `'modal'`.\n *\n * @member {String} module:ckfinder/ckfinder~CKFinderConfig#openerMethod\n */\n\n/**\n * The path (URL) to the connector which handles the file upload in CKFinder file manager.\n * When specified, it enables the automatic upload of resources such as images inserted into the content.\n *\n * For instance, to use CKFinder's\n * [quick upload](https://ckeditor.com/docs/ckfinder/ckfinder3-php/commands.html#command_quick_upload)\n * command, your can use the following (or similar) path:\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tckfinder: {\n *\t\t\t\t\tuploadUrl: '/ckfinder/core/connector/php/connector.php?command=QuickUpload&type=Files&responseType=json'\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * Used by the {@link module:adapter-ckfinder/uploadadapter~CKFinderUploadAdapter upload adapter}.\n *\n * @member {String} module:ckfinder/ckfinder~CKFinderConfig#uploadUrl\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module easy-image/easyimage\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport CloudServicesUploadAdapter from './cloudservicesuploadadapter';\nimport Image from '@ckeditor/ckeditor5-image/src/image';\nimport ImageUpload from '@ckeditor/ckeditor5-image/src/imageupload';\n\n/**\n * The Easy Image feature, which makes the image upload in CKEditor 5 possible with virtually zero\n * server setup. A part of the [CKEditor Cloud Services](https://ckeditor.com/ckeditor-cloud-services/)\n * family.\n *\n * This is a \"glue\" plugin which enables:\n *\n * * {@link module:image/image~Image},\n * * {@link module:image/imageupload~ImageUpload},\n * * {@link module:easy-image/cloudservicesuploadadapter~CloudServicesUploadAdapter}.\n *\n * See the {@glink features/image-upload/easy-image \"Easy Image integration\" guide} to learn how to configure\n * and use this feature.\n *\n * Check out the {@glink features/image-upload/image-upload comprehensive \"Image upload\" guide} to learn about\n * other ways to upload images into CKEditor 5.\n *\n * **Note**: After enabling the Easy Image plugin you need to configure the\n * [CKEditor Cloud Services](https://ckeditor.com/ckeditor-cloud-services/)\n * integration through {@link module:cloud-services/cloudservices~CloudServicesConfig `config.cloudServices`}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class EasyImage extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [\n\t\t\tCloudServicesUploadAdapter,\n\t\t\tImage,\n\t\t\tImageUpload\n\t\t];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'EasyImage';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module heading/heading\n */\n\nimport HeadingEditing from './headingediting';\nimport HeadingUI from './headingui';\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport '../theme/heading.css';\n\n/**\n * The headings feature.\n *\n * For a detailed overview, check the {@glink features/headings Headings feature documentation}\n * and the {@glink api/heading package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:heading/headingediting~HeadingEditing heading editing feature}\n * and {@link module:heading/headingui~HeadingUI heading UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Heading extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ HeadingEditing, HeadingUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Heading';\n\t}\n}\n\n/**\n * The configuration of the heading feature. Introduced by the {@link module:heading/headingediting~HeadingEditing} feature.\n *\n * Read more in {@link module:heading/heading~HeadingConfig}.\n *\n * @member {module:heading/heading~HeadingConfig} module:core/editor/editorconfig~EditorConfig#heading\n */\n\n/**\n * The configuration of the heading feature.\n * The option is used by the {@link module:heading/headingediting~HeadingEditing} feature.\n *\n *\t\tClassicEditor\n *\t\t\t.create( {\n * \t\t\t\theading: ... // Heading feature config.\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface HeadingConfig\n */\n\n/**\n * The available heading options.\n *\n * The default value is:\n *\n *\t\tconst headingConfig = {\n *\t\t\toptions: [\n *\t\t\t\t{ model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' },\n *\t\t\t\t{ model: 'heading1', view: 'h2', title: 'Heading 1', class: 'ck-heading_heading1' },\n *\t\t\t\t{ model: 'heading2', view: 'h3', title: 'Heading 2', class: 'ck-heading_heading2' },\n *\t\t\t\t{ model: 'heading3', view: 'h4', title: 'Heading 3', class: 'ck-heading_heading3' }\n *\t\t\t]\n *\t\t};\n *\n * It defines 3 levels of headings. In the editor model they will use `heading1`, `heading2`, and `heading3` elements.\n * Their respective view elements (so the elements output by the editor) will be: `h2`, `h3`, and `h4`. This means that\n * if you choose \"Heading 1\" in the headings dropdown the editor will turn the current block to `<heading1>` in the model\n * which will result in rendering (and outputting to data) the `<h2>` element.\n *\n * The `title` and `class` properties will be used by the `headings` dropdown to render available options.\n * Usually, the first option in the headings dropdown is the \"Paragraph\" option, hence it's also defined on the list.\n * However, you don't need to define its view representation because it's handled by\n * the {@link module:paragraph/paragraph~Paragraph} feature (which is required by\n * the {@link module:heading/headingediting~HeadingEditing} feature).\n *\n * You can **read more** about configuring heading levels and **see more examples** in\n * the {@glink features/headings Headings} guide.\n *\n * Note: In the model you should always start from `heading1`, regardless of how the headings are represented in the view.\n * That's assumption is used by features like {@link module:autoformat/autoformat~Autoformat} to know which element\n * they should use when applying the first level heading.\n *\n * The defined headings are also available as values passed to the `'heading'` command under their model names.\n * For example, the below code will apply `<heading1>` to the current selection:\n *\n *\t\teditor.execute( 'heading', { value: 'heading1' } );\n *\n * @member {Array.<module:heading/heading~HeadingOption>} module:heading/heading~HeadingConfig#options\n */\n\n/**\n * Heading option descriptor.\n *\n * @typedef {Object} module:heading/heading~HeadingOption\n * @property {String} model Name of the model element to convert.\n * @property {module:engine/view/elementdefinition~ElementDefinition} view Definition of a view element to convert from/to.\n * @property {String} title The user-readable title of the option.\n * @property {String} class The class which will be added to the dropdown item representing this option.\n * @property {String} [icon] Icon used by {@link module:heading/headingbuttonsui~HeadingButtonsUI}. It can be omitted when using\n * the default configuration.\n * @extends module:engine/conversion/conversion~ConverterDefinition\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagecaption\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ImageCaptionEditing from './imagecaption/imagecaptionediting';\n\nimport '../theme/imagecaption.css';\n\n/**\n * The image caption plugin.\n *\n * For a detailed overview, check the {@glink features/image#image-captions image caption} documentation.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageCaption extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ImageCaptionEditing ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageCaption';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagestyle\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ImageStyleEditing from './imagestyle/imagestyleediting';\nimport ImageStyleUI from './imagestyle/imagestyleui';\n\n/**\n * The image style plugin.\n *\n * For a detailed overview, check the {@glink features/image#image-styles image styles} documentation.\n *\n * This is a \"glue\" plugin which loads the {@link module:image/imagestyle/imagestyleediting~ImageStyleEditing}\n * and {@link module:image/imagestyle/imagestyleui~ImageStyleUI} plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageStyle extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ImageStyleEditing, ImageStyleUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageStyle';\n\t}\n}\n\n/**\n * Available image styles.\n *\n * The default value is:\n *\n *\t\tconst imageConfig = {\n *\t\t\tstyles: [ 'full', 'side' ]\n *\t\t};\n *\n * which configures two default styles:\n *\n *  * the \"full\" style which does not apply any class, e.g. for images styled to span 100% width of the content,\n *  * the \"side\" style with the `.image-style-side` CSS class.\n *\n * See {@link module:image/imagestyle/utils~defaultStyles} to learn more about default\n * styles provided by the image feature.\n *\n * The {@link module:image/imagestyle/utils~defaultStyles default styles} can be customized,\n * e.g. to change the icon, title or CSS class of the style. The feature also provides several\n * {@link module:image/imagestyle/utils~defaultIcons default icons} to choose from.\n *\n *\t\timport customIcon from 'custom-icon.svg';\n *\n *\t\t// ...\n *\n *\t\tconst imageConfig = {\n *\t\t\tstyles: [\n *\t\t\t\t// This will only customize the icon of the \"full\" style.\n *\t\t\t\t// Note: 'right' is one of default icons provided by the feature.\n *\t\t\t\t{ name: 'full', icon: 'right' },\n *\n *\t\t\t\t// This will customize the icon, title and CSS class of the default \"side\" style.\n *\t\t\t\t{ name: 'side', icon: customIcon, title: 'My side style', className: 'custom-side-image' }\n *\t\t\t]\n *\t\t};\n *\n * If none of the default styles is good enough, it is possible to define independent custom styles, too:\n *\n *\t\timport fullSizeIcon from '@ckeditor/ckeditor5-core/theme/icons/object-center.svg';\n *\t\timport sideIcon from '@ckeditor/ckeditor5-core/theme/icons/object-right.svg';\n *\n *\t\t// ...\n *\n *\t\tconst imageConfig = {\n *\t\t\tstyles: [\n *\t\t\t\t// A completely custom full size style with no class, used as a default.\n *\t\t\t\t{ name: 'fullSize', title: 'Full size', icon: fullSizeIcon, isDefault: true },\n *\n *\t\t\t\t{ name: 'side', title: 'To the side', icon: sideIcon, className: 'side-image' }\n *\t\t\t]\n *\t\t};\n *\n * Note: Setting `title` to one of {@link module:image/imagestyle/imagestyleui~ImageStyleUI#localizedDefaultStylesTitles}\n * will automatically translate it to the language of the editor.\n *\n * Read more about styling images in the {@glink features/image#image-styles Image styles guide}.\n *\n * The feature creates commands based on defined styles, so you can change the style of a selected image by executing\n * the following command:\n *\n *\t\teditor.execute( 'imageStyle' { value: 'side' } );\n *\n * The feature also creates buttons that execute the commands. So, assuming that you use the\n * default image styles setting, you can {@link module:image/image~ImageConfig#toolbar configure the image toolbar}\n * (or any other toolbar) to contain these options:\n *\n *\t\tconst imageConfig = {\n *\t\t\ttoolbar: [ 'imageStyle:full', 'imageStyle:side' ]\n *\t\t};\n *\n * @member {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} module:image/image~ImageConfig#styles\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagetoolbar\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport { getSelectedImageWidget } from './image/utils';\nimport WidgetToolbarRepository from '@ckeditor/ckeditor5-widget/src/widgettoolbarrepository';\n\n/**\n * The image toolbar plugin. It creates and manages the image toolbar (the toolbar displayed when an image is selected).\n *\n * For a detailed overview, check the {@glink features/image#image-contextual-toolbar image contextual toolbar} documentation.\n *\n * Instances of toolbar components (e.g. buttons) are created using the editor's\n * {@link module:ui/componentfactory~ComponentFactory component factory}\n * based on the {@link module:image/image~ImageConfig#toolbar `image.toolbar` configuration option}.\n *\n * The toolbar uses the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageToolbar extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ WidgetToolbarRepository ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageToolbar';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\t\tconst widgetToolbarRepository = editor.plugins.get( WidgetToolbarRepository );\n\n\t\twidgetToolbarRepository.register( 'image', {\n\t\t\tariaLabel: t( 'Image toolbar' ),\n\t\t\titems: editor.config.get( 'image.toolbar' ) || [],\n\t\t\tgetRelatedElement: getSelectedImageWidget\n\t\t} );\n\t}\n}\n\n/**\n * Items to be placed in the image toolbar.\n * This option is used by the {@link module:image/imagetoolbar~ImageToolbar} feature.\n *\n * Assuming that you use the following features:\n *\n * * {@link module:image/imagestyle~ImageStyle} (with a default configuration),\n * * {@link module:image/imagetextalternative~ImageTextAlternative},\n *\n * three toolbar items will be available in {@link module:ui/componentfactory~ComponentFactory}:\n * `'imageStyle:full'`, `'imageStyle:side'`, and `'imageTextAlternative'` so you can configure the toolbar like this:\n *\n *\t\tconst imageConfig = {\n *\t\t\ttoolbar: [ 'imageStyle:full', 'imageStyle:side', '|', 'imageTextAlternative' ]\n *\t\t};\n *\n * Of course, the same buttons can also be used in the\n * {@link module:core/editor/editorconfig~EditorConfig#toolbar main editor toolbar}.\n *\n * Read more about configuring toolbar in {@link module:core/editor/editorconfig~EditorConfig#toolbar}.\n *\n * @member {Array.<String>} module:image/image~ImageConfig#toolbar\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module indent/indent\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport IndentEditing from './indentediting';\nimport IndentUI from './indentui';\n\n/**\n * The indent feature.\n *\n * This plugin acts as a single entry point plugin for other features that implement indentation of elements like lists or paragraphs.\n *\n * The compatible features are:\n *\n * * The {@link module:list/list~List} or {@link module:list/listediting~ListEditing} feature for list indentation.\n * * The {@link module:indent/indentblock~IndentBlock} feature for block indentation.\n *\n * This is a \"glue\" plugin that loads the following plugins:\n *\n * * The {@link module:indent/indentediting~IndentEditing indent editing feature}.\n * * The {@link module:indent/indentui~IndentUI indent UI feature}.\n *\n * The dependent plugins register the `'indent'` and `'outdent'` commands and introduce the `'indent'` and `'outdent'` buttons\n * that allow to increase or decrease text indentation of supported elements.\n *\n * **Note**: In order for the commands and buttons to work, at least one of compatible features is required.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Indent extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Indent';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ IndentEditing, IndentUI ];\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module link/link\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport LinkEditing from './linkediting';\nimport LinkUI from './linkui';\nimport AutoLink from './autolink';\n\n/**\n * The link plugin.\n *\n * This is a \"glue\" plugin that loads the {@link module:link/linkediting~LinkEditing link editing feature}\n * and {@link module:link/linkui~LinkUI link UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Link extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ LinkEditing, LinkUI, AutoLink ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Link';\n\t}\n}\n\n/**\n * The configuration of the {@link module:link/link~Link} feature.\n *\n * Read more in {@link module:link/link~LinkConfig}.\n *\n * @member {module:link/link~LinkConfig} module:core/editor/editorconfig~EditorConfig#link\n */\n\n/**\n * The configuration of the {@link module:link/link~Link link feature}.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\tlink:  ... // Link feature configuration.\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n * @interface LinkConfig\n */\n\n/**\n * When set, the editor will add the given protocol to the link when the user creates a link without one.\n * For example, when the user is creating a link and types `ckeditor.com` in the link form input, during link submission\n * the editor will automatically add the `http://` protocol, so the link will look as follows: `http://ckeditor.com`.\n *\n * The feature also provides email address auto-detection. When you submit `hello@example.com`,\n * the plugin will automatically change it to `mailto:hello@example.com`.\n *\n * \t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\tlink: {\n * \t\t\t\t\tdefaultProtocol: 'http://'\n * \t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * **NOTE:** If no configuration is provided, the editor will not auto-fix the links.\n *\n * @member {String} module:link/link~LinkConfig#defaultProtocol\n */\n\n/**\n * When set to `true`, the `target=\"blank\"` and `rel=\"noopener noreferrer\"` attributes are automatically added to all external links\n * in the editor. \"External links\" are all links in the editor content starting with `http`, `https`, or `//`.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tlink: {\n *\t\t\t\t\taddTargetToExternalLinks: true\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * Internally, this option activates a predefined {@link module:link/link~LinkConfig#decorators automatic link decorator}\n * that extends all external links with the `target` and `rel` attributes.\n *\n * **Note**: To control the `target` and `rel` attributes of specific links in the edited content, a dedicated\n * {@link module:link/link~LinkDecoratorManualDefinition manual} decorator must be defined in the\n * {@link module:link/link~LinkConfig#decorators `config.link.decorators`} array. In such scenario,\n * the `config.link.addTargetToExternalLinks` option should remain `undefined` or `false` to not interfere with the manual decorator.\n *\n * It is possible to add other {@link module:link/link~LinkDecoratorAutomaticDefinition automatic}\n * or {@link module:link/link~LinkDecoratorManualDefinition manual} link decorators when this option is active.\n *\n * More information about decorators can be found in the {@link module:link/link~LinkConfig#decorators decorators configuration}\n * reference.\n *\n * @default false\n * @member {Boolean} module:link/link~LinkConfig#addTargetToExternalLinks\n */\n\n/**\n * Decorators provide an easy way to configure and manage additional link attributes in the editor content. There are\n * two types of link decorators:\n *\n * * {@link module:link/link~LinkDecoratorAutomaticDefinition Automatic} &ndash; They match links against pre–defined rules and\n * manage their attributes based on the results.\n * * {@link module:link/link~LinkDecoratorManualDefinition Manual} &ndash; They allow users to control link attributes individually,\n *  using the editor UI.\n *\n * Link decorators are defined as objects with key-value pairs, where the key is the name provided for a given decorator and the\n * value is the decorator definition.\n *\n * The name of the decorator also corresponds to the {@glink framework/guides/architecture/editing-engine#text-attributes text attribute}\n * in the model. For instance, the `isExternal` decorator below is represented as a `linkIsExternal` attribute in the model.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tlink: {\n *\t\t\t\t\tdecorators: {\n *\t\t\t\t\t\tisExternal: {\n *\t\t\t\t\t\t\tmode: 'automatic',\n *\t\t\t\t\t\t\tcallback: url => url.startsWith( 'http://' ),\n *\t\t\t\t\t\t\tattributes: {\n *\t\t\t\t\t\t\t\ttarget: '_blank',\n *\t\t\t\t\t\t\t\trel: 'noopener noreferrer'\n *\t\t\t\t\t\t\t}\n *\t\t\t\t\t\t},\n *\t\t\t\t\t\tisDownloadable: {\n *\t\t\t\t\t\t\tmode: 'manual',\n *\t\t\t\t\t\t\tlabel: 'Downloadable',\n *\t\t\t\t\t\t\tattributes: {\n *\t\t\t\t\t\t\t\tdownload: 'file.png',\n *\t\t\t\t\t\t\t}\n *\t\t\t\t\t\t},\n *\t\t\t\t\t\t// ...\n *\t\t\t\t\t}\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * To learn more about the configuration syntax, check out the {@link module:link/link~LinkDecoratorAutomaticDefinition automatic}\n * and {@link module:link/link~LinkDecoratorManualDefinition manual} decorator option reference.\n *\n * **Warning:** Currently, link decorators work independently of one another and no conflict resolution mechanism exists.\n * For example, configuring the `target` attribute using both an automatic and a manual decorator at the same time could end up with\n * quirky results. The same applies if multiple manual or automatic decorators were defined for the same attribute.\n *\n * **Note**: Since the `target` attribute management for external links is a common use case, there is a predefined automatic decorator\n * dedicated for that purpose which can be enabled by turning a single option on. Check out the\n * {@link module:link/link~LinkConfig#addTargetToExternalLinks `config.link.addTargetToExternalLinks`}\n * configuration description to learn more.\n *\n * See also the {@glink features/link#custom-link-attributes-decorators link feature guide} for more information.\n *\n * @member {Object.<String, module:link/link~LinkDecoratorDefinition>} module:link/link~LinkConfig#decorators\n */\n\n/**\n * A link decorator definition. Two types implement this defition:\n *\n * * {@link module:link/link~LinkDecoratorManualDefinition}\n * * {@link module:link/link~LinkDecoratorAutomaticDefinition}\n *\n * Refer to their document for more information about available options or to the\n * {@glink features/link#custom-link-attributes-decorators link feature guide} for general information.\n *\n * @interface LinkDecoratorDefinition\n */\n\n/**\n * Link decorator type.\n *\n * Check out the {@glink features/link#custom-link-attributes-decorators link feature guide} for more information.\n *\n * @member {'manual'|'automatic'} module:link/link~LinkDecoratorDefinition#mode\n */\n\n/**\n * Describes an automatic {@link module:link/link~LinkConfig#decorators link decorator}. This decorator type matches\n * all links in the editor content against a function that decides whether the link should receive a pre–defined set of attributes.\n *\n * It takes an object with key-value pairs of attributes and a callback function that must return a Boolean value based on the link's\n * `href` (URL). When the callback returns `true`, attributes are applied to the link.\n *\n * For example, to add the `target=\"_blank\"` attribute to all links in the editor starting with `http://`, the\n * configuration could look like this:\n *\n *\t\t{\n *\t\t\tmode: 'automatic',\n *\t\t\tcallback: url => url.startsWith( 'http://' ),\n *\t\t\tattributes: {\n *\t\t\t\ttarget: '_blank'\n *\t\t\t}\n *\t\t}\n *\n * **Note**: Since the `target` attribute management for external links is a common use case, there is a predefined automatic decorator\n * dedicated for that purpose that can be enabled by turning a single option on. Check out the\n * {@link module:link/link~LinkConfig#addTargetToExternalLinks `config.link.addTargetToExternalLinks`}\n * configuration description to learn more.\n *\n * @typedef {Object} module:link/link~LinkDecoratorAutomaticDefinition\n * @property {'automatic'} mode Link decorator type. It is `'automatic'` for all automatic decorators.\n * @property {Function} callback Takes a `url` as a parameter and returns `true` if the `attributes` should be applied to the link.\n * @property {Object} attributes Key-value pairs used as link attributes added to the output during the\n * {@glink framework/guides/architecture/editing-engine#conversion downcasting}.\n * Attributes should follow the {@link module:engine/view/elementdefinition~ElementDefinition} syntax.\n */\n\n/**\n * Describes a manual {@link module:link/link~LinkConfig#decorators link decorator}. This decorator type is represented in\n * the link feature's {@link module:link/linkui user interface} as a switch that the user can use to control the presence\n * of a predefined set of attributes.\n *\n * For instance, to allow the users to manually control the presence of the `target=\"_blank\"` and\n * `rel=\"noopener noreferrer\"` attributes on specific links, the decorator could look as follows:\n *\n *\t\t{\n *\t\t\tmode: 'manual',\n *\t\t\tlabel: 'Open in a new tab',\n *\t\t\tdefaultValue: true,\n *\t\t\tattributes: {\n *\t\t\t\ttarget: '_blank',\n *\t\t\t\trel: 'noopener noreferrer'\n *\t\t\t}\n *\t\t}\n *\n * @typedef {Object} module:link/link~LinkDecoratorManualDefinition\n * @property {'manual'} mode Link decorator type. It is `'manual'` for all manual decorators.\n * @property {String} label The label of the UI button that the user can use to control the presence of link attributes.\n * @property {Object} attributes Key-value pairs used as link attributes added to the output during the\n * {@glink framework/guides/architecture/editing-engine#conversion downcasting}.\n * Attributes should follow the {@link module:engine/view/elementdefinition~ElementDefinition} syntax.\n * @property {Boolean} [defaultValue] Controls whether the decorator is \"on\" by default.\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module list/list\n */\n\nimport ListEditing from './listediting';\nimport ListUI from './listui';\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\n/**\n * The list feature.\n *\n * This is a \"glue\" plugin that loads the {@link module:list/listediting~ListEditing list editing feature}\n * and {@link module:list/listui~ListUI list UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class List extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ListEditing, ListUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'List';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module media-embed/mediaembed\n */\n\nimport MediaEmbedEditing from './mediaembedediting';\nimport AutoMediaEmbed from './automediaembed';\nimport MediaEmbedUI from './mediaembedui';\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Widget from '@ckeditor/ckeditor5-widget/src/widget';\n\nimport '../theme/mediaembed.css';\n\n/**\n * The media embed plugin.\n *\n * For a detailed overview, check the {@glink features/media-embed Media Embed feature documentation}.\n *\n * This is a \"glue\" plugin which loads the following plugins:\n *\n * * The {@link module:media-embed/mediaembedediting~MediaEmbedEditing media embed editing feature},\n * * The {@link module:media-embed/mediaembedui~MediaEmbedUI media embed UI feature} and\n * * The {@link module:media-embed/automediaembed~AutoMediaEmbed auto-media embed feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class MediaEmbed extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ MediaEmbedEditing, MediaEmbedUI, AutoMediaEmbed, Widget ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'MediaEmbed';\n\t}\n}\n\n/**\n * The media embed provider descriptor. Used in\n * {@link module:media-embed/mediaembed~MediaEmbedConfig#providers `config.mediaEmbed.providers`} and\n * {@link module:media-embed/mediaembed~MediaEmbedConfig#extraProviders `config.mediaEmbed.extraProviders`}.\n *\n * See {@link module:media-embed/mediaembed~MediaEmbedConfig} to learn more.\n *\n *\t\t{\n *\t\t\tname: 'example',\n *\n *\t\t\t// The following RegExp matches https://www.example.com/media/{media id},\n *\t\t\t// (either with \"http(s)://\" and \"www\" or without), so the valid URLs are:\n *\t\t\t//\n *\t\t\t// * https://www.example.com/media/{media id},\n *\t\t\t// * http://www.example.com/media/{media id},\n *\t\t\t// * www.example.com/media/{media id},\n *\t\t\t// * example.com/media/{media id}\n *\t\t\turl: /^example\\.com\\/media\\/(\\w+)/,\n *\n *\t\t\t// The rendering function of the provider.\n *\t\t\t// Used to represent the media when editing the content (i.e. in the view)\n *\t\t\t// and also in the data output of the editor if semantic data output is disabled.\n *\t\t\thtml: match => `The HTML representing the media with ID=${ match[ 1 ] }.`\n *\t\t}\n *\n * You can allow any sort of media in the editor using the \"allow–all\" `RegExp`.\n * But mind that, since URLs are processed in the order of configuration, if one of the previous\n * `RegExps` matches the URL, it will have a precedence over this one.\n *\n *\t\t{\n *\t\t\tname: 'allow-all',\n *\t\t\turl: /^.+/\n *\t\t}\n *\n * To implement responsive media, you can use the following HTML structure:\n *\n *\t\t{\n *\t\t\t...\n *\t\t\thtml: match =>\n *\t\t\t\t'<div style=\"position:relative; padding-bottom:100%; height:0\">' +\n *\t\t\t\t\t'<iframe src=\"...\" frameborder=\"0\" ' +\n *\t\t\t\t\t\t'style=\"position:absolute; width:100%; height:100%; top:0; left:0\">' +\n *\t\t\t\t\t'</iframe>' +\n *\t\t\t\t'</div>'\n *\t\t}\n *\n * @typedef {Object} module:media-embed/mediaembed~MediaEmbedProvider\n * @property {String} name The name of the provider. Used e.g. when\n * {@link module:media-embed/mediaembed~MediaEmbedConfig#removeProviders removing providers}.\n * @property {RegExp|Array.<RegExp>} url The `RegExp` object (or array of objects) defining the URL of the media.\n * If any URL matches the `RegExp`, it becomes the media in the editor model, as defined by the provider. The result\n * of matching (output of `String.prototype.match()`) is passed to the `html` rendering function of the media.\n *\n * **Note:** You do not need to include the protocol (`http://`, `https://`) and `www` subdomain in your `RegExps`,\n * they are stripped from the URLs before matching anyway.\n * @property {Function} [html] (optional) The rendering function of the media. The function receives the entire matching\n * array from the corresponding `url` `RegExp` as an argument, allowing rendering a dedicated\n * preview of the media identified by a certain ID or a hash. When not defined, the media embed feature\n * will use a generic media representation in the view and output data.\n * Note that when\n * {@link module:media-embed/mediaembed~MediaEmbedConfig#previewsInData `config.mediaEmbed.previewsInData`}\n * is `true`, the rendering function **will always** be used for the media in the editor data output.\n */\n\n/**\n * The configuration of the {@link module:media-embed/mediaembed~MediaEmbed} feature.\n *\n * Read more in {@link module:media-embed/mediaembed~MediaEmbedConfig}.\n *\n * @member {module:media-embed/mediaembed~MediaEmbedConfig} module:core/editor/editorconfig~EditorConfig#mediaEmbed\n */\n\n/**\n * The configuration of the media embed features.\n *\n * Read more about {@glink features/media-embed#configuration configuring the media embed feature}.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\tmediaEmbed: ... // Media embed feature options.\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface MediaEmbedConfig\n */\n\n/**\n * The default media providers supported by the editor.\n *\n * The names of providers with rendering functions (previews):\n *\n * * \"dailymotion\",\n * * \"spotify\",\n * * \"youtube\",\n * * \"vimeo\"\n *\n * The names of providers without rendering functions:\n *\n * * \"instagram\",\n * * \"twitter\",\n * * \"googleMaps\",\n * * \"flickr\",\n * * \"facebook\"\n *\n * See the {@link module:media-embed/mediaembed~MediaEmbedProvider provider syntax} to learn more about\n * different kinds of media and media providers.\n *\n * **Note**: The default media provider configuration may not support all possible media URLs,\n * only the most common are included.\n *\n * Media without rendering functions are always represented in the data using the \"semantic\" markup. See\n * {@link module:media-embed/mediaembed~MediaEmbedConfig#previewsInData `config.mediaEmbed.previewsInData`} to\n * learn more about possible data outputs.\n *\n * The priority of media providers corresponds to the order of configuration. The first provider\n * to match the URL is always used, even if there are other providers that support a particular URL.\n * The URL is never matched against the remaining providers.\n *\n * To discard **all** default media providers, simply override this configuration with your own\n * {@link module:media-embed/mediaembed~MediaEmbedProvider definitions}:\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tplugins: [ MediaEmbed, ... ],\n *\t\t\t\tmediaEmbed: {\n *\t\t\t\t\tproviders: [\n *\t\t\t\t\t\t{\n *\t\t\t\t\t\t\t name: 'myProvider',\n *\t\t\t\t\t\t\t url: /^example\\.com\\/media\\/(\\w+)/,\n *\t\t\t\t\t\t\t html: match => '...'\n *\t\t\t\t\t\t},\n *\t\t\t\t\t\t...\n * \t\t\t\t\t]\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * You can take inspiration from the default configuration of this feature which you can find in:\n * https://github.com/ckeditor/ckeditor5-media-embed/blob/master/src/mediaembedediting.js\n *\n * To **extend** the list of default providers, use\n * {@link module:media-embed/mediaembed~MediaEmbedConfig#extraProviders `config.mediaEmbed.extraProviders`}.\n *\n * To **remove** certain providers, use\n * {@link module:media-embed/mediaembed~MediaEmbedConfig#removeProviders `config.mediaEmbed.removeProviders`}.\n *\n * @member {Array.<module:media-embed/mediaembed~MediaEmbedProvider>} module:media-embed/mediaembed~MediaEmbedConfig#providers\n */\n\n/**\n * The additional media providers supported by the editor. This configuration helps extend the default\n * {@link module:media-embed/mediaembed~MediaEmbedConfig#providers}.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tplugins: [ MediaEmbed, ... ],\n *\t\t\t\tmediaEmbed: {\n *\t\t\t\t\textraProviders: [\n *\t\t\t\t\t\t{\n *\t\t\t\t\t\t\t name: 'extraProvider',\n *\t\t\t\t\t\t\t url: /^example\\.com\\/media\\/(\\w+)/,\n *\t\t\t\t\t\t\t html: match => '...'\n *\t\t\t\t\t\t},\n *\t\t\t\t\t\t...\n * \t\t\t\t\t]\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See the {@link module:media-embed/mediaembed~MediaEmbedProvider provider syntax} to learn more.\n *\n * @member {Array.<module:media-embed/mediaembed~MediaEmbedProvider>} module:media-embed/mediaembed~MediaEmbedConfig#extraProviders\n */\n\n/**\n * The list of media providers that should not be used despite being available in\n * {@link module:media-embed/mediaembed~MediaEmbedConfig#providers `config.mediaEmbed.providers`} and\n * {@link module:media-embed/mediaembed~MediaEmbedConfig#extraProviders `config.mediaEmbed.extraProviders`}\n *\n *\t\tmediaEmbed: {\n *\t\t\tremoveProviders: [ 'youtube', 'twitter' ]\n *\t\t}\n *\n * @member {Array.<String>} module:media-embed/mediaembed~MediaEmbedConfig#removeProviders\n */\n\n/**\n * Controls the data format produced by the feature.\n *\n * When `false` (default), the feature produces \"semantic\" data, i.e. it does not include the preview of\n * the media, just the `<oembed>` tag with the `url` attribute:\n *\n *\t\t<figure class=\"media\">\n *\t\t\t<oembed url=\"https://url\"></oembed>\n *\t\t</figure>\n *\n * When `true`, the media is represented in the output in the same way it looks in the editor,\n * i.e. the media preview is saved to the database:\n *\n *\t\t<figure class=\"media\">\n *\t\t\t<div data-oembed-url=\"https://url\">\n *\t\t\t\t<iframe src=\"https://preview\"></iframe>\n *\t\t\t</div>\n *\t\t</figure>\n *\n * **Note:** Media without preview are always represented in the data using the \"semantic\" markup\n * regardless of the value of the `previewsInData`. Learn more about different kinds of media\n * in the {@link module:media-embed/mediaembed~MediaEmbedConfig#providers `config.mediaEmbed.providers`}\n * configuration description.\n *\n * @member {Boolean} [module:media-embed/mediaembed~MediaEmbedConfig#previewsInData=false]\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/pastefromoffice\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport GoogleDocsNormalizer from './normalizers/googledocsnormalizer';\nimport MSWordNormalizer from './normalizers/mswordnormalizer';\nimport Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';\n\n/**\n * The Paste from Office plugin.\n *\n * This plugin handles content pasted from Office apps and transforms it (if necessary)\n * to a valid structure which can then be understood by the editor features.\n *\n * Transformation is made by a set of predefined {@link module:paste-from-office/normalizer~Normalizer normalizers}.\n * This plugin includes following normalizers:\n *   * {@link module:paste-from-office/normalizers/mswordnormalizer~MSWordNormalizer Microsoft Word normalizer}\n *   * {@link module:paste-from-office/normalizers/googledocsnormalizer~GoogleDocsNormalizer Google Docs normalizer}\n *\n * For more information about this feature check the {@glink api/paste-from-office package page}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class PasteFromOffice extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'PasteFromOffice';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ Clipboard ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst viewDocument = editor.editing.view.document;\n\t\tconst normalizers = [];\n\n\t\tnormalizers.push( new MSWordNormalizer( viewDocument ) );\n\t\tnormalizers.push( new GoogleDocsNormalizer( viewDocument ) );\n\n\t\teditor.plugins.get( 'Clipboard' ).on(\n\t\t\t'inputTransformation',\n\t\t\t( evt, data ) => {\n\t\t\t\tif ( data.isTransformedWithPasteFromOffice ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst htmlString = data.dataTransfer.getData( 'text/html' );\n\t\t\t\tconst activeNormalizer = normalizers.find( normalizer => normalizer.isActive( htmlString ) );\n\n\t\t\t\tif ( activeNormalizer ) {\n\t\t\t\t\tactiveNormalizer.execute( data );\n\n\t\t\t\t\tdata.isTransformedWithPasteFromOffice = true;\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ priority: 'high' }\n\t\t);\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/table\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport TableEditing from './tableediting';\nimport TableUI from './tableui';\nimport TableSelection from './tableselection';\nimport TableClipboard from './tableclipboard';\nimport TableKeyboard from './tablekeyboard';\nimport TableMouse from './tablemouse';\nimport Widget from '@ckeditor/ckeditor5-widget/src/widget';\n\nimport '../theme/table.css';\n\n/**\n * The table plugin.\n *\n * For a detailed overview, check the {@glink features/table Table feature documentation}.\n *\n * This is a \"glue\" plugin that loads the following table features:\n *\n * * {@link module:table/tableediting~TableEditing editing feature},\n * * {@link module:table/tableselection~TableSelection selection feature},\n * * {@link module:table/tablekeyboard~TableKeyboard keyboard navigation feature},\n * * {@link module:table/tablemouse~TableMouse mouse selection feature},\n * * {@link module:table/tableclipboard~TableClipboard clipboard feature},\n * * {@link module:table/tableui~TableUI UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Table extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableEditing, TableUI, TableSelection, TableMouse, TableKeyboard, TableClipboard, Widget ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Table';\n\t}\n}\n\n/**\n * The configuration of the table feature. Used by the table feature in the `@ckeditor/ckeditor5-table` package.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\ttable: ... // Table feature options.\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface TableConfig\n */\n\n/**\n * The configuration of the {@link module:table/table~Table} feature.\n *\n * Read more in {@link module:table/table~TableConfig}.\n *\n * @member {module:table/table~TableConfig} module:core/editor/editorconfig~EditorConfig#table\n */\n\n/**\n * An array of color definitions (either strings or objects).\n *\n *\t\tconst colors = [\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(0, 0%, 60%)',\n *\t\t\t\tlabel: 'Grey'\n *\t\t\t},\n *\t\t\t'hsl(0, 0%, 80%)',\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(0, 0%, 90%)',\n *\t\t\t\tlabel: 'Light grey'\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(0, 0%, 100%)',\n *\t\t\t\tlabel: 'White',\n *\t\t\t\thasBorder: true\n *\t\t\t},\n *\t\t\t'#FF0000'\n *\t\t]\n *\n * Usually used as a configuration parameter, for instance in\n * {@link module:table/table~TableConfig#tableProperties `config.table.tableProperties`}\n * or {@link module:table/table~TableConfig#tableCellProperties `config.table.tableCellProperties`}.\n *\n * @typedef {Array.<String|Object>} module:table/table~TableColorConfig\n */\n","/**\n * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tabletoolbar\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport WidgetToolbarRepository from '@ckeditor/ckeditor5-widget/src/widgettoolbarrepository';\nimport { getSelectedTableWidget, getTableWidgetAncestor } from './utils/ui/widget';\n\n/**\n * The table toolbar class. It creates toolbars for the table feature and its content (for now only for the table cell content).\n *\n * The table toolbar shows up when a table widget is selected. Its components (e.g. buttons) are created based on the\n * {@link module:table/table~TableConfig#tableToolbar `table.tableToolbar` configuration option}.\n *\n * Table content toolbar shows up when the selection is inside the content of a table. It creates its component based on the\n * {@link module:table/table~TableConfig#contentToolbar `table.contentToolbar` configuration option}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableToolbar extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ WidgetToolbarRepository ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableToolbar';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\t\tconst widgetToolbarRepository = editor.plugins.get( WidgetToolbarRepository );\n\n\t\tconst tableContentToolbarItems = editor.config.get( 'table.contentToolbar' );\n\n\t\tconst tableToolbarItems = editor.config.get( 'table.tableToolbar' );\n\n\t\tif ( tableContentToolbarItems ) {\n\t\t\twidgetToolbarRepository.register( 'tableContent', {\n\t\t\t\tariaLabel: t( 'Table toolbar' ),\n\t\t\t\titems: tableContentToolbarItems,\n\t\t\t\tgetRelatedElement: getTableWidgetAncestor\n\t\t\t} );\n\t\t}\n\n\t\tif ( tableToolbarItems ) {\n\t\t\twidgetToolbarRepository.register( 'table', {\n\t\t\t\tariaLabel: t( 'Table toolbar' ),\n\t\t\t\titems: tableToolbarItems,\n\t\t\t\tgetRelatedElement: getSelectedTableWidget\n\t\t\t} );\n\t\t}\n\t}\n}\n\n/**\n * Items to be placed in the table content toolbar.\n * The {@link module:table/tabletoolbar~TableToolbar} plugin is required to make this toolbar work.\n *\n * Assuming that you use the {@link module:table/tableui~TableUI} feature, the following toolbar items will be available\n * in {@link module:ui/componentfactory~ComponentFactory}:\n *\n * * `'tableRow'`,\n * * `'tableColumn'`,\n * * `'mergeTableCells'`.\n *\n * You can thus configure the toolbar like this:\n *\n *\t\tconst tableConfig = {\n *\t\t\tcontentToolbar: [ 'tableRow', 'tableColumn', 'mergeTableCells' ]\n *\t\t};\n *\n * Of course, the same buttons can also be used in the\n * {@link module:core/editor/editorconfig~EditorConfig#toolbar main editor toolbar}.\n *\n * Read more about configuring the toolbar in {@link module:core/editor/editorconfig~EditorConfig#toolbar}.\n *\n * @member {Array.<String>} module:table/table~TableConfig#contentToolbar\n */\n\n/**\n * Items to be placed in the table toolbar.\n * The {@link module:table/tabletoolbar~TableToolbar} plugin is required to make this toolbar work.\n *\n * You can thus configure the toolbar like this:\n *\n *\t\tconst tableConfig = {\n *\t\t\ttableToolbar: [ 'blockQuote' ]\n *\t\t};\n *\n * Of course, the same buttons can also be used in the\n * {@link module:core/editor/editorconfig~EditorConfig#toolbar main editor toolbar}.\n *\n * Read more about configuring the toolbar in {@link module:core/editor/editorconfig~EditorConfig#toolbar}.\n *\n * @member {Array.<String>} module:table/table~TableConfig#tableToolbar\n */\n"],"sourceRoot":""}