master
cast1e 2024-10-15 18:51:53 +08:00
parent 21d4c33460
commit 6580f1d261
12 changed files with 386 additions and 99 deletions

View File

@ -40,6 +40,7 @@ pub fn init(app: &mut App) -> std::result::Result<(), Box<dyn std::error::Error>
if let Some(window) = app.get_webview_window("main") {
let _ = window.show();
let _ = window.set_focus();
let _ = window.unminimize();
}
}
TrayIconEvent::Click {

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1728972948301" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3377" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M904.533333 422.4l-85.333333-14.933333-17.066667-38.4 49.066667-70.4c14.933333-21.333333 12.8-49.066667-6.4-68.266667l-53.333333-53.333333c-19.2-19.2-46.933333-21.333333-68.266667-6.4l-70.4 49.066666-38.4-17.066666-14.933333-85.333334c-2.133333-23.466667-23.466667-42.666667-49.066667-42.666666h-74.666667c-25.6 0-46.933333 19.2-53.333333 44.8l-14.933333 85.333333-38.4 17.066667L296.533333 170.666667c-21.333333-14.933333-49.066667-12.8-68.266666 6.4l-53.333334 53.333333c-19.2 19.2-21.333333 46.933333-6.4 68.266667l49.066667 70.4-17.066667 38.4-85.333333 14.933333c-21.333333 4.266667-40.533333 25.6-40.533333 51.2v74.666667c0 25.6 19.2 46.933333 44.8 53.333333l85.333333 14.933333 17.066667 38.4L170.666667 727.466667c-14.933333 21.333333-12.8 49.066667 6.4 68.266666l53.333333 53.333334c19.2 19.2 46.933333 21.333333 68.266667 6.4l70.4-49.066667 38.4 17.066667 14.933333 85.333333c4.266667 25.6 25.6 44.8 53.333333 44.8h74.666667c25.6 0 46.933333-19.2 53.333333-44.8l14.933334-85.333333 38.4-17.066667 70.4 49.066667c21.333333 14.933333 49.066667 12.8 68.266666-6.4l53.333334-53.333334c19.2-19.2 21.333333-46.933333 6.4-68.266666l-49.066667-70.4 17.066667-38.4 85.333333-14.933334c25.6-4.266667 44.8-25.6 44.8-53.333333v-74.666667c-4.266667-27.733333-23.466667-49.066667-49.066667-53.333333z m-19.2 117.333333l-93.866666 17.066667c-10.666667 2.133333-19.2 8.533333-23.466667 19.2l-29.866667 70.4c-4.266667 10.666667-2.133333 21.333333 4.266667 29.866667l53.333333 76.8-40.533333 40.533333-76.8-53.333333c-8.533333-6.4-21.333333-8.533333-29.866667-4.266667L576 768c-10.666667 4.266667-17.066667 12.8-19.2 23.466667l-17.066667 93.866666h-57.6l-17.066666-93.866666c-2.133333-10.666667-8.533333-19.2-19.2-23.466667l-70.4-29.866667c-10.666667-4.266667-21.333333-2.133333-29.866667 4.266667l-76.8 53.333333-40.533333-40.533333 53.333333-76.8c6.4-8.533333 8.533333-21.333333 4.266667-29.866667L256 576c-4.266667-10.666667-12.8-17.066667-23.466667-19.2l-93.866666-17.066667v-57.6l93.866666-17.066666c10.666667-2.133333 19.2-8.533333 23.466667-19.2l29.866667-70.4c4.266667-10.666667 2.133333-21.333333-4.266667-29.866667l-53.333333-76.8 40.533333-40.533333 76.8 53.333333c8.533333 6.4 21.333333 8.533333 29.866667 4.266667L448 256c10.666667-4.266667 17.066667-12.8 19.2-23.466667l17.066667-93.866666h57.6l17.066666 93.866666c2.133333 10.666667 8.533333 19.2 19.2 23.466667l70.4 29.866667c10.666667 4.266667 21.333333 2.133333 29.866667-4.266667l76.8-53.333333 40.533333 40.533333-53.333333 76.8c-6.4 8.533333-8.533333 21.333333-4.266667 29.866667L768 448c4.266667 10.666667 12.8 17.066667 23.466667 19.2l93.866666 17.066667v55.466666z" fill="currentColor" p-id="3378"></path><path d="M512 394.666667c-64 0-117.333333 53.333333-117.333333 117.333333s53.333333 117.333333 117.333333 117.333333 117.333333-53.333333 117.333333-117.333333-53.333333-117.333333-117.333333-117.333333z m0 170.666666c-29.866667 0-53.333333-23.466667-53.333333-53.333333s23.466667-53.333333 53.333333-53.333333 53.333333 23.466667 53.333333 53.333333-23.466667 53.333333-53.333333 53.333333z" fill="currentColor" p-id="3379"></path></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -64,16 +64,12 @@ import { open } from '@tauri-apps/plugin-dialog';
import { invoke } from '@tauri-apps/api/core';
import { useStore } from 'vuex';
import { ElMessage } from 'element-plus';
import type { AddInfo } from '@/ts/types';
const store = useStore();
const visible = defineModel<boolean>();
const bg = ref<HTMLDivElement | null>(null);
interface AddInfo {
name: string,
preview: string,
media: string,
description: string
}
const addInfo = ref<AddInfo>({
name: "",
preview: "",
@ -150,8 +146,8 @@ function handleAdd() {
if (checkInfo(addInfo.value)) {
if (applyButton.value) {
ElMessage({
type:"info",
message:"正在新建项目, 请勿重新点击或关闭程序"
type: "info",
message: "正在新建项目, 请勿重新点击或关闭程序"
})
applyButton.value.disabled = true;
invoke("new_wallpaper", {
@ -189,6 +185,16 @@ function handleAdd() {
</script>
<style>
@keyframes add-item-entry {
0% {
top: 100%;
}
100% {
top: calc(100% - 60px);
}
}
.item-add-bg {
border: solid var(--bd-color) 1px;
backdrop-filter: blur(30px) saturate(180%);
@ -202,6 +208,7 @@ function handleAdd() {
width: 85%;
height: calc(100% - 55px);
transition: .8s cubic-bezier(0.9, 0, 0, 1.1);
animation: add-item-entry .3s ease-in-out;
}
.item-add-show {

View File

@ -5,9 +5,7 @@
<slot name="content"></slot>
</div>
<div id="close" @click="handleClose">
<el-icon :size="25">
<Close />
</el-icon>
<SvgIcon name="window-close" size="25px"></SvgIcon>
</div>
</div>
</div>
@ -15,7 +13,7 @@
<script lang="ts">
import { defineComponent, nextTick } from 'vue'
import "@/style/cui.scss"
import "@/style/cui.css"
export default defineComponent({
name: "CDiaLog",
@ -63,7 +61,7 @@ export default defineComponent({
})
</script>
<style lang="scss" scoped>
<style scoped>
#mask {
z-index: 200;
position: absolute;
@ -71,8 +69,6 @@ export default defineComponent({
left: 0;
width: 100%;
height: 100%;
backdrop-filter: blur(10px);
animation: cui-dialog-blur .6s;
}
#bg {
@ -87,6 +83,7 @@ export default defineComponent({
top: 50%;
left: 50%;
animation: cui-dialog-appear .6s cubic-bezier(0, 0.6, 0.2, 1.0);
box-shadow: var(--shadow-edge-glow), var(--shadow);
}
#content {

View File

@ -0,0 +1,242 @@
<template>
<div class="item-edit-content">
<main class="item-edit-main">
<table class="item-edit-form">
<tbody>
<tr>
<td class="item-edit-form-title">标题</td>
<td><input type="text" v-model="data.name" /></td>
</tr>
<tr>
<td class="item-edit-form-title">文件</td>
<td>
<template v-if="image_src">
<img :src="image_src" class="item-edit-image" @click="selectPreview">
</template>
<template v-else>
<img :src="data.preview" class="item-edit-image" @click="selectPreview">
</template>
</td>
</tr>
<tr>
<td class="item-edit-form-title">描述</td>
<td><textarea class="item-edit-description" v-model="data.description"></textarea>
</td>
</tr>
<tr>
<td></td>
<td><button class="apply-button" @click="handleEdit" ref="applyButton">添加</button></td>
</tr>
</tbody>
</table>
</main>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { open } from '@tauri-apps/plugin-dialog';
import { invoke } from '@tauri-apps/api/core';
import { useStore } from 'vuex';
import { ElMessage } from 'element-plus';
import type { EditInfo } from '@/ts/types';
const store = useStore();
const data = defineModel<EditInfo>("data", {
required: true
})
const emit = defineEmits(["submit"]);
const image_src = ref("");
const image_path = ref("");
const support_img_ext = ['.jpg', '.png', '.gif', '.webp'];
const support_img_ext_map: { [key in (typeof support_img_ext)[number]]: string } = {
'.jpg': 'image/jpeg',
'.png': 'image/png',
'.gif': 'image/gif',
'.webp': 'image/webp'
}
const applyButton = ref<HTMLButtonElement | null>(null);
async function handleFileOpen() {
const file = await open({
multiple: false,
directory: false,
});
return file;
}
function selectPreview() {
handleFileOpen().then((file) => {
if (file) {
let ext = file.substring(file.lastIndexOf("."));
if (support_img_ext.includes(ext)) {
image_path.value = file;
invoke("get_file", {
path: file
}).then((res) => {
let binary_data_arr = new Uint8Array(res as number[]);
const blob = new Blob([binary_data_arr], { type: support_img_ext_map[ext] });
const imageUrl = URL.createObjectURL(blob);
image_src.value = imageUrl;
})
} else ElMessage({
type: "error",
message: "文件格式不受支持"
})
}
})
}
function checkInfo(info: EditInfo) {
if (!info.name) return false
else return true;
}
function handleEdit() {
if (checkInfo(data.value)) {
if (applyButton.value) {
ElMessage({
type: "info",
message: "正在修改项目, 请勿重新点击或关闭程序"
})
const info = Object.assign({}, data.value);
info.preview = image_path.value;
applyButton.value.disabled = true;
invoke("edit_wallpaper", {
info: info
}).then((res) => {
if (applyButton.value) applyButton.value.disabled = false;
if (res as string == "Success") {
store.commit("getWpList");
emit("submit");
ElMessage({
type: "success",
message: "修改成功"
})
}
else ElMessage({
type: "error",
message: `修改失败 ${res}`
})
})
}
}
else ElMessage({
type: "error",
message: "请填写名称并选择媒体文件"
})
}
</script>
<style>
.item-edit-show {
top: 60px;
}
.item-edit-content {
padding: 10px;
height: calc(100% - 20px);
overflow: hidden;
}
.item-edit-main {
margin: 10px;
height: 100%;
overflow: auto;
}
.item-edit-main::-webkit-scrollbar {
display: none;
}
.item-edit-header-icon {
width: 40px;
height: 40px;
border-radius: 5px;
background-color: #3b93ff;
transition: .3s;
align-items: center;
justify-content: center;
}
.item-edit-header-icon:hover {
background-color: #1e5daa;
cursor: pointer;
}
.item-edit-header-item {
display: flex;
align-items: center;
color: var(--text-color);
}
.item-edit-header-title {
font-size: 22px;
font-weight: 600;
margin-left: 10px;
}
.item-edit-main {
color: var(--text-color);
}
.item-edit-preview {
background: linear-gradient(135deg, #0000000A 0%, #FFFFFF0A 100%);
border-radius: 5px;
width: 400px;
height: 200px;
margin-bottom: 10px;
box-shadow: var(--shadow-edge-glow);
position: relative;
cursor: pointer;
transition: .5s;
}
.item-edit-preview:hover {
background: var(--bg-hover-fill);
}
.item-edit-preview:active {
transform: scale(0.95);
}
.item-edit-image {
background: linear-gradient(135deg, #0000001A 0%, #FFFFFF1A 100%);
border-radius: 5px;
width: 400px;
margin-bottom: 10px;
box-shadow: var(--shadow-edge-glow);
cursor: pointer;
}
.item-edit-image:active {
transform: scale(0.95);
}
.item-edit-form {
margin-top: 5px;
}
.item-edit-form td {
vertical-align: top;
padding: 5px;
}
.item-edit-description {
width: 300px;
height: 150px;
}
.item-edit-form-title {
font-size: 15px;
font-weight: 600;
}
.item-edit-preview-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>

View File

@ -52,7 +52,6 @@ const props = defineProps({
}
.item-card:hover {
box-shadow: var(--shadow-edge-glow), var(--shadow);
cursor: pointer;
transform: scale(1.03);
box-shadow: 0 0 2px 5px rgba(177, 177, 177, 0.151);
@ -67,7 +66,7 @@ const props = defineProps({
}
.item-card:hover .item-card-title {
bottom: 0;
bottom: 5px;
}
.item-card-main img {
@ -78,10 +77,11 @@ const props = defineProps({
.item-card-title {
position: absolute;
bottom: -40px;
right: 5px;
right: 10px;
transition: .3s;
font-size: 30px;
font-weight: 400;
color: var(--text-color);
text-shadow: 1px 1px 2px var(--bg-color);
}
</style>

View File

@ -26,6 +26,11 @@
</div>
<template v-if="mode == 'win'">
<div class="titlebar-button-wrapper colbox">
<div class="titlebar-button" id="titlebar-settings" @click="minimize">
<div class="titlebar-button-rect">
<svg-icon name="setting" :size="button_size_default"></svg-icon>
</div>
</div>
<div class="titlebar-button" id="titlebar-minimize" @click="minimize">
<div class="titlebar-button-rect">
<svg-icon name="window-minimize" :size="button_size_default"></svg-icon>
@ -146,7 +151,7 @@ function close() {
justify-content: center;
}
#titlebar-minimize {
#titlebar-settings {
padding-left: 5px;
}
@ -154,6 +159,7 @@ function close() {
padding-right: 5px;
}
#titlebar-settings .titlebar-button-rect:hover,
#titlebar-minimize .titlebar-button-rect:hover,
#titlebar-maximize .titlebar-button-rect:hover {
background-color: var(--bg-hover-fill);

View File

@ -1,7 +1,7 @@
import { createStore } from 'vuex'
import { invoke } from '@tauri-apps/api/core'
import type { ResourceDir, wpConfig, Cell } from '@/ts/types'
import { WebviewWindow, } from '@tauri-apps/api/webviewWindow'
import { WebviewWindow } from '@tauri-apps/api/webviewWindow'
function arrayBufferToString(buffer: ArrayBuffer): string {
const decoder = new TextDecoder('utf-8')
@ -73,21 +73,27 @@ export const store = createStore({
}
})
},
apply_wallpaper(state, payload:{
title:string,
url:string
}) {
apply_wallpaper(
state,
payload: {
title: string
url: string
}
) {
const window_options = {
title: payload.title,
url: payload.url,
fullscreen: true,
shadow:false,
shadow: false,
decorations: false,
transparent: true
}
if (state.videoWindow)
state.videoWindow.destroy().then((_) => {state.videoWindow = new WebviewWindow(payload.title, window_options)})
else state.videoWindow = new WebviewWindow(payload.title,window_options)
state.videoWindow.destroy().then((_) => {
state.videoWindow = new WebviewWindow(payload.title, window_options)
})
else state.videoWindow = new WebviewWindow(payload.title, window_options)
}
}
},
actions: {}
})

View File

@ -0,0 +1,35 @@
@keyframes cui-dialog-appear {
0% {
/* opacity: 0%; */
transform: translate(-50%, -50%) scale(0.7);
}
100% {
/* opacity: 100%; */
transform: translate(-50%, -50%) scale(1);
}
}
@keyframes cui-dialog-disappear {
0% {
opacity: 100%;
transform: translate(-50%, -50%) scale(1);
}
100% {
opacity: 0%;
transform: translate(-50%, -50%) scale(0.5);
}
}
@keyframes cui-dialog-blur {
0% {
opacity: 0%;
/* backdrop-filter: blur(0px); */
}
100% {
opacity: 100%;
/* backdrop-filter: blur(10px); */
}
}

View File

@ -7,8 +7,8 @@ type WallpaperType = 'Video'
export interface Info {
media_type: WallpaperType
description: string
created: number,
entry_point:string
created: number
entry_point: string
}
export interface Option {
mute: boolean
@ -20,7 +20,7 @@ export interface Cell {
}
export interface Resource {
"config.json": string,
'config.json': string
[filename: string]: string
}
@ -29,3 +29,17 @@ export interface ResourceDir {
[resId: string]: Resource
}
}
interface AddInfo {
name: string
preview: string
media: string
description: string
}
interface EditInfo {
path: string
name: string
preview: string
description: string
}

View File

@ -6,10 +6,12 @@ import { ref, onMounted, computed, nextTick } from 'vue';
import CRMenu from '@/components/CRMenu.vue';
import CRMenuCell from '@/components/CRMenuCell.vue';
import SvgIcon from '@/components/SvgIcon.vue';
import type { Cell } from '@/ts/types'
import type { Cell, EditInfo } from '@/ts/types'
import { useStore } from 'vuex';
import { invoke } from '@tauri-apps/api/core';
import { ElMessage } from 'element-plus';
import CDialog from '@/components/CDialog.vue';
import EditItem from '@/components/EditItem.vue';
const store = useStore();
const items = computed<Cell[]>(() => store.state.wpList);
@ -18,27 +20,38 @@ const applyBar = ref<InstanceType<typeof ApplyBar> | null>(null);
const item_add_visible = ref(false);
const r_display = ref(false);
const r_data = ref<Cell>({
img: "",
path: "",
config: {
name: "",
info: {
description: "",
created: 0,
media_type: "Video",
entry_point: ""
},
option: {
mute: true
}
img: "",
path: "",
config: {
name: "",
info: {
description: "",
created: 0,
media_type: "Video",
entry_point: ""
},
option: {
mute: true
}
}
});
const menu = ref<InstanceType<typeof CRMenu> | null>(null);
const options = ref<{ name: string, icon: string, handler: (data: Cell) => void }[]>([{
name: "删除",
icon: "delete",
handler: del_wallpaper
}, {
name: "修改",
icon: "edit",
handler: edit_wallpaper
}])
const edit_visible = ref(false);
const edit_data = ref<EditInfo>({
path: "",
name: "",
preview: "",
description: "",
});
onMounted(() => {
store.commit("getWpList");
@ -73,6 +86,20 @@ function del_wallpaper(data: Cell) {
})
})
}
function edit_wallpaper(data: Cell) {
edit_visible.value = true;
edit_data.value = {
path: data.path,
name: data.config.name,
preview: data.img,
description: data.config.info.description
}
}
function handle_edit_close() {
edit_visible.value = false;
}
</script>
<template>
@ -92,6 +119,11 @@ function del_wallpaper(data: Cell) {
</CRMenuCell>
</template>
</CRMenu>
<CDialog v-model:visible="edit_visible" height="80%" width="80%">
<template #content>
<EditItem v-model:data="edit_data" @submit="handle_edit_close"></EditItem>
</template>
</CDialog>
</template>
<style>

View File

@ -1,54 +0,0 @@
// vite.config.ts
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "file:///D:/code/wallitor/wallitor-gui/node_modules/.pnpm/vite@5.4.7_@types+node@20.16.7/node_modules/vite/dist/node/index.js";
import vue from "file:///D:/code/wallitor/wallitor-gui/node_modules/.pnpm/@vitejs+plugin-vue@5.1.4_vite@5.4.7_@types+node@20.16.7__vue@3.5.8_typescript@5.4.5_/node_modules/@vitejs/plugin-vue/dist/index.mjs";
import vueDevTools from "file:///D:/code/wallitor/wallitor-gui/node_modules/.pnpm/vite-plugin-vue-devtools@7.4.6_rollup@4.22.4_vite@5.4.7_@types+node@20.16.7__vue@3.5.8_typescript@5.4.5_/node_modules/vite-plugin-vue-devtools/dist/vite.mjs";
import ElementPlus from "file:///D:/code/wallitor/wallitor-gui/node_modules/.pnpm/unplugin-element-plus@0.8.0_rollup@4.22.4/node_modules/unplugin-element-plus/dist/vite.mjs";
import path from "path";
import { createSvgIconsPlugin } from "file:///D:/code/wallitor/wallitor-gui/node_modules/.pnpm/vite-plugin-svg-icons@2.0.1_vite@5.4.7_@types+node@20.16.7_/node_modules/vite-plugin-svg-icons/dist/index.mjs";
var __vite_injected_original_dirname = "D:\\code\\wallitor\\wallitor-gui";
var __vite_injected_original_import_meta_url = "file:///D:/code/wallitor/wallitor-gui/vite.config.ts";
var vite_config_default = defineConfig({
clearScreen: false,
// Tauri expects a fixed port, fail if that port is not available
server: {
strictPort: true
},
envPrefix: ["VITE_", "TAURI_PLATFORM", "TAURI_ARCH", "TAURI_FAMILY", "TAURI_PLATFORM_VERSION", "TAURI_PLATFORM_TYPE", "TAURI_DEBUG"],
plugins: [
vue(),
vueDevTools(),
createSvgIconsPlugin({
iconDirs: [
path.resolve(__vite_injected_original_dirname, "src/assets/svgs")
],
symbolId: "icon-[name]"
}),
ElementPlus({
// options
})
],
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", __vite_injected_original_import_meta_url))
}
},
build: {
// Tauri uses Chromium on Windows and WebKit on macOS and Linux
target: process.env.TAURI_PLATFORM == "windows" ? "chrome105" : "safari13",
// don't minify for debug builds
minify: !process.env.TAURI_DEBUG ? "esbuild" : false,
// 为调试构建生成源代码映射 (sourcemap)
sourcemap: !!process.env.TAURI_DEBUG,
rollupOptions: {
input: {
main: path.resolve(__vite_injected_original_dirname, "index.html"),
video: path.resolve(__vite_injected_original_dirname, "video/index.html")
}
}
}
});
export {
vite_config_default as default
};
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJEOlxcXFxjb2RlXFxcXHdhbGxpdG9yXFxcXHdhbGxpdG9yLWd1aVwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiRDpcXFxcY29kZVxcXFx3YWxsaXRvclxcXFx3YWxsaXRvci1ndWlcXFxcdml0ZS5jb25maWcudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL0Q6L2NvZGUvd2FsbGl0b3Ivd2FsbGl0b3ItZ3VpL3ZpdGUuY29uZmlnLnRzXCI7aW1wb3J0IHsgZmlsZVVSTFRvUGF0aCwgVVJMIH0gZnJvbSAnbm9kZTp1cmwnXHJcblxyXG5pbXBvcnQgeyBkZWZpbmVDb25maWcgfSBmcm9tICd2aXRlJ1xyXG5pbXBvcnQgdnVlIGZyb20gJ0B2aXRlanMvcGx1Z2luLXZ1ZSdcclxuaW1wb3J0IHZ1ZURldlRvb2xzIGZyb20gJ3ZpdGUtcGx1Z2luLXZ1ZS1kZXZ0b29scydcclxuaW1wb3J0IEVsZW1lbnRQbHVzIGZyb20gJ3VucGx1Z2luLWVsZW1lbnQtcGx1cy92aXRlJ1xyXG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xyXG5pbXBvcnQgeyBjcmVhdGVTdmdJY29uc1BsdWdpbiB9IGZyb20gXCJ2aXRlLXBsdWdpbi1zdmctaWNvbnNcIjtcclxuXHJcbi8vIGh0dHBzOi8vdml0ZWpzLmRldi9jb25maWcvXHJcbmV4cG9ydCBkZWZhdWx0IGRlZmluZUNvbmZpZyh7XHJcbiAgY2xlYXJTY3JlZW46IGZhbHNlLFxyXG4gIC8vIFRhdXJpIGV4cGVjdHMgYSBmaXhlZCBwb3J0LCBmYWlsIGlmIHRoYXQgcG9ydCBpcyBub3QgYXZhaWxhYmxlXHJcbiAgc2VydmVyOiB7XHJcbiAgICBzdHJpY3RQb3J0OiB0cnVlLFxyXG4gIH0sXHJcbiAgZW52UHJlZml4OiBbJ1ZJVEVfJywgJ1RBVVJJX1BMQVRGT1JNJywgJ1RBVVJJX0FSQ0gnLCAnVEFVUklfRkFNSUxZJywgJ1RBVVJJX1BMQVRGT1JNX1ZFUlNJT04nLCAnVEFVUklfUExBVEZPUk1fVFlQRScsICdUQVVSSV9ERUJVRyddLFxyXG4gIHBsdWdpbnM6IFtcclxuICAgIHZ1ZSgpLFxyXG4gICAgdnVlRGV2VG9vbHMoKSxcclxuICAgIGNyZWF0ZVN2Z0ljb25zUGx1Z2luKHtcclxuICAgICAgaWNvbkRpcnM6IFtcclxuICAgICAgICBwYXRoLnJlc29sdmUoX19kaXJuYW1lLCBcInNyYy9hc3NldHMvc3Znc1wiKSxcclxuICAgICAgXSxcclxuICAgICAgc3ltYm9sSWQ6IFwiaWNvbi1bbmFtZV1cIlxyXG4gICAgfSksXHJcbiAgICBFbGVtZW50UGx1cyh7XHJcbiAgICAgIC8vIG9wdGlvbnNcclxuICAgIH0pLFxyXG4gIF0sXHJcbiAgcmVzb2x2ZToge1xyXG4gICAgYWxpYXM6IHtcclxuICAgICAgJ0AnOiBmaWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4vc3JjJywgaW1wb3J0Lm1ldGEudXJsKSlcclxuICAgIH1cclxuICB9LFxyXG4gIGJ1aWxkOiB7XHJcbiAgICAvLyBUYXVyaSB1c2VzIENocm9taXVtIG9uIFdpbmRvd3MgYW5kIFdlYktpdCBvbiBtYWNPUyBhbmQgTGludXhcclxuICAgIHRhcmdldDogcHJvY2Vzcy5lbnYuVEFVUklfUExBVEZPUk0gPT0gJ3dpbmRvd3MnID8gJ2Nocm9tZTEwNScgOiAnc2FmYXJpMTMnLFxyXG4gICAgLy8gZG9uJ3QgbWluaWZ5IGZvciBkZWJ1ZyBidWlsZHNcclxuICAgIG1pbmlmeTogIXByb2Nlc3MuZW52LlRBVVJJX0RFQlVHID8gJ2VzYnVpbGQnIDogZmFsc2UsXHJcbiAgICAvLyBcdTRFM0FcdThDMDNcdThCRDVcdTY3ODRcdTVFRkFcdTc1MUZcdTYyMTBcdTZFOTBcdTRFRTNcdTc4MDFcdTY2MjBcdTVDMDQgKHNvdXJjZW1hcClcclxuICAgIHNvdXJjZW1hcDogISFwcm9jZXNzLmVudi5UQVVSSV9ERUJVRyxcclxuICAgIHJvbGx1cE9wdGlvbnM6IHtcclxuICAgICAgaW5wdXQ6IHtcclxuICAgICAgICBtYWluOiBwYXRoLnJlc29sdmUoX19kaXJuYW1lLCAnaW5kZXguaHRtbCcpLFxyXG4gICAgICAgIHZpZGVvOiBwYXRoLnJlc29sdmUoX19kaXJuYW1lLCAndmlkZW8vaW5kZXguaHRtbCcpLFxyXG4gICAgICB9LFxyXG4gICAgfSxcclxuICB9LFxyXG59KVxyXG4iXSwKICAibWFwcGluZ3MiOiAiO0FBQWlSLFNBQVMsZUFBZSxXQUFXO0FBRXBULFNBQVMsb0JBQW9CO0FBQzdCLE9BQU8sU0FBUztBQUNoQixPQUFPLGlCQUFpQjtBQUN4QixPQUFPLGlCQUFpQjtBQUN4QixPQUFPLFVBQVU7QUFDakIsU0FBUyw0QkFBNEI7QUFQckMsSUFBTSxtQ0FBbUM7QUFBZ0ksSUFBTSwyQ0FBMkM7QUFVMU4sSUFBTyxzQkFBUSxhQUFhO0FBQUEsRUFDMUIsYUFBYTtBQUFBO0FBQUEsRUFFYixRQUFRO0FBQUEsSUFDTixZQUFZO0FBQUEsRUFDZDtBQUFBLEVBQ0EsV0FBVyxDQUFDLFNBQVMsa0JBQWtCLGNBQWMsZ0JBQWdCLDBCQUEwQix1QkFBdUIsYUFBYTtBQUFBLEVBQ25JLFNBQVM7QUFBQSxJQUNQLElBQUk7QUFBQSxJQUNKLFlBQVk7QUFBQSxJQUNaLHFCQUFxQjtBQUFBLE1BQ25CLFVBQVU7QUFBQSxRQUNSLEtBQUssUUFBUSxrQ0FBVyxpQkFBaUI7QUFBQSxNQUMzQztBQUFBLE1BQ0EsVUFBVTtBQUFBLElBQ1osQ0FBQztBQUFBLElBQ0QsWUFBWTtBQUFBO0FBQUEsSUFFWixDQUFDO0FBQUEsRUFDSDtBQUFBLEVBQ0EsU0FBUztBQUFBLElBQ1AsT0FBTztBQUFBLE1BQ0wsS0FBSyxjQUFjLElBQUksSUFBSSxTQUFTLHdDQUFlLENBQUM7QUFBQSxJQUN0RDtBQUFBLEVBQ0Y7QUFBQSxFQUNBLE9BQU87QUFBQTtBQUFBLElBRUwsUUFBUSxRQUFRLElBQUksa0JBQWtCLFlBQVksY0FBYztBQUFBO0FBQUEsSUFFaEUsUUFBUSxDQUFDLFFBQVEsSUFBSSxjQUFjLFlBQVk7QUFBQTtBQUFBLElBRS9DLFdBQVcsQ0FBQyxDQUFDLFFBQVEsSUFBSTtBQUFBLElBQ3pCLGVBQWU7QUFBQSxNQUNiLE9BQU87QUFBQSxRQUNMLE1BQU0sS0FBSyxRQUFRLGtDQUFXLFlBQVk7QUFBQSxRQUMxQyxPQUFPLEtBQUssUUFBUSxrQ0FBVyxrQkFBa0I7QUFBQSxNQUNuRDtBQUFBLElBQ0Y7QUFBQSxFQUNGO0FBQ0YsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K