vue-editify 0.1.43 → 0.1.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,12 +23,12 @@ import { computed, getCurrentInstance, nextTick, onBeforeUnmount, onMounted, pro
23
23
  import { AlexEditor, AlexElement, AlexElementRangeType, AlexElementsRangeType } from 'alex-editor'
24
24
  import { element as DapElement, event as DapEvent, data as DapData, number as DapNumber, color as DapColor } from 'dap-util'
25
25
  import { mergeObject, getToolbarConfig, getMenuConfig, MenuConfigType, ObjectType, ToolbarConfigType, PluginResultType } from '../core/tool'
26
- import { parseList, orderdListHandle, commonElementHandle, tableHandle, preHandle, specialInblockHandle } from '../core/rule'
26
+ import { parseList, orderdListHandle, commonElementHandle, tableThTdHandle, tableFormatHandle, tableRangeMergedHandle, preHandle, specialInblockHandle } from '../core/rule'
27
27
  import { isTask, elementToParagraph, getMatchElementsByRange, hasTableInRange, hasLinkInRange, hasPreInRange, hasImageInRange, hasVideoInRange } from '../core/function'
28
28
  import Toolbar from '../components/toolbar/toolbar.vue'
29
29
  import Menu from '../components/menu/menu.vue'
30
30
  import Layer from '../components/layer/layer.vue'
31
- import { EditifyProps, EditifyTableColumnResizeParamsType, EditifyToolbarOptionsType } from './props'
31
+ import { EditifyProps, EditifyResizeParamsType, EditifyToolbarOptionsType } from './props'
32
32
  import { trans } from '../locale'
33
33
  import { LanguagesItemType } from '../hljs'
34
34
 
@@ -52,8 +52,8 @@ const isModelChange = ref<boolean>(false)
52
52
  const isInputChinese = ref<boolean>(false)
53
53
  //工具条和菜单栏判定延时器
54
54
  const rangeUpdateTimer = ref<any>(null)
55
- //表格列宽拖拽记录数据
56
- const tableColumnResizeParams = ref<EditifyTableColumnResizeParamsType>({
55
+ //拖拽记录数据
56
+ const resizeParams = ref<EditifyResizeParamsType>({
57
57
  element: null, //被拖拽的td
58
58
  start: 0 //水平方向起点位置
59
59
  })
@@ -287,7 +287,13 @@ const createEditor = () => {
287
287
  commonElementHandle(editor.value!, el)
288
288
  },
289
289
  el => {
290
- tableHandle(editor.value!, el)
290
+ tableThTdHandle(editor.value!, el)
291
+ },
292
+ el => {
293
+ tableFormatHandle(editor.value!, el)
294
+ },
295
+ el => {
296
+ tableRangeMergedHandle(editor.value!, el)
291
297
  },
292
298
  el => {
293
299
  preHandle(editor.value!, el, !!(toolbarConfig.value?.use && toolbarConfig.value?.codeBlock?.languages?.show), <(string | LanguagesItemType)[]>toolbarConfig.value?.codeBlock?.languages?.options)
@@ -338,96 +344,151 @@ const setVideoHeight = () => {
338
344
  video.style.height = video.offsetWidth / props.videoRatio + 'px'
339
345
  })
340
346
  }
341
- //鼠标在页面按下:处理表格拖拽改变列宽和菜单栏是否使用判断
347
+ //鼠标在页面按下:处理表格拖拽改变列宽、拖拽改变图片视频宽度和菜单栏是否使用判断
342
348
  const documentMouseDown = (e: Event) => {
343
349
  if (props.disabled) {
344
350
  return
345
351
  }
352
+ const elm = e.target as HTMLElement
353
+ const event = e as MouseEvent
346
354
  //鼠标在编辑器内按下
347
- if (DapElement.isContains(contentRef.value!, <HTMLElement>e.target)) {
348
- const elm = <HTMLElement>e.target
355
+ if (DapElement.isContains(contentRef.value!, elm)) {
349
356
  const key = DapData.get(elm, 'data-alex-editor-key')
350
357
  if (key) {
351
358
  const element = editor.value!.getElementByKey(key)
352
- if (element && element.parsedom == 'td') {
353
- const length = element.parent!.children!.length
354
- //最后一个td不设置
355
- if (element.parent!.children![length - 1].isEqual(element)) {
356
- return
359
+ if (element) {
360
+ //如果是td则表示拖拽改变列宽
361
+ if (element.parsedom == 'td') {
362
+ const length = element.parent!.children!.length
363
+ //最后一个td不设置
364
+ if (element.parent!.children![length - 1].isEqual(element)) {
365
+ return
366
+ }
367
+ const rect = DapElement.getElementBounding(elm)
368
+ //在可拖拽范围内
369
+ if (event.pageX >= Math.abs(rect.left + elm.offsetWidth - 5) && event.pageX <= Math.abs(rect.left + elm.offsetWidth + 5)) {
370
+ resizeParams.value.element = element
371
+ resizeParams.value.start = event.pageX
372
+ }
357
373
  }
358
- const rect = DapElement.getElementBounding(elm)
359
- //在可拖拽范围内
360
- if ((<MouseEvent>e).pageX >= Math.abs(rect.left + elm.offsetWidth - 5) && (<MouseEvent>e).pageX <= Math.abs(rect.left + elm.offsetWidth + 5)) {
361
- tableColumnResizeParams.value.element = element
362
- tableColumnResizeParams.value.start = (<MouseEvent>e).pageX
374
+ //如果是img或者video则表示拖拽改变图片视频宽度
375
+ else if (['img', 'video'].includes(element.parsedom!)) {
376
+ const rect = DapElement.getElementBounding(elm)
377
+ //在可拖拽范围内
378
+ if ((event.pageX >= Math.abs(rect.left + elm.offsetWidth - 10) && event.pageX <= Math.abs(rect.left + elm.offsetWidth)) || (event.pageX >= Math.abs(rect.left) && event.pageX <= Math.abs(rect.left + 10))) {
379
+ resizeParams.value.element = element
380
+ resizeParams.value.start = event.pageX
381
+ }
363
382
  }
364
383
  }
365
384
  }
366
385
  }
367
386
  //如果点击了除编辑器外的地方,菜单栏不可使用
368
- if (!DapElement.isContains(elRef.value!, <HTMLElement>e.target) && !isSourceView.value) {
387
+ if (!DapElement.isContains(elRef.value!, elm) && !isSourceView.value) {
369
388
  canUseMenu.value = false
370
389
  }
371
390
  }
372
- //鼠标在页面移动:处理表格拖拽改变列宽
391
+ //鼠标在页面移动:处理表格拖拽改变列宽、拖拽改变图片视频宽度
373
392
  const documentMouseMove = (e: Event) => {
374
393
  if (props.disabled) {
375
394
  return
376
395
  }
377
- if (!tableColumnResizeParams.value.element) {
396
+ if (!resizeParams.value.element) {
378
397
  return
379
398
  }
380
- const tables = getMatchElementsByRange(editor.value!, dataRangeCaches.value, { parsedom: 'table' })
381
- if (tables.length != 1) {
382
- return
399
+ const event = e as MouseEvent
400
+ //表格列宽拖拽
401
+ if (resizeParams.value.element.parsedom == 'td') {
402
+ const tables = getMatchElementsByRange(editor.value!, dataRangeCaches.value, { parsedom: 'table' })
403
+ if (tables.length != 1) {
404
+ return
405
+ }
406
+ const colgroup = tables[0].children!.find(item => {
407
+ return item.parsedom == 'colgroup'
408
+ })!
409
+ const index = resizeParams.value.element.parent!.children!.findIndex(el => {
410
+ return el.isEqual(resizeParams.value.element!)
411
+ })
412
+ const width = `${resizeParams.value.element.elm!.offsetWidth + event.pageX - resizeParams.value.start}`
413
+ colgroup.children![index].marks!['width'] = width
414
+ colgroup.children![index].elm!.setAttribute('width', width)
415
+ resizeParams.value.start = event.pageX
416
+ }
417
+ //图片视频拖拽改变宽度
418
+ else if (['img', 'video'].includes(resizeParams.value.element.parsedom!)) {
419
+ const width = `${resizeParams.value.element.elm!.offsetWidth + event.pageX - resizeParams.value.start}px`
420
+ if (resizeParams.value.element.hasStyles()) {
421
+ resizeParams.value.element.styles!['width'] = width
422
+ } else {
423
+ resizeParams.value.element.styles = {
424
+ width: width
425
+ }
426
+ }
427
+ resizeParams.value.element.elm!.style.width = width
428
+ if (resizeParams.value.element.parsedom == 'video') {
429
+ setVideoHeight()
430
+ }
431
+ resizeParams.value.start = event.pageX
383
432
  }
384
- const colgroup = tables[0].children!.find(item => {
385
- return item.parsedom == 'colgroup'
386
- })!
387
- const index = tableColumnResizeParams.value.element.parent!.children!.findIndex(el => {
388
- return el.isEqual(tableColumnResizeParams.value.element!)
389
- })
390
- const width = `${tableColumnResizeParams.value.element.elm!.offsetWidth + (<MouseEvent>e).pageX - tableColumnResizeParams.value.start}`
391
- colgroup.children![index].marks!['width'] = width
392
- colgroup.children![index].elm!.setAttribute('width', width)
393
- tableColumnResizeParams.value.start = (<MouseEvent>e).pageX
394
433
  }
395
- //鼠标在页面松开:处理表格拖拽改变列宽
434
+ //鼠标在页面松开:处理表格拖拽改变列宽、拖拽改变图片视频宽度
396
435
  const documentMouseUp = () => {
397
436
  if (props.disabled) {
398
437
  return
399
438
  }
400
- if (!tableColumnResizeParams.value.element) {
439
+ if (!resizeParams.value.element) {
401
440
  return
402
441
  }
403
- const tables = getMatchElementsByRange(editor.value!, dataRangeCaches.value, { parsedom: 'table' })
404
- if (tables.length != 1) {
405
- return
442
+ //表格列宽拖拽
443
+ if (resizeParams.value.element.parsedom == 'td') {
444
+ const tables = getMatchElementsByRange(editor.value!, dataRangeCaches.value, { parsedom: 'table' })
445
+ if (tables.length != 1) {
446
+ return
447
+ }
448
+ const colgroup = tables[0].children!.find(item => {
449
+ return item.parsedom == 'colgroup'
450
+ })!
451
+ const index = resizeParams.value.element.parent!.children!.findIndex(el => {
452
+ return el.isEqual(resizeParams.value.element!)
453
+ })
454
+ const width = parseFloat(colgroup.children![index].marks!['width'])
455
+ if (!isNaN(width)) {
456
+ colgroup.children![index].marks!['width'] = `${Number(((width / resizeParams.value.element.parent!.elm!.offsetWidth) * 100).toFixed(2))}%`
457
+ editor.value!.formatElementStack()
458
+ editor.value!.domRender()
459
+ editor.value!.rangeRender()
460
+ }
461
+ resizeParams.value.element = null
462
+ resizeParams.value.start = 0
406
463
  }
407
- const colgroup = tables[0].children!.find(item => {
408
- return item.parsedom == 'colgroup'
409
- })!
410
- const index = tableColumnResizeParams.value.element.parent!.children!.findIndex(el => {
411
- return el.isEqual(tableColumnResizeParams.value.element!)
412
- })
413
- const width = Number(colgroup.children![index].marks!['width'])
414
- if (!isNaN(width)) {
415
- colgroup.children![index].marks!['width'] = `${Number(((width / tableColumnResizeParams.value.element.parent!.elm!.offsetWidth) * 100).toFixed(2))}%`
416
- editor.value!.formatElementStack()
417
- editor.value!.domRender()
418
- editor.value!.rangeRender()
464
+ //图片视频拖拽改变宽度
465
+ else if (['img', 'video'].includes(resizeParams.value.element.parsedom!)) {
466
+ const width = parseFloat(resizeParams.value.element.styles!['width'])
467
+ if (!isNaN(width)) {
468
+ if (resizeParams.value.element.hasStyles()) {
469
+ resizeParams.value.element.styles!['width'] = `${Number(((width / DapElement.width(contentRef.value!)) * 100).toFixed(2))}%`
470
+ } else {
471
+ resizeParams.value.element.styles = {
472
+ width: `${Number(((width / DapElement.width(contentRef.value!)) * 100).toFixed(2))}%`
473
+ }
474
+ }
475
+ editor.value!.formatElementStack()
476
+ editor.value!.domRender()
477
+ editor.value!.rangeRender()
478
+ }
479
+ resizeParams.value.element = null
480
+ resizeParams.value.start = 0
419
481
  }
420
- tableColumnResizeParams.value.element = null
421
- tableColumnResizeParams.value.start = 0
422
482
  }
423
483
  //鼠标点击页面:处理任务列表复选框勾选
424
484
  const documentClick = (e: Event) => {
425
485
  if (props.disabled) {
426
486
  return
427
487
  }
488
+ const elm = e.target as HTMLElement
489
+ const event = e as MouseEvent
428
490
  //鼠标在编辑器内点击
429
- if (DapElement.isContains(contentRef.value!, <HTMLElement>e.target)) {
430
- const elm = <HTMLElement>e.target
491
+ if (DapElement.isContains(contentRef.value!, elm)) {
431
492
  const key = DapData.get(elm, 'data-alex-editor-key')
432
493
  if (key) {
433
494
  const element = editor.value!.getElementByKey(key)!
@@ -435,7 +496,7 @@ const documentClick = (e: Event) => {
435
496
  if (isTask(element)) {
436
497
  const rect = DapElement.getElementBounding(elm)
437
498
  //在复选框范围内
438
- if ((<MouseEvent>e).pageX >= Math.abs(rect.left) && (<MouseEvent>e).pageX <= Math.abs(rect.left + 16) && (<MouseEvent>e).pageY >= Math.abs(rect.top + elm.offsetHeight / 2 - 8) && (<MouseEvent>e).pageY <= Math.abs(rect.top + elm.offsetHeight / 2 + 8)) {
499
+ if (event.pageX >= Math.abs(rect.left) && event.pageX <= Math.abs(rect.left + 16) && event.pageY >= Math.abs(rect.top + elm.offsetHeight / 2 - 8) && event.pageY <= Math.abs(rect.top + elm.offsetHeight / 2 + 8)) {
439
500
  //取消勾选
440
501
  if (element.marks!['data-editify-task'] == 'checked') {
441
502
  element.marks!['data-editify-task'] = 'uncheck'
@@ -477,6 +538,10 @@ const handleCustomHtmlPaste = async (elements: AlexElement[]) => {
477
538
  if (el.marks!['disabled']) {
478
539
  marks['disabled'] = el.marks!['disabled']
479
540
  }
541
+ //图片的alt属性保留
542
+ if (el.parsedom == 'img' && el.marks!['alt']) {
543
+ marks['alt'] = el.marks!['alt']
544
+ }
480
545
  //图片和视频的src属性保留
481
546
  if (['img', 'video'].includes(el.parsedom!) && el.marks!['src']) {
482
547
  marks['src'] = el.marks!['src']
@@ -521,9 +586,29 @@ const handleCustomHtmlPaste = async (elements: AlexElement[]) => {
521
586
  if (el.parsedom == 'div' && el.marks!['data-editify-task']) {
522
587
  marks['data-editify-task'] = el.marks!['data-editify-task']
523
588
  }
589
+ //表格列宽属性保留
590
+ if (el.parsedom == 'col' && el.marks!['width']) {
591
+ marks['width'] = el.marks!['width']
592
+ }
593
+ //表格单元格colspan属性保留
594
+ if (['td', 'th'].includes(el.parsedom!) && el.marks!['colspan']) {
595
+ marks['colspan'] = el.marks!['colspan']
596
+ }
597
+ //表格单元格rowspan属性保留
598
+ if (['td', 'th'].includes(el.parsedom!) && el.marks!['rowspan']) {
599
+ marks['rowspan'] = el.marks!['rowspan']
600
+ }
601
+ //表格单元格被合并属性保留
602
+ if (['td', 'th'].includes(el.parsedom!) && el.marks!['data-editify-merged']) {
603
+ marks['data-editify-merged'] = el.marks!['data-editify-merged']
604
+ }
524
605
  }
525
606
  //处理需要保留的样式
526
607
  if (el.hasStyles()) {
608
+ //图片和视频保留width样式
609
+ if (['img', 'video'].includes(el.parsedom!) && el.styles!['width']) {
610
+ styles['width'] = el.styles!['width']
611
+ }
527
612
  //块元素保留text-indent样式
528
613
  if ((el.isBlock() || el.isInblock()) && el.styles!['text-indent']) {
529
614
  styles['text-indent'] = el.styles!['text-indent']
@@ -631,10 +716,10 @@ const handleEditorClick = (e: Event) => {
631
716
  if (props.disabled || isSourceView.value) {
632
717
  return
633
718
  }
634
- const node = <HTMLElement>e.target
719
+ const elm = e.target as HTMLElement
635
720
  //点击的是图片或者视频
636
- if (node.nodeName.toLocaleLowerCase() == 'img' || node.nodeName.toLocaleLowerCase() == 'video') {
637
- const key = Number(node.getAttribute('data-editify-element'))
721
+ if (elm.nodeName.toLocaleLowerCase() == 'img' || elm.nodeName.toLocaleLowerCase() == 'video') {
722
+ const key = Number(elm.getAttribute('data-editify-element'))
638
723
  if (DapNumber.isNumber(key)) {
639
724
  const element = editor.value!.getElementByKey(key)!
640
725
  if (!editor.value!.range) {
@@ -4,7 +4,7 @@ import { PluginType, MenuConfigType, ObjectType, ToolbarConfigType } from '../co
4
4
  import { AlexElement } from 'alex-editor'
5
5
  import { LocaleType } from '../locale'
6
6
 
7
- export type EditifyTableColumnResizeParamsType = {
7
+ export type EditifyResizeParamsType = {
8
8
  element: AlexElement | null
9
9
  start: number
10
10
  }
@@ -1,3 +1,19 @@
1
+ .editify-icon-merge-cells-up:before {
2
+ content: '\e73e';
3
+ }
4
+
5
+ .editify-icon-merge-cells-left:before {
6
+ content: '\e741';
7
+ }
8
+
9
+ .editify-icon-merge-cells-right:before {
10
+ content: '\e73f';
11
+ }
12
+
13
+ .editify-icon-merge-cells-down:before {
14
+ content: '\e740';
15
+ }
16
+
1
17
  .editify-icon-mathformula:before {
2
18
  content: '\e616';
3
19
  }
Binary file
Binary file
package/src/index.ts CHANGED
@@ -9,17 +9,17 @@ export type { ButtonTypeType, ButtonOptionsItemType, ButtonSelectConfigType, But
9
9
  export type { InsertImageUploadErrorType } from './components/insertImage/props'
10
10
  export type { InsertVideoUploadErrorType } from './components/insertVideo/props'
11
11
  export type { MenuButtonType, MenuSelectButtonType, MenuDisplayButtonType, MenuImageButtonType, MenuVideoButtonType, MenuTableButtonType, MenuCustomButtonType, CodeBlockToolbarType, TextToolbarType, ToolbarConfigType, MenuSequenceType, MenuModeType, MenuExtendType, MenuConfigType, PluginType, PluginResultType } from './core/tool'
12
- export type { ElementMatchConfig } from './core/function'
12
+ export type { ElementMatchConfigType } from './core/function'
13
13
 
14
14
  //导出编辑器操作方法
15
- export { elementIsMatch, getMatchElementByElement, getMatchElementsByRange, elementIsInList, elementIsInTask, isList, isTask, hasPreInRange, isRangeInPre, hasQuoteInRange, isRangeInQuote, hasListInRange, isRangeInList, hasTaskInRange, isRangeInTask, hasLinkInRange, hasTableInRange, hasImageInRange, hasVideoInRange, queryTextStyle, queryTextMark, getRangeText, setIndentIncrease, setIndentDecrease, setQuote, setAlign, setList, setTask, setTextStyle, setTextMark, removeTextStyle, removeTextMark, setLineHeight, insertLink, insertImage, insertVideo, insertTable, insertCodeBlock } from './core/function'
15
+ export { elementIsMatch, getMatchElementByElement, getMatchElementsByRange, elementIsInList, elementIsInTask, isList, isTask, hasPreInRange, isRangeInPre, hasQuoteInRange, isRangeInQuote, hasListInRange, isRangeInList, hasTaskInRange, isRangeInTask, hasLinkInRange, hasTableInRange, hasImageInRange, hasVideoInRange, queryTextStyle, queryTextMark, getRangeText, setIndentIncrease, setIndentDecrease, setQuote, setAlign, setList, setTask, setTextStyle, setTextMark, removeTextStyle, removeTextMark, setLineHeight, insertLink, insertImage, insertVideo, insertTable, insertCodeBlock, insertSeparator } from './core/function'
16
16
 
17
17
  //安装函数
18
18
  const install: FunctionPlugin = (app: App) => {
19
19
  app.component(Editify.name!, Editify)
20
20
  }
21
21
  //版本号
22
- const version = '0.1.43'
22
+ const version = '0.1.45'
23
23
 
24
24
  //导出AlexElement元素
25
25
  export { AlexElement } from 'alex-editor'
@@ -9,6 +9,10 @@ export const en_US: ObjectType = {
9
9
  insertColumnRight: 'Insert column backward',
10
10
  deleteRow: 'Delete rows',
11
11
  deleteColumn: 'Delete column',
12
+ mergeCellsLeft: 'Merge cells to the left',
13
+ mergeCellsRight: 'Merge cells to the right',
14
+ mergeCellsUp: 'Merge cells up',
15
+ mergeCellsDown: 'Merge cells down',
12
16
  deleteTable: 'Delete table',
13
17
  selectLanguages: 'Select language',
14
18
  autoRecognize: 'Auto',
@@ -9,6 +9,10 @@ export const zh_CN: ObjectType = {
9
9
  insertColumnRight: '向后插入列',
10
10
  deleteRow: '删除行',
11
11
  deleteColumn: '删除列',
12
+ mergeCellsLeft: '向左合并单元格',
13
+ mergeCellsRight: '向右合并单元格',
14
+ mergeCellsUp: '向上合并单元格',
15
+ mergeCellsDown: '向下合并单元格',
12
16
  deleteTable: '删除表格',
13
17
  selectLanguages: '选择语言',
14
18
  autoRecognize: '自动识别',
@@ -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