vue-editify 0.1.27 → 0.1.29
Sign up to get free protection for your applications and to get access to all the features.
- package/lib/core/function.d.ts +265 -0
- package/lib/core/rule.d.ts +32 -0
- package/lib/core/tool.d.ts +50 -1
- package/lib/editify.es.js +129 -65
- package/lib/editify.umd.js +1 -1
- package/lib/hljs/index.d.ts +9 -0
- package/lib/index.d.ts +1 -1
- package/lib/locale/index.d.ts +5 -0
- package/lib/plugins/attachment/index.d.ts +19 -0
- package/lib/style.css +1 -1
- package/package.json +2 -2
- package/src/components/menu/menu.vue +45 -9
- package/src/core/function.ts +265 -42
- package/src/core/rule.ts +40 -7
- package/src/core/tool.ts +51 -9
- package/src/editify/editify.less +2 -1
- package/src/editify/editify.vue +3 -11
- package/src/hljs/index.ts +9 -2
- package/src/index.ts +1 -1
- package/src/locale/index.ts +5 -2
- package/src/plugins/attachment/index.ts +101 -57
- package/vite.config.ts.timestamp-1714200628309-967ea10c27215.mjs +0 -48
package/src/core/tool.ts
CHANGED
@@ -198,8 +198,15 @@ export type MenuConfigType = {
|
|
198
198
|
extends?: MenuExtendType
|
199
199
|
}
|
200
200
|
|
201
|
+
export type PluginMenuConfigType = {
|
202
|
+
extraDisabled?: ((name: string) => boolean) | null
|
203
|
+
sequence: number
|
204
|
+
extend: MenuCustomButtonType
|
205
|
+
}
|
206
|
+
|
201
207
|
export type PluginResultType = {
|
202
|
-
|
208
|
+
name: string
|
209
|
+
menu?: PluginMenuConfigType
|
203
210
|
updateView?: () => void
|
204
211
|
customParseNode?: (element: AlexElement) => AlexElement
|
205
212
|
renderRule?: (el: AlexElement) => void
|
@@ -209,7 +216,9 @@ export type PluginResultType = {
|
|
209
216
|
|
210
217
|
export type PluginType = (editifyInstance: ComponentInternalInstance, color: string | null, editTrans: (key: string) => any) => PluginResultType
|
211
218
|
|
212
|
-
|
219
|
+
/**
|
220
|
+
* 粘贴html时保留的数据
|
221
|
+
*/
|
213
222
|
export const pasteKeepData: ObjectType = {
|
214
223
|
//粘贴html时元素保留的样式(全部元素)
|
215
224
|
marks: {
|
@@ -237,7 +246,12 @@ export const pasteKeepData: ObjectType = {
|
|
237
246
|
}
|
238
247
|
}
|
239
248
|
|
240
|
-
|
249
|
+
/**
|
250
|
+
* 对象平替值方法
|
251
|
+
* @param o1
|
252
|
+
* @param o2
|
253
|
+
* @returns
|
254
|
+
*/
|
241
255
|
export const mergeObject = function (o1: ObjectType, o2: ObjectType) {
|
242
256
|
if (!DapCommon.isObject(o1) && DapCommon.isObject(o2)) {
|
243
257
|
return null
|
@@ -255,7 +269,13 @@ export const mergeObject = function (o1: ObjectType, o2: ObjectType) {
|
|
255
269
|
return o1
|
256
270
|
}
|
257
271
|
|
258
|
-
|
272
|
+
/**
|
273
|
+
* 判断对象是否含有某个属性或者属性值是否一致
|
274
|
+
* @param obj
|
275
|
+
* @param name
|
276
|
+
* @param value
|
277
|
+
* @returns
|
278
|
+
*/
|
259
279
|
export const queryHasValue = function (obj: ObjectType, name: string, value?: string | number) {
|
260
280
|
//如果value不存在则判断是否拥有属性name
|
261
281
|
if (value == null || value == undefined) {
|
@@ -296,7 +316,11 @@ export const queryHasValue = function (obj: ObjectType, name: string, value?: st
|
|
296
316
|
return ownValue == value
|
297
317
|
}
|
298
318
|
|
299
|
-
|
319
|
+
/**
|
320
|
+
* 深拷贝函数
|
321
|
+
* @param data
|
322
|
+
* @returns
|
323
|
+
*/
|
300
324
|
export const cloneData = function (data: any) {
|
301
325
|
if (DapCommon.isObject(data) || Array.isArray(data)) {
|
302
326
|
return JSON.parse(JSON.stringify(data))
|
@@ -304,7 +328,11 @@ export const cloneData = function (data: any) {
|
|
304
328
|
return data
|
305
329
|
}
|
306
330
|
|
307
|
-
|
331
|
+
/**
|
332
|
+
* 根据行元素获取colgroup的col数量
|
333
|
+
* @param row
|
334
|
+
* @returns
|
335
|
+
*/
|
308
336
|
export const getColNumbers = function (row: AlexElement) {
|
309
337
|
const children = row.children || []
|
310
338
|
let num = 0
|
@@ -321,7 +349,11 @@ export const getColNumbers = function (row: AlexElement) {
|
|
321
349
|
return num
|
322
350
|
}
|
323
351
|
|
324
|
-
|
352
|
+
/**
|
353
|
+
* 获取菜单按钮列表数据配置
|
354
|
+
* @param editTrans
|
355
|
+
* @returns
|
356
|
+
*/
|
325
357
|
export const getButtonOptionsConfig = function (editTrans: (key: string) => any): ButtonOptionsConfigType {
|
326
358
|
return {
|
327
359
|
//标题配置
|
@@ -517,7 +549,12 @@ export const getButtonOptionsConfig = function (editTrans: (key: string) => any)
|
|
517
549
|
}
|
518
550
|
}
|
519
551
|
|
520
|
-
|
552
|
+
/**
|
553
|
+
* 工具条全量配置
|
554
|
+
* @param editTrans
|
555
|
+
* @param editLocale
|
556
|
+
* @returns
|
557
|
+
*/
|
521
558
|
export const getToolbarConfig = function (editTrans: (key: string) => any, editLocale: LocaleType): ToolbarConfigType {
|
522
559
|
return {
|
523
560
|
//是否使用工具条
|
@@ -762,7 +799,12 @@ export const getToolbarConfig = function (editTrans: (key: string) => any, editL
|
|
762
799
|
}
|
763
800
|
}
|
764
801
|
|
765
|
-
|
802
|
+
/**
|
803
|
+
* 菜单栏全量配置
|
804
|
+
* @param editTrans
|
805
|
+
* @param editLocale
|
806
|
+
* @returns
|
807
|
+
*/
|
766
808
|
export const getMenuConfig = function (editTrans: (key: string) => any, editLocale: LocaleType): MenuConfigType {
|
767
809
|
return {
|
768
810
|
//是否使用菜单栏
|
package/src/editify/editify.less
CHANGED
@@ -348,7 +348,7 @@
|
|
348
348
|
color: @font-color-link;
|
349
349
|
transition: all 200ms;
|
350
350
|
position: relative;
|
351
|
-
padding: 0
|
351
|
+
padding: 0 10px;
|
352
352
|
font-size: 14px;
|
353
353
|
vertical-align: baseline;
|
354
354
|
|
@@ -378,6 +378,7 @@
|
|
378
378
|
&.editify-placeholder::before {
|
379
379
|
cursor: auto;
|
380
380
|
}
|
381
|
+
|
381
382
|
:deep(a) {
|
382
383
|
cursor: pointer;
|
383
384
|
}
|
package/src/editify/editify.vue
CHANGED
@@ -45,8 +45,6 @@ const emits = defineEmits(['update:modelValue', 'focus', 'blur', 'change', 'keyd
|
|
45
45
|
|
46
46
|
//设置国际化方法
|
47
47
|
const $editTrans = trans(props.locale || 'zh_CN')
|
48
|
-
//对子孙后代组件提供国际化方法
|
49
|
-
provide('$editTrans', $editTrans)
|
50
48
|
|
51
49
|
//是否编辑器内部修改值
|
52
50
|
const isModelChange = ref<boolean>(false)
|
@@ -135,15 +133,7 @@ const pluginResultList = computed<PluginResultType[]>(() => {
|
|
135
133
|
})
|
136
134
|
//最终生效的菜单栏配置
|
137
135
|
const menuConfig = computed<MenuConfigType>(() => {
|
138
|
-
|
139
|
-
//注册插件:自定义菜单栏
|
140
|
-
pluginResultList.value.forEach(pluginResult => {
|
141
|
-
menu = <MenuConfigType>mergeObject(menu, pluginResult.menu || {})
|
142
|
-
})
|
143
|
-
//加入自定义menu配置
|
144
|
-
menu = <MenuConfigType>mergeObject(menu, props.menu || {})
|
145
|
-
//返回最终配置
|
146
|
-
return <MenuConfigType>mergeObject(getMenuConfig($editTrans, props.locale), menu)
|
136
|
+
return <MenuConfigType>mergeObject(getMenuConfig($editTrans, props.locale), props.menu || {})
|
147
137
|
})
|
148
138
|
|
149
139
|
//编辑器内部修改值的方法
|
@@ -841,6 +831,7 @@ onBeforeUnmount(() => {
|
|
841
831
|
editor.value!.destroy()
|
842
832
|
})
|
843
833
|
|
834
|
+
provide('$editTrans', $editTrans)
|
844
835
|
provide('editify', instance)
|
845
836
|
provide('isSourceView', isSourceView)
|
846
837
|
provide('isFullScreen', isFullScreen)
|
@@ -848,6 +839,7 @@ provide('canUseMenu', canUseMenu)
|
|
848
839
|
provide('editor', editor)
|
849
840
|
provide('dataRangeCaches', dataRangeCaches)
|
850
841
|
provide('showBorder', showBorder)
|
842
|
+
provide('pluginResultList', pluginResultList)
|
851
843
|
|
852
844
|
defineExpose({
|
853
845
|
editor,
|
package/src/hljs/index.ts
CHANGED
@@ -74,7 +74,12 @@ export type LanguagesItemType = {
|
|
74
74
|
value?: string
|
75
75
|
}
|
76
76
|
|
77
|
-
|
77
|
+
/**
|
78
|
+
* 获取经过hljs处理的html元素
|
79
|
+
* @param code
|
80
|
+
* @param language
|
81
|
+
* @returns
|
82
|
+
*/
|
78
83
|
export const getHljsHtml = function (code: string, language: string) {
|
79
84
|
if (language) {
|
80
85
|
return hljs.highlight(code, {
|
@@ -84,7 +89,9 @@ export const getHljsHtml = function (code: string, language: string) {
|
|
84
89
|
}
|
85
90
|
return hljs.highlightAuto(code).value
|
86
91
|
}
|
87
|
-
|
92
|
+
/**
|
93
|
+
* 可选择语言列表
|
94
|
+
*/
|
88
95
|
export const languages: LanguagesItemType[] = [
|
89
96
|
{
|
90
97
|
label: 'Plain Text',
|
package/src/index.ts
CHANGED
package/src/locale/index.ts
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
import { en_US } from './en_US'
|
2
2
|
import { zh_CN } from './zh_CN'
|
3
3
|
|
4
|
-
//语言类型
|
5
4
|
export type LocaleType = 'zh_CN' | 'en_US'
|
6
5
|
|
7
|
-
|
6
|
+
/**
|
7
|
+
* 翻译方法
|
8
|
+
* @param locale
|
9
|
+
* @returns
|
10
|
+
*/
|
8
11
|
export const trans = (locale: LocaleType) => {
|
9
12
|
return (key: string) => {
|
10
13
|
return { zh_CN, en_US }[locale][key]
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { ComponentInternalInstance, h } from 'vue'
|
2
|
-
import { AlexEditor, AlexElement } from 'alex-editor'
|
2
|
+
import { AlexEditor, AlexElement, AlexElementsRangeType } from 'alex-editor'
|
3
3
|
import { ObjectType, PluginType } from '../../core/tool'
|
4
4
|
import Layer from '../../components/layer/layer.vue'
|
5
5
|
import Button from '../../components/button/button.vue'
|
@@ -7,7 +7,7 @@ import Icon from '../../components/icon/icon.vue'
|
|
7
7
|
import InsertAttachment from './insertAttachment/insertAttachment.vue'
|
8
8
|
import { InsertAttachmentUploadErrorType } from './insertAttachment/props'
|
9
9
|
import { event as DapEvent, common as DapCommon } from 'dap-util'
|
10
|
-
import { hasPreInRange } from '../../core/function'
|
10
|
+
import { hasLinkInRange, hasPreInRange, hasQuoteInRange } from '../../core/function'
|
11
11
|
|
12
12
|
export type AttachmentOptionsType = {
|
13
13
|
//排序
|
@@ -34,72 +34,116 @@ export type AttachmentOptionsType = {
|
|
34
34
|
handleError?: (error: InsertAttachmentUploadErrorType, file: File) => void
|
35
35
|
}
|
36
36
|
|
37
|
+
/**
|
38
|
+
* 元素是否附件
|
39
|
+
* @param element
|
40
|
+
* @returns
|
41
|
+
*/
|
42
|
+
export const isAttachment = (element: AlexElement) => {
|
43
|
+
if (element.isEmpty()) {
|
44
|
+
return false
|
45
|
+
}
|
46
|
+
return element.parsedom == 'span' && element.type == 'closed' && element.hasMarks() && element.marks!['data-attachment']
|
47
|
+
}
|
48
|
+
|
49
|
+
/**
|
50
|
+
* 选区是否含有附件
|
51
|
+
* @param editor
|
52
|
+
* @param dataRangeCaches
|
53
|
+
* @returns
|
54
|
+
*/
|
55
|
+
export const hasAttachmentInRange = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType) => {
|
56
|
+
if (!editor.range) {
|
57
|
+
return false
|
58
|
+
}
|
59
|
+
if (editor.range.anchor.isEqual(editor.range.focus)) {
|
60
|
+
return isAttachment(editor.range.anchor.element)
|
61
|
+
}
|
62
|
+
return dataRangeCaches.flatList.some(item => {
|
63
|
+
return isAttachment(item.element)
|
64
|
+
})
|
65
|
+
}
|
66
|
+
|
67
|
+
/**
|
68
|
+
* 附件插件
|
69
|
+
* @param options
|
70
|
+
* @returns
|
71
|
+
*/
|
37
72
|
export const attachment = (options?: AttachmentOptionsType) => {
|
38
73
|
if (!DapCommon.isObject(options)) {
|
39
74
|
options = {}
|
40
75
|
}
|
41
76
|
const plugin: PluginType = (editifyInstance: ComponentInternalInstance, color: string | null, editTrans: (key: string) => any) => {
|
77
|
+
let isDisabled = false
|
78
|
+
//如果光标范围内有链接、代码块和引用则禁用
|
79
|
+
if (editifyInstance.exposed!.editor.value) {
|
80
|
+
isDisabled = hasPreInRange(editifyInstance.exposed!.editor.value, editifyInstance.exposed!.dataRangeCaches.value) || hasLinkInRange(editifyInstance.exposed!.editor.value, editifyInstance.exposed!.dataRangeCaches.value) || hasQuoteInRange(editifyInstance.exposed!.editor.value, editifyInstance.exposed!.dataRangeCaches.value)
|
81
|
+
}
|
42
82
|
return {
|
83
|
+
name: 'attachment',
|
43
84
|
//附件菜单项配置
|
44
85
|
menu: {
|
45
|
-
sequence:
|
46
|
-
|
86
|
+
sequence: options!.sequence || 100,
|
87
|
+
extraDisabled: (name: string) => {
|
88
|
+
//如果光标选区内有附件则禁用链接菜单和引用菜单
|
89
|
+
if (name == 'link' || name == 'quote') {
|
90
|
+
return hasAttachmentInRange(editifyInstance.exposed!.editor.value, editifyInstance.exposed!.dataRangeCaches.value)
|
91
|
+
}
|
92
|
+
return false
|
47
93
|
},
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
contenteditable: 'false'
|
77
|
-
}
|
78
|
-
//创建元素
|
79
|
-
const attachmentElement = new AlexElement('closed', 'span', marks, null, null)
|
80
|
-
//获取editor对象
|
81
|
-
const editor = <AlexEditor>editifyInstance.exposed!.editor.value
|
82
|
-
//插入编辑器
|
83
|
-
editor.insertElement(attachmentElement)
|
84
|
-
//创建空文本元素
|
85
|
-
const beforeText = AlexElement.getSpaceElement()
|
86
|
-
const afterText = AlexElement.getSpaceElement()
|
87
|
-
//将空白文本元素插入附件两端
|
88
|
-
editor.addElementAfter(afterText, attachmentElement)
|
89
|
-
editor.addElementBefore(beforeText, attachmentElement)
|
90
|
-
//移动光标到新插入的元素
|
91
|
-
editor.range!.anchor.moveToStart(afterText)
|
92
|
-
editor.range!.focus.moveToStart(afterText)
|
93
|
-
//渲染
|
94
|
-
editor.formatElementStack()
|
95
|
-
editor.domRender()
|
96
|
-
editor.rangeRender()
|
94
|
+
extend: {
|
95
|
+
type: 'select',
|
96
|
+
title: options!.title || editTrans('insertAttachment'),
|
97
|
+
leftBorder: options!.leftBorder,
|
98
|
+
rightBorder: options!.rightBorder,
|
99
|
+
hideScroll: true,
|
100
|
+
disabled: isDisabled,
|
101
|
+
default: () => h(Icon, { value: 'attachment' }),
|
102
|
+
layer: (_name: string, btnInstance: InstanceType<typeof Button>) =>
|
103
|
+
h(InsertAttachment, {
|
104
|
+
color: color,
|
105
|
+
accept: options!.accept,
|
106
|
+
allowedFileType: options!.allowedFileType || [],
|
107
|
+
multiple: !!options!.multiple,
|
108
|
+
maxSize: options!.maxSize,
|
109
|
+
minSize: options!.minSize,
|
110
|
+
customUpload: options!.customUpload,
|
111
|
+
handleError: options!.handleError,
|
112
|
+
onChange: () => {
|
113
|
+
;(<InstanceType<typeof Layer>>btnInstance.$refs.layerRef).setPosition()
|
114
|
+
},
|
115
|
+
onInsert: (name: string, url: string) => {
|
116
|
+
//如果地址存在
|
117
|
+
if (url) {
|
118
|
+
const marks: ObjectType = {
|
119
|
+
'data-attachment': url,
|
120
|
+
'data-attachment-name': name || editTrans('attachmentDefaultName'),
|
121
|
+
contenteditable: 'false'
|
97
122
|
}
|
98
|
-
|
99
|
-
|
123
|
+
//创建元素
|
124
|
+
const attachmentElement = new AlexElement('closed', 'span', marks, null, null)
|
125
|
+
//获取editor对象
|
126
|
+
const editor = <AlexEditor>editifyInstance.exposed!.editor.value
|
127
|
+
//插入编辑器
|
128
|
+
editor.insertElement(attachmentElement)
|
129
|
+
//创建空文本元素
|
130
|
+
const beforeText = AlexElement.getSpaceElement()
|
131
|
+
const afterText = AlexElement.getSpaceElement()
|
132
|
+
//将空白文本元素插入附件两端
|
133
|
+
editor.addElementAfter(afterText, attachmentElement)
|
134
|
+
editor.addElementBefore(beforeText, attachmentElement)
|
135
|
+
//移动光标到新插入的元素
|
136
|
+
editor.range!.anchor.moveToStart(afterText)
|
137
|
+
editor.range!.focus.moveToStart(afterText)
|
138
|
+
//渲染
|
139
|
+
editor.formatElementStack()
|
140
|
+
editor.domRender()
|
141
|
+
editor.rangeRender()
|
100
142
|
}
|
101
|
-
|
102
|
-
|
143
|
+
//关闭浮层
|
144
|
+
btnInstance.show = false
|
145
|
+
}
|
146
|
+
})
|
103
147
|
}
|
104
148
|
},
|
105
149
|
//找到附件元素点击下载
|
@@ -1,48 +0,0 @@
|
|
1
|
-
// vite.config.ts
|
2
|
-
import { defineConfig } from "file:///Users/lingkai/Desktop/%E5%89%8D%E7%AB%AF%E5%BA%93/vue-editify/node_modules/vite/dist/node/index.js";
|
3
|
-
import vue from "file:///Users/lingkai/Desktop/%E5%89%8D%E7%AB%AF%E5%BA%93/vue-editify/node_modules/@vitejs/plugin-vue/dist/index.mjs";
|
4
|
-
import dts from "file:///Users/lingkai/Desktop/%E5%89%8D%E7%AB%AF%E5%BA%93/vue-editify/node_modules/vite-plugin-dts/dist/index.mjs";
|
5
|
-
import path from "path";
|
6
|
-
var __vite_injected_original_dirname = "/Users/lingkai/Desktop/\u524D\u7AEF\u5E93/vue-editify";
|
7
|
-
var vite_config_default = defineConfig({
|
8
|
-
plugins: [vue(), dts()],
|
9
|
-
build: {
|
10
|
-
//打包后的目录名称
|
11
|
-
outDir: "lib",
|
12
|
-
minify: "terser",
|
13
|
-
lib: {
|
14
|
-
entry: path.resolve(__vite_injected_original_dirname, "src/index.ts"),
|
15
|
-
name: "editify",
|
16
|
-
fileName: (format) => `editify.${format}.js`
|
17
|
-
},
|
18
|
-
rollupOptions: {
|
19
|
-
// 确保外部化处理那些你不想打包进库的依赖
|
20
|
-
external: ["vue"],
|
21
|
-
output: {
|
22
|
-
// 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
|
23
|
-
globals: {
|
24
|
-
vue: "Vue"
|
25
|
-
},
|
26
|
-
exports: "named"
|
27
|
-
}
|
28
|
-
},
|
29
|
-
sourcemap: false
|
30
|
-
//是否构建source map 文件
|
31
|
-
},
|
32
|
-
css: {
|
33
|
-
preprocessorOptions: {
|
34
|
-
less: {
|
35
|
-
// 使用 less 编写样式的 UI 库(如 antd)时建议加入这个设置
|
36
|
-
javascriptEnabled: true,
|
37
|
-
additionalData: `@import "src/css/base.less";`
|
38
|
-
}
|
39
|
-
}
|
40
|
-
},
|
41
|
-
server: {
|
42
|
-
host: "0.0.0.0"
|
43
|
-
}
|
44
|
-
});
|
45
|
-
export {
|
46
|
-
vite_config_default as default
|
47
|
-
};
|
48
|
-
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvVXNlcnMvbGluZ2thaS9EZXNrdG9wL1x1NTI0RFx1N0FFRlx1NUU5My92dWUtZWRpdGlmeVwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL1VzZXJzL2xpbmdrYWkvRGVza3RvcC9cdTUyNERcdTdBRUZcdTVFOTMvdnVlLWVkaXRpZnkvdml0ZS5jb25maWcudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL1VzZXJzL2xpbmdrYWkvRGVza3RvcC8lRTUlODklOEQlRTclQUIlQUYlRTUlQkElOTMvdnVlLWVkaXRpZnkvdml0ZS5jb25maWcudHNcIjtpbXBvcnQgeyBkZWZpbmVDb25maWcgfSBmcm9tICd2aXRlJ1xuaW1wb3J0IHZ1ZSBmcm9tICdAdml0ZWpzL3BsdWdpbi12dWUnXG5pbXBvcnQgZHRzIGZyb20gJ3ZpdGUtcGx1Z2luLWR0cydcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnXG5cbmV4cG9ydCBkZWZhdWx0IGRlZmluZUNvbmZpZyh7XG5cdHBsdWdpbnM6IFt2dWUoKSwgZHRzKCldLFxuXHRidWlsZDoge1xuXHRcdC8vXHU2MjUzXHU1MzA1XHU1NDBFXHU3Njg0XHU3NkVFXHU1RjU1XHU1NDBEXHU3OUYwXG5cdFx0b3V0RGlyOiAnbGliJyxcblx0XHRtaW5pZnk6ICd0ZXJzZXInLFxuXHRcdGxpYjoge1xuXHRcdFx0ZW50cnk6IHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsICdzcmMvaW5kZXgudHMnKSxcblx0XHRcdG5hbWU6ICdlZGl0aWZ5Jyxcblx0XHRcdGZpbGVOYW1lOiBmb3JtYXQgPT4gYGVkaXRpZnkuJHtmb3JtYXR9LmpzYFxuXHRcdH0sXG5cdFx0cm9sbHVwT3B0aW9uczoge1xuXHRcdFx0Ly8gXHU3ODZFXHU0RkREXHU1OTE2XHU5MEU4XHU1MzE2XHU1OTA0XHU3NDA2XHU5MEEzXHU0RTlCXHU0RjYwXHU0RTBEXHU2MEYzXHU2MjUzXHU1MzA1XHU4RkRCXHU1RTkzXHU3Njg0XHU0RjlEXHU4RDU2XG5cdFx0XHRleHRlcm5hbDogWyd2dWUnXSxcblx0XHRcdG91dHB1dDoge1xuXHRcdFx0XHQvLyBcdTU3MjggVU1EIFx1Njc4NFx1NUVGQVx1NkEyMVx1NUYwRlx1NEUwQlx1NEUzQVx1OEZEOVx1NEU5Qlx1NTkxNlx1OTBFOFx1NTMxNlx1NzY4NFx1NEY5RFx1OEQ1Nlx1NjNEMFx1NEY5Qlx1NEUwMFx1NEUyQVx1NTE2OFx1NUM0MFx1NTNEOFx1OTFDRlxuXHRcdFx0XHRnbG9iYWxzOiB7XG5cdFx0XHRcdFx0dnVlOiAnVnVlJ1xuXHRcdFx0XHR9LFxuXHRcdFx0XHRleHBvcnRzOiAnbmFtZWQnXG5cdFx0XHR9XG5cdFx0fSxcblx0XHRzb3VyY2VtYXA6IGZhbHNlIC8vXHU2NjJGXHU1NDI2XHU2Nzg0XHU1RUZBc291cmNlIG1hcCBcdTY1ODdcdTRFRjZcblx0fSxcblx0Y3NzOiB7XG5cdFx0cHJlcHJvY2Vzc29yT3B0aW9uczoge1xuXHRcdFx0bGVzczoge1xuXHRcdFx0XHQvLyBcdTRGN0ZcdTc1MjggbGVzcyBcdTdGMTZcdTUxOTlcdTY4MzdcdTVGMEZcdTc2ODQgVUkgXHU1RTkzXHVGRjA4XHU1OTgyIGFudGRcdUZGMDlcdTY1RjZcdTVFRkFcdThCQUVcdTUyQTBcdTUxNjVcdThGRDlcdTRFMkFcdThCQkVcdTdGNkVcblx0XHRcdFx0amF2YXNjcmlwdEVuYWJsZWQ6IHRydWUsXG5cdFx0XHRcdGFkZGl0aW9uYWxEYXRhOiBgQGltcG9ydCBcInNyYy9jc3MvYmFzZS5sZXNzXCI7YFxuXHRcdFx0fVxuXHRcdH1cblx0fSxcblx0c2VydmVyOiB7XG5cdFx0aG9zdDogJzAuMC4wLjAnXG5cdH1cbn0pXG4iXSwKICAibWFwcGluZ3MiOiAiO0FBQTRULFNBQVMsb0JBQW9CO0FBQ3pWLE9BQU8sU0FBUztBQUNoQixPQUFPLFNBQVM7QUFDaEIsT0FBTyxVQUFVO0FBSGpCLElBQU0sbUNBQW1DO0FBS3pDLElBQU8sc0JBQVEsYUFBYTtBQUFBLEVBQzNCLFNBQVMsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDO0FBQUEsRUFDdEIsT0FBTztBQUFBO0FBQUEsSUFFTixRQUFRO0FBQUEsSUFDUixRQUFRO0FBQUEsSUFDUixLQUFLO0FBQUEsTUFDSixPQUFPLEtBQUssUUFBUSxrQ0FBVyxjQUFjO0FBQUEsTUFDN0MsTUFBTTtBQUFBLE1BQ04sVUFBVSxZQUFVLFdBQVcsTUFBTTtBQUFBLElBQ3RDO0FBQUEsSUFDQSxlQUFlO0FBQUE7QUFBQSxNQUVkLFVBQVUsQ0FBQyxLQUFLO0FBQUEsTUFDaEIsUUFBUTtBQUFBO0FBQUEsUUFFUCxTQUFTO0FBQUEsVUFDUixLQUFLO0FBQUEsUUFDTjtBQUFBLFFBQ0EsU0FBUztBQUFBLE1BQ1Y7QUFBQSxJQUNEO0FBQUEsSUFDQSxXQUFXO0FBQUE7QUFBQSxFQUNaO0FBQUEsRUFDQSxLQUFLO0FBQUEsSUFDSixxQkFBcUI7QUFBQSxNQUNwQixNQUFNO0FBQUE7QUFBQSxRQUVMLG1CQUFtQjtBQUFBLFFBQ25CLGdCQUFnQjtBQUFBLE1BQ2pCO0FBQUEsSUFDRDtBQUFBLEVBQ0Q7QUFBQSxFQUNBLFFBQVE7QUFBQSxJQUNQLE1BQU07QUFBQSxFQUNQO0FBQ0QsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K
|