// ==UserScript== // @name QingFlow Dragon King Super Tools // @namespace http://tampermonkey.net/ // @version 0.2 // @description 轻流QingFlow应用自动超级字段插件 // @author Mr.Dragon King // @license Mr.Dragon King // @match *://*.qingflow.com/f/* // @icon https://www.google.com/s2/favicons?sz=64&domain=pmbaobao.com // @require https://cdn.bootcss.com/jquery/3.3.1/jquery.js // @grant GM_log // @downloadURL none // ==/UserScript== //@Data var fieldUN = "未同步!!!";//字段数量 var PageOptimizationOpen = false; //@注册基础元素-字段 var field_Textfield = "/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[1]/div/div/div[1]";//单行文字 var field_Textarea = "/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[1]/div/div/div[2]";//多行文字 var field_Number = "/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[1]/div/div/div[3]";//数字 var field_Link = "/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[1]/div/div/div[4]";//链接 var field_Date = "/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[1]/div/div/div[5]";//日期 var field_StartStopTime = "/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[1]/div/div/div[6]";//起止时间 var field_Phone = "/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[1]/div/div/div[7]";//电话 var field_Mailbox = "/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[1]/div/div/div[8]";//邮箱 var field_AloneChoice = "/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[1]/div/div/div[9]";//单项选择 var field_DropDownChoice = "/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[1]/div/div/div[10]";//下拉选择 //@注册基础元素-字段基础参数 var field_Title = "/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[3]/qf-edit-area/div/qf-function-lock/qf-title-and-hint/div[2]/input";//字段标题 var fieldParameter_Required = "/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[3]/qf-edit-area/div/qf-function-lock/div[2]/label";//必填 var fieldParameter_QRCode = "/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[3]/qf-edit-area/div/qf-function-lock/div[2]/label";//扫码(默认二维码) var fieldParameter_BarCode = "/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[3]/qf-edit-area/div/qf-function-lock/div[2]/qf-radio-group/label[2]";//扫码-条形码 var fieldParameter_NotDuplicateValue= ""//不允许重复值 //@注册基础元素-字段高级参数 var fieldParameter_AssociateExistingData= "";//关联已有数据 var fieldParameter_LimitWords= "";//限制字数 var fieldParameter_DecimalsAllowed= "";//允许小数 var fieldParameter_DisplayAmount= ""//显示金额 var fieldParameter_TimeFormat= "";//时间格式 var fieldParameter_TimeOverlapNotAllowed= "";//不允许时间重叠 var fieldParameter_FixedTelephone= "";//支持固定电话 var fieldParameter_SMSVerification= "";//短信验证 var fieldParameter_OptionContent= "";//选项内容 //打印控制台版本信息 console.log("=====================================================================") console.log("|| @name QingFlow Dragon King Super Tools") console.log("|| @version 体验版本0.1") console.log("|| @description 轻流QingFlow应用自动超级字段插件") console.log("|| @author Mr.Dragon King") console.log("|| @license Mr.Dragon King") console.log("=====================================================================") console.log("Hello,欢迎使用【QingFlow Dragon King Super Tools】\n轻流QingFlow应用自动超级字段插件🐲\n\n@author Mr.Dragon King \n@version 0.2\n\n使用帮助:\nhttps://www.yuque.com/g/mrscott-prexr/bgia0r/hfwq3pdgm0y7m50i/collaborator/join?token=Je5Br7K9hrV1R8FE# 《QingFlow Dragon King Super Tools使用帮助》\n\n更多信息可联系作者"); //@jquery库 function jquery() { var myScript = document.createElement('script'); myScript.src = 'https://cdn.bootcss.com/jquery/3.3.1/jquery.js'; document.getElementsByTagName('head')[0].appendChild(myScript); } //@XPath方法 function $x(STR_XPATH) { var xresult = document.evaluate(STR_XPATH, document, null, XPathResult.ANY_TYPE, null); var xnodes = []; var xres; while (xres = xresult.iterateNext()) { xnodes.push(xres); } return xnodes; } //@页面启动 (function () { //加载库 setTimeout(function () { jquery(); Menu(); //alert("Hello,欢迎使用【QingFlow Dragon King Super Tools】\n轻流QingFlow应用自动超级字段插件🐲\n\n@author Mr.Dragon King \n@version 0.2\n\n使用帮助:\nhttps://www.yuque.com/g/mrscott-prexr/bgia0r/hfwq3pdgm0y7m50i/collaborator/join?token=Je5Br7K9hrV1R8FE# 《QingFlow Dragon King Super Tools使用帮助》\n\n更多信息可联系作者"); }, 4000); })(); $(function () { $(document).on("click", "#a", function () { console.log("优化界面完成") }); }); //@菜单menu function Menu() { setInterval(function(){ if(window.location.href.slice(0,23) == "https://qingflow.com/f/" && $x("/html/body/qf-root/qf-pages/qf-app-item/qf-creation/qf-header-edit/div").length<=0){ var BatchAddFields = "";//批量添加字段按钮 var Help = "";//插件使用帮助按钮 var SystemDesignDrawing = "";//系统设计图 var PageOptimization = "";//界面优化 $("body > qf-root > qf-pages > qf-app-item > qf-creation > qf-header-edit > header").before("
" + BatchAddFields + PageOptimization + Help + SystemDesignDrawing + "
"); } },2000); } //@插件使用帮助Help $(function () { $(document).on("click", "#Help", function () { alert("Hello,欢迎使用【QingFlow Dragon King Super Tools】\n轻流QingFlow应用自动超级字段插件🐲\n插件使用帮助文档待上传,当前如存在使用问题可联系作者!!!"); }); }); //@轻流系统设计图SystemDesignDrawing $(function () { $(document).on("click", "#SystemDesignDrawing", function () { window.open("https://exiao.yuque.com/pc5k40/ngqg4r/oucgap?singleDoc", "_blank"); }); }); //@面板界面优化PageOptimization $(function () { $(document).on("click", "#PageOptimization", function () { PageOptimizationOpen = true; setTimeout(() => { $x("/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[3]")[0].style.cssText = "width:350px"; console.log("优化界面完成") }, 1000) }); }); //@批量添加字段BatchAddFields $(function () { $(document).on("click", "#BatchAddFields", function () { BatchAddFields(); }); }); //@解析文字算法AnalysisOfConstructionContent function AnalysisOfConstructionContent(InputData) { InputData = InputData.replace(/\ +/g, ""); InputData = InputData.replace(/[\r\n]/g, ""); var FieldAnalysisData = [];//解析结果 var fieldData = {//字段数据 type: "",//字段类型 title: "",//字段标题 parameter: [],//字段参数 } var fieldData_parameter_textData = "";//解析参数字段内容 二次解析内容 var distinguishType = 0;//识别类型 1为字段类型 2为字段名称 3为参数 for (let textLengthIndex = 0; InputData.length > textLengthIndex; textLengthIndex++) { if (InputData[textLengthIndex] == "【") { //校验字段类型添加 //识别上个字段内容并添加到字段信息中 if (fieldData.type.length != 0) { FieldAnalysisData.push(fieldData); //初始化值 fieldData = {//字段数据 type: "",//字段类型 title: "",//字段标题 parameter: [],//字段参数 } fieldData_parameter_textData = "";//解析参数字段内容 二次解析内容 } else { } //转换识别类型 为1 字段类型 distinguishType = 1; } if (InputData[textLengthIndex] == "】") { //校验字段类型添加结束,添加字段标题 fieldData.type = `${fieldData.type}${InputData[textLengthIndex]}`; distinguishType = 2; } if (InputData[textLengthIndex] == "(" || InputData[textLengthIndex] == "(") { //校验字段标题添加结束,添加字段参数 distinguishType = 3; } if (distinguishType == 1) { fieldData.type = `${fieldData.type}${InputData[textLengthIndex]}` } if (distinguishType == 2) { if (InputData[textLengthIndex] != "】") { fieldData.title = `${fieldData.title}${InputData[textLengthIndex]}` } } if (distinguishType == 3) { if (InputData[textLengthIndex] != "(" && InputData[textLengthIndex] != "(") { if (InputData[textLengthIndex] == ")" || InputData[textLengthIndex] == ")") { if (fieldData_parameter_textData.length == 0) { } else { let outfieldData_parameter_textData = ResolveFieldParameters(fieldData_parameter_textData) if (outfieldData_parameter_textData.type == "非注册参数") { alert(`Hello,欢迎使用【QingFlow Dragon King Super Tools】\n轻流QingFlow应用自动超级字段插件🐲\n\n@author Mr.Dragon King \n@version 0.2\n\n【非注册参数】\n发现未注册的字段参数,错误参数将无法进行添加到字段中!!!\n\n${fieldData.type}${fieldData.title}(${fieldData_parameter_textData})\n\n如有疑问可仔细查阅插件帮助文档,更多信息可联系作者!`); fieldData_parameter_textData = ""; } else { fieldData.parameter.push(outfieldData_parameter_textData) fieldData_parameter_textData = ""; } } } else { if (InputData[textLengthIndex] == ";" || InputData[textLengthIndex] == ";") { let outfieldData_parameter_textData = ResolveFieldParameters(fieldData_parameter_textData) if (outfieldData_parameter_textData.type == "非注册参数") { alert(`Hello,欢迎使用【QingFlow Dragon King Super Tools】\n轻流QingFlow应用自动超级字段插件🐲\n\n@author Mr.Dragon King \n@version 0.2\n\n【非注册参数】\n发现未注册的字段参数,错误参数将无法进行添加到字段中!!!\n\n${fieldData.type}${fieldData.title}(${fieldData_parameter_textData})\n\n如有疑问可仔细查阅插件帮助文档,更多信息可联系作者!`); fieldData_parameter_textData = ""; } else { fieldData.parameter.push(outfieldData_parameter_textData) fieldData_parameter_textData = ""; } } else { fieldData_parameter_textData = `${fieldData_parameter_textData}${InputData[textLengthIndex]}` } } } } if (textLengthIndex == InputData.length - 1) { console.log("字段校验完成判断是否存在fieldData数据...") if (fieldData.type.length != 0) { console.log("存在fieldData数据,添加到FieldAnalysisData") FieldAnalysisData.push(fieldData); console.log("添加到FieldAnalysisData完成") } else { console.log("不存在fieldData数据,添加到FieldAnalysisData") } //初始化值 fieldData = {//字段数据 type: "",//字段类型 title: "",//字段标题 parameter: [],//字段参数 } fieldData_parameter_textData = "";//解析参数字段内容 二次解析内容 console.log("【QingFlow Dragon King Super Tools】-->字段解析完成:", FieldAnalysisData) AddField(FieldAnalysisData); } } } //@解析字段参数算法ResolveFieldParameters function ResolveFieldParameters(fieldData_parameter_textData) { fieldData_parameter_textData = fieldData_parameter_textData.replace(/\ +/g, ""); fieldData_parameter_textData = fieldData_parameter_textData.replace(/[\r\n]/g, ""); var fieldData_parameter = { type: "",//参数类型 };//缓存字段参数 switch (fieldData_parameter_textData) { case "必填": { fieldData_parameter.type = "必填"; } break; case "二维码": { fieldData_parameter.type = "二维码"; } break; case "条形码": { fieldData_parameter.type = "条形码"; } break; case "不允许重复值": { fieldData_parameter.type = "不允许重复值"; } break; case "金额¥": { fieldData_parameter.type = "金额¥"; } break; case "金额$": { fieldData_parameter.type = "金额$"; } case "不允许时间重叠": { fieldData_parameter.type = "不允许时间重叠"; } break; case "年": { fieldData_parameter.type = "年"; } break; case "年月": { fieldData_parameter.type = "年月"; } break; case "年月日": { fieldData_parameter.type = "年月日"; } break; case "年月日时分": { fieldData_parameter.type = "年月日时分"; } break; case "年月日时分秒": { fieldData_parameter.type = "年月日时分秒"; } case "固定电话": { fieldData_parameter.type = "年月日时分秒"; } break; case "短信验证": { fieldData_parameter.type = "年月日时分秒"; } break; default: { if (fieldData_parameter_textData.slice(1, 7) == "关联已有数据") { fieldData_parameter.type = "关联已有数据"; var DataType = 1 var AssociateExistingData = { "app": "", "field": "", } for (let index = 8; index < fieldData_parameter_textData.length; index++) { if (DataType == 1) { if (fieldData_parameter_textData[index] != "-") { AssociateExistingData.app = `${AssociateExistingData.app}${fieldData_parameter_textData[index]}` } else { DataType = 2; } } if (DataType == 2) { if (fieldData_parameter_textData[index] != "/" && fieldData_parameter_textData[index] != "-") { AssociateExistingData.field = `${AssociateExistingData.field}${fieldData_parameter_textData[index]}` } } } fieldData_parameter["AssociateExistingData"] = AssociateExistingData; } else { fieldData_parameter.type = "非注册参数"; } } } return fieldData_parameter; } //@触发批量添加字段BatchAddFields function BatchAddFields() { var InputValue = prompt("Hello,欢迎使用【QingFlow Dragon King Super Tools】\n轻流QingFlow应用自动超级字段插件🐲\n@author Mr.Dragon King \n@version 0.2\n\n请批量输入字段信息", "【单行文本】字段名称"); if (InputValue != null && InputValue != "") { AnalysisOfConstructionContent(InputValue) } } var fieldloopIndex = 0; //@添加字段AddField async function AddField(FieldAnalysisData) { switch (FieldAnalysisData[fieldloopIndex].type) { case "【单行文本】": { await Add_field_Textfield(); await fieldTitle(FieldAnalysisData[fieldloopIndex].title); await inputEvent(field_Title); for (let Parameter_index = 0; Parameter_index < FieldAnalysisData[fieldloopIndex].parameter.length; Parameter_index++) { if (FieldAnalysisData[fieldloopIndex].parameter[Parameter_index].type == "关联已有数据") { await ToggleDefault(); await Choice_AssociateExistingData(); await Choice_AssociateExistingData_App(); await Choice_AssociateExistingData_AppInput(FieldAnalysisData[fieldloopIndex].parameter[Parameter_index].AssociateExistingData.app); await Choice_AssociateExistingData_AppInputOut(); await Choice_AssociateExistingData_AppChoice(); await Choice_AssociateExistingData_Field(); await Choice_AssociateExistingData_FieldInput(FieldAnalysisData[fieldloopIndex].parameter[Parameter_index].AssociateExistingData.field); await Choice_AssociateExistingData_FieldInputOut(); await Choice_AssociateExistingData_FieldChoice(); } else { await Textfield_Parameter(FieldAnalysisData[fieldloopIndex].parameter[Parameter_index]) } } } break; case "【多行文本】": { await Add_field_Textarea(); await fieldTitle(FieldAnalysisData[fieldloopIndex].title); await inputEvent(field_Title); for (let Parameter_index = 0; Parameter_index < FieldAnalysisData[fieldloopIndex].parameter.length; Parameter_index++) { if (FieldAnalysisData[fieldloopIndex].parameter[Parameter_index].type == "关联已有数据") { await ToggleDefault(); await Choice_AssociateExistingData(); await Choice_AssociateExistingData_App(); await Choice_AssociateExistingData_AppInput(FieldAnalysisData[fieldloopIndex].parameter[Parameter_index].AssociateExistingData.app); await Choice_AssociateExistingData_AppInputOut(); await Choice_AssociateExistingData_AppChoice(); await Choice_AssociateExistingData_Field(); await Choice_AssociateExistingData_FieldInput(FieldAnalysisData[fieldloopIndex].parameter[Parameter_index].AssociateExistingData.field); await Choice_AssociateExistingData_FieldInputOut(); await Choice_AssociateExistingData_FieldChoice(); } else { await Textarea_Parameter(FieldAnalysisData[fieldloopIndex].parameter[Parameter_index]) } } } break; default: { console.log("未注册字段", FieldAnalysisData[fieldloopIndex].type) } } fieldloopIndex = fieldloopIndex + 1; if (fieldloopIndex < FieldAnalysisData.length) { AddField(FieldAnalysisData) } else { fieldloopIndex = 0; } } //@设置字段标题 fieldTitle function fieldTitle(title) { return new Promise(resolve => { setTimeout(() => { $x(field_Title)[0].value = title; resolve()//成功态 }, 500) }) } //@输入结束 InputEvent function inputEvent(data) { return new Promise(resolve => { $x(data)[0].dispatchEvent(new InputEvent("input")); resolve()//成功态 }) } //@添加单行文字field_Textfield function Add_field_Textfield() { return new Promise(resolve => { setTimeout(() => { $x(field_Textfield)[0].click(); resolve()//成功态 }, 500) }) } //@添加多行文字Add_field_Textarea function Add_field_Textarea() { return new Promise(resolve => { setTimeout(() => { $x(field_Textarea)[0].click(); resolve()//成功态 }, 500) }) } //=================================字段参数【单行文本参数】================================= //@添加单行文本参数Textfield_Parameter async function Textfield_Parameter(parameter) { return new Promise(resolve => { setTimeout(() => { switch (parameter.type) { case "必填": { $x("/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[3]/qf-edit-area/div/qf-function-lock/div[1]/label")[0].click() } break; case "二维码": { $x("/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[3]/qf-edit-area/div/qf-function-lock/div[2]/label")[0].click() } break; case "条形码": { $x("/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[3]/qf-edit-area/div/qf-function-lock/div[2]/label")[0].click() setTimeout(() => { $x("/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[3]/qf-edit-area/div/qf-function-lock/div[2]/qf-radio-group/label[2]")[0].click() }, 200) } break; case "不允许重复值": { $x("/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[3]/qf-edit-area/div/qf-function-lock/div[3]/label")[0].click() } break; default: { console.log("未注册字段参数") } } resolve()//成功态 }, 500) }) } //=================================字段参数【多行文本参数】================================= //@添加多行文本参数Textarea_Parameter async function Textarea_Parameter(parameter) { return new Promise(resolve => { setTimeout(() => { switch (parameter.type) { case "必填": { $x("/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[3]/qf-edit-area/div/qf-function-lock/div[1]/label")[0].click() } break; case "不允许重复值": { $x("/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[3]/qf-edit-area/div/qf-function-lock/div[3]/label")[0].click() } break; default: { console.log("未注册字段参数") } } resolve()//成功态 }, 500) }) } //=================================特殊参数【关联已有数据】================================= //@切换默认 ToggleDefault function ToggleDefault() { return new Promise(resolve => { setTimeout(() => { $x("/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[3]/qf-edit-area/div/qf-function-lock/qf-dft-val-edit/div/qf-select/qf-select-top-control/qf-select-item")[0].click() resolve()//成功态 }, 200) }) } //@切换关联已有数据 ChoiceAssociateExistingData function Choice_AssociateExistingData() { return new Promise(resolve => { setTimeout(() => { $x("/html/body/div[3]/div[2]/div/qf-option-container/div[2]/cdk-virtual-scroll-viewport/div[1]/div/qf-option-item[2]")[0].click() resolve()//成功态 }, 200) }) } //@触发关联已有数据的应用 Choice_AssociateExistingData_App function Choice_AssociateExistingData_App() { return new Promise(resolve => { setTimeout(() => { $x("/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[3]/qf-edit-area/div/qf-function-lock/qf-dft-val-edit/div/qf-function-lock/qf-dft-associate-data/div[1]/qf-select[1]/qf-select-top-control/div[1]/input")[0].click() resolve()//成功态 }, 200) }) } //@关联已有数据的应用名称输入 Choice_AssociateExistingData_AppInput function Choice_AssociateExistingData_AppInput(appName) { return new Promise(resolve => { setTimeout(() => { $x("/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[3]/qf-edit-area/div/qf-function-lock/qf-dft-val-edit/div/qf-function-lock/qf-dft-associate-data/div[1]/qf-select[1]/qf-select-top-control/div[1]/input")[0].value = appName; resolve()//成功态 }, 200) }) } //@关联已有数据的应用名称输入结束 Choice_AssociateExistingData_AppInputOut function Choice_AssociateExistingData_AppInputOut() { return new Promise(resolve => { setTimeout(() => { $x("/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[3]/qf-edit-area/div/qf-function-lock/qf-dft-val-edit/div/qf-function-lock/qf-dft-associate-data/div[1]/qf-select[1]/qf-select-top-control/div[1]/input")[0].dispatchEvent(new InputEvent("input")); resolve()//成功态 }, 200) }) } //@关联已有数据的应用选择Choice_AssociateExistingData_AppInputOut function Choice_AssociateExistingData_AppChoice() { return new Promise(resolve => { setTimeout(() => { if ($x("/html/body/div[3]/div[2]/div/qf-option-container/div[2]/cdk-virtual-scroll-viewport/div[1]/div/qf-option-item").length == 1) { $x("/html/body/div[3]/div[2]/div/qf-option-container/div[2]/cdk-virtual-scroll-viewport/div[1]/div/qf-option-item")[0].click() } resolve()//成功态 }, 200) }) } //@触发关联已有数据的字段 Choice_AssociateExistingData_Field function Choice_AssociateExistingData_Field() { return new Promise(resolve => { setTimeout(() => { $x("/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[3]/qf-edit-area/div/qf-function-lock/qf-dft-val-edit/div/qf-function-lock/qf-dft-associate-data/div[1]/qf-select[2]/qf-select-top-control/div[1]/input")[0].click() resolve()//成功态 }, 200) }) } //@关联已有数据的字段名称输入 Choice_AssociateExistingData_FieldInput function Choice_AssociateExistingData_FieldInput(fieldName) { return new Promise(resolve => { setTimeout(() => { $x("/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[3]/qf-edit-area/div/qf-function-lock/qf-dft-val-edit/div/qf-function-lock/qf-dft-associate-data/div[1]/qf-select[2]/qf-select-top-control/div[1]/input")[0].value = fieldName; resolve()//成功态 }, 200) }) } //@关联已有数据的字段名称输入结束 Choice_AssociateExistingData_FieldInputOut function Choice_AssociateExistingData_FieldInputOut() { return new Promise(resolve => { setTimeout(() => { $x("/html/body/qf-root/qf-pages/qf-app-item/qf-creation/div/div[3]/qf-edit-area/div/qf-function-lock/qf-dft-val-edit/div/qf-function-lock/qf-dft-associate-data/div[1]/qf-select[2]/qf-select-top-control/div[1]/input")[0].dispatchEvent(new InputEvent("input")); resolve()//成功态 }, 200) }) } //@关联已有数据的字段选择Choice_AssociateExistingData_FieldChoice function Choice_AssociateExistingData_FieldChoice() { return new Promise(resolve => { setTimeout(() => { if ($x("/html/body/div[3]/div[2]/div/qf-option-container/div[2]/cdk-virtual-scroll-viewport/div[1]/div/qf-option-item").length == 1) { $x("/html/body/div[3]/div[2]/div/qf-option-container/div[2]/cdk-virtual-scroll-viewport/div[1]/div/qf-option-item")[0].click() } resolve()//成功态 }, 200) }) } //======================================================================================