WPS Usage Summary

authorcontenttime
JJWPS related issues20220110

WPS windows system (A6 project suggests ActiveX, IE+360 compatibility mode)

1. Load wps control

html(word)

	<div id="app" style="height:100%;width:100%" v-cloak>
     <div id="wps"  style="height:100%;width:100%" ></div>
   </div>

js

var vm = new Vue({
    el: '#app',
    data: function () {
        return {
            //url parameter
            urlParams: null,
            DocFrame: null,
            MenuItems: {
                FILE: 1 << 0,
                EDIT: 1 << 1,
                VIEW: 1 << 2,
                INSERT: 1 << 3,
                FORMAT: 1 << 4,
                TOOL: 1 << 5,
                CHART: 1 << 6,
                HELP: 1 << 7
            },
            FileSubmenuItems: {
                NEW: 1 << 0,
                OPEN: 1 << 1,
                CLOSE: 1 << 2,
                SAVE: 1 << 3,
                SAVEAS: 1 << 4,
                PAGESETUP: 1 << 5,
                PRINTPY: 1 << 6,
                PRINT: 1 << 7,
                PROPERTY: 1 << 8
            }
        }
    },
    methods: {
        //Initialize obj
        init: function (tagID, width, height) {
            var iframe;
            var obj;
            var _this = this;
            iframe = document.getElementById(tagID);
            var codes = [];
            codes.push('<object id=DocFrame1 height=' + height + ' width=' + width + ' ');
            codes.push('data=data:application/x-oleobject;base64,7Kd9juwHQ0OBQYiirbY6XwEABAA7DwMAAgAEAB0AAAADAAQAgICAAAQABAD///8ABQBcAFgAAABLAGkAbgBnAHMAbwBmAHQAIABBAGMAdABpAHYAZQBYACAARABvAGMAdQBtAGUAbgB0ACAARgByAGEAbQBlACAAQwBvAG4AdAByAG8AbAAgADEALgAwAAAA ');
            codes.push('classid=clsid:8E7DA7EC-07EC-4343-8141-88A2ADB63A5F viewastext=VIEWASTEXT></object> ');
            iframe.innerHTML = codes.join("");
            obj = document.getElementById("DocFrame1");
            var fn = function () {
                //User request to save document (ctrl+s)
                function obj

                ::OnRequireSave()
                {
                    _this.onRequireSave()
                }

                //User save (toolbar save)
                function obj

                ::OnDocumentBeforeSave()
                {
                    _this.onDocumentBeforeSave()
                }

            };
            fn();
            return obj;
        },
        //Initialize plug-in
        initFrame: function () {
            this.DocFrame = this.init("wps", "100%", "100%");
            //Hide the close button to allow only the browser tab to close
            this.DocFrame.FileSubmenuItems &= ~[this.FileSubmenuItems.CLOSE];
        },
        // New document
        createDocument: function () {
            this.DocFrame.createDocument("uot");
        },
        // Open remote document
        // pathUrl is required
        // readOnly is not required. If it is true, it means to open as read-only; otherwise, it means to open as editable and not as read-only.
        openDocumentRemote: function (pathUrl, readOnly) {
            this.DocFrame.openDocumentRemote(pathUrl, readOnly == undefined ? true : readOnly);
        },
        //User request to save Document event
        onRequireSave: function () {
            console.log("User request to save document");
        },
        //User save event
        onDocumentBeforeSave: function () {
            console.log("User save");
        },
        // Save to remote
        saveURL: function (url, fileName) {
            this.DocFrame.saveURL(url, fileName);
        },
        // Protect document true protect document (read-only) false stop protection (editable)
        enableProtect: function (flag) {
            this.DocFrame.enableProtect(flag);
        },
    },
    created: function () {
    		//Get url parameters
        this.urlParams = getUrlParams()
    },
    mounted: function () {
        var _this = this;
        //Initialize plug-in
        this.initFrame();
        //If it exists, open the remote url
        if (this.urlParams.type) {
            this.openDocumentRemote('http://172.26.18.58:8088/didi filling instructions docx')
        } else {
            this.createDocument()
        }
    }
});

html(Excel)

 <div id="app" style="height:100%;width:100%" v-cloak>
     <div id="et" style="height:100%;width:100%"></div>
 </div>

js

var vm = new Vue({
    el: '#app',
    data: function () {
        return {
            //url parameter
            urlParams: null,
            DocFrame: null,
            MenuItems: {
                FILE: 1 << 0,
                EDIT: 1 << 1,
                VIEW: 1 << 2,
                INSERT: 1 << 3,
                FORMAT: 1 << 4,
                TOOL: 1 << 5,
                CHART: 1 << 6,
                HELP: 1 << 7
            },
            FileSubmenuItems: {
                NEW: 1 << 0,
                OPEN: 1 << 1,
                CLOSE: 1 << 2,
                SAVE: 1 << 3,
                SAVEAS: 1 << 4,
                PAGESETUP: 1 << 5,
                PRINT: 1 << 6,
                PROPERTY: 1 << 7
            }
        }
    },
    methods: {
        //Initialize obj
        init: function (tagID, width, height) {
            var iframe;
            var obj;
            var _this = this;
            iframe = document.getElementById(tagID);
            var codes = [];
            codes.push('<object id=DocFrame1 height=' + height + ' width=' + width + ' ');
            codes.push('data=data:application/x-oleobject;base64,7Kd9juwHQ0OBQYiirbY6XwEABAA7DwMAAgAEAB0AAAADAAQAgICAAAQABAD///8ABQBcAFgAAABLAGkAbgBnAHMAbwBmAHQAIABBAGMAdABpAHYAZQBYACAARABvAGMAdQBtAGUAbgB0ACAARgByAGEAbQBlACAAQwBvAG4AdAByAG8AbAAgADEALgAwAAAA ');
            codes.push('classid=clsid:8E7DA7EC-07EC-4343-8141-88A2ADB63A5F viewastext=VIEWASTEXT></object> ');
            iframe.innerHTML = codes.join("");
            obj = document.getElementById("DocFrame1");
            var fn = function () {
                //User request to save document (ctrl+s)
                function obj

                ::OnRequireSave()
                {
                    _this.onRequireSave()
                }

                //User save (toolbar save)
                function obj

                ::OnDocumentBeforeSave()
                {
                    _this.onDocumentBeforeSave()
                }
            };
            fn();
            return obj;
        },
        //Initialize plug-in
        initFrame: function () {
            this.DocFrame = this.init("et", "100%", "100%");
            this.DocFrame.AppModeType = "et";
            //Hide the close button to allow only the browser tab to close
            this.DocFrame.FileSubmenuItems &= ~[this.FileSubmenuItems.CLOSE];
        },
        // New document
        createDocument: function () {
            this.DocFrame.createDocument("uos");
        },
        // Open remote document
        // pathUrl is required
        // readOnly is not required. If it is true, it means to open as read-only; otherwise, it means to open as editable and not as read-only.
        openDocumentRemote: function (pathUrl, readOnly) {
            this.DocFrame.openDocumentRemote(pathUrl, readOnly == undefined ? true : readOnly);
        },
        //User request to save document
        onRequireSave: function () {
            console.log("User request to save document");
        },
        //User save
        onDocumentBeforeSave: function () {
            console.log("User save");
        },
        // Save to remote
        saveURL: function (url, fileName) {
            this.DocFrame.saveURL(url, fileName);
        },
        // Protect document true protect document (read-only) false stop protection (editable)
        enableProtect: function (flag) {
            this.DocFrame.enableProtect(flag);
        },
    },
    created: function () {
        this.urlParams = getUrlParams()
    },
    mounted: function () {
        var _this = this;
        //Initialize plug-in
        this.initFrame();
        //If it exists, open the remote url
        if (this.urlParams.type) {
            this.openDocumentRemote('http://172.26.18.58:8088 / annual conference program & host registration information form xlsx')
        } else {
            this.createDocument()
        }
    }
});

html

<div id="app" style="height:100%;width:100%" v-cloak>
   <div id="wpp" style="height:100%;width:100%"></div>
</div>

js

var vm = new Vue({
	el: '#app',
	data: function () {
		return {
			//url parameter
			urlParams: null,
			DocFrame: null,
			MenuItems: {
				FILE: 1 << 0,
				EDIT: 1 << 1,
				VIEW: 1 << 2,
				INSERT: 1 << 3,
				FORMAT: 1 << 4,
				TOOL: 1 << 5,
				CHART: 1 << 6,
				HELP: 1 << 7
			},
			FileSubmenuItems: {
				NEW: 1 << 0,
				OPEN: 1 << 1,
				CLOSE: 1 << 2,
				SAVE: 1 << 3,
				SAVEAS: 1 << 4,
				PAGESETUP: 1 << 5,
				PRINTPY: 1 << 6,
				PRINT: 1 << 7,
				PROPERTY: 1 << 8
			}
		}
	},
	methods: {
		//Initialize obj
		init: function (tagID, width, height) {
			var iframe;
			var obj;
			var _this = this;
			iframe = document.getElementById(tagID);
			var codes = [];
			codes.push('<object id=DocFrame1 height=' + height + ' width=' + width + ' ');
			codes.push('data=data:application/x-oleobject;base64,7Kd9juwHQ0OBQYiirbY6XwEABAA7DwMAAgAEAB0AAAADAAQAgICAAAQABAD///8ABQBcAFgAAABLAGkAbgBnAHMAbwBmAHQAIABBAGMAdABpAHYAZQBYACAARABvAGMAdQBtAGUAbgB0ACAARgByAGEAbQBlACAAQwBvAG4AdAByAG8AbAAgADEALgAwAAAA ');
			codes.push('classid=clsid:8E7DA7EC-07EC-4343-8141-88A2ADB63A5F viewastext=VIEWASTEXT></object> ');
			iframe.innerHTML = codes.join("");
			obj = document.getElementById("DocFrame1");
			var fn = function () {
				//User request to save document (ctrl+s)
				function obj

				::OnRequireSave()
				{
					_this.onRequireSave()
				}

				//User save (toolbar save)
				function obj

				::OnDocumentBeforeSave()
				{
					_this.onDocumentBeforeSave()
				}
			};
			fn();
			return obj;
		},
		//Initialize plug-in
		initFrame: function () {
			this.DocFrame = this.init("wpp", "100%", "100%");
			this.DocFrame.AppModeType = "wpp";
			//Hide the close button to allow only the browser tab to close
			this.DocFrame.FileSubmenuItems &= ~[this.FileSubmenuItems.CLOSE];
		},
		// New document
		createDocument: function () {
			this.DocFrame.createDocument("uop");
		},
		// Open remote document
		// pathUrl is required
		// readOnly is not required. If it is true, it means to open as read-only; otherwise, it means to open as editable and not as read-only.
		openDocumentRemote: function (pathUrl, readOnly) {
			this.DocFrame.openDocumentRemote(pathUrl, readOnly == undefined ? true : readOnly);
		},
		//User request to save Document event
		onRequireSave: function () {
			console.log("User request to save document");
		},
		//User save event
		onDocumentBeforeSave: function () {
			console.log("User save");
		},
		// Save to remote
		saveURL: function (url, fileName) {
			this.DocFrame.saveURL(url, fileName);
		},
	},
	created: function () {
		this.urlParams = getUrlParams()
	},
	mounted: function () {
		var _this = this;
		//Initialize plug-in
		this.initFrame();
		//If it exists, open the remote url
		if (this.urlParams.type) {
			this.openDocumentRemote('http://172.26.18.58:8088/architecture design v2 ppt')
		} else {
			this.createDocument()
		}
	}
});

WPS limux system

html(word)

	<div id="app" style="height:100%;width:100%" v-cloak>
     <div id="wps"  style="height:100%;width:100%" ></div>
   </div>

js

var vm = new Vue({
    el: '#app',
    data: function () {
        return {
            //url parameter
            urlParams: null,
            DocFrame: null,
        }
    },
    methods: {
        //Initialize obj
        init: function (tagID) {
            var iframe;
            var obj;
            iframe = document.getElementById(tagID);
            iframe.innerHTML = '';
            var codes = [];
            codes.push(
                "<object  name='webwps' id='id-wps' type='application/x-wps' width='100%' height='100%'> <param name='Enabled' value='1' />  </object>"
            );
            iframe.innerHTML = codes.join("");
            obj = document.getElementById("id-wps");

            window.onbeforeunload = function () {
                obj.Application.Quit();
            };
            window.onresize = function () {
                console.log("ondrag");
                obj.sltReleaseKeyboard();
            };
            return obj.Application;
        },
        //Initialize plug-in
        initFrame: function () {
            this.DocFrame = this.init("wps");
        },
        // New document
        createDocument: function () {
            //obj.EnterEditMode();// After creating a new one, you can enter quiteditmode sltrereleasekeyboard immediately
            this.DocFrame.createDocument("wps");
        },
        // Open remote document
        // pathUrl is required
        // readOnly is not required. If it is true, it means to open as read-only; otherwise, it means to open as editable and not as read-only.
        openDocumentRemote: function (pathUrl, readOnly) {
            this.DocFrame.openDocumentRemote(pathUrl, readOnly == undefined ? true : readOnly);
        },
        // Save to remote
        saveURL: function (url, fileName) {
            this.DocFrame.saveURL(url, fileName);
        },
        // Protect document true protect document (read-only) false stop protection (editable)
        enableProtect: function (flag) {
            this.DocFrame.enableProtect(flag);
        },

    },
    created: function () {
        this.urlParams = getUrlParams()
    },
    mounted: function () {
        var _this = this;
        //Initialize plug-in
        this.initFrame();
        //If it exists, open the remote url
        if (this.urlParams.type) {
            this.openDocumentRemote('http://172.26.18.58:8088/didi filling instructions docx')
        } else {
            this.createDocument()
        }

        //Register save event
        this.DocFrame.registerEvent("DIID_ApplicationEvents4", "DocumentBeforeSave", "documentBeforeSaveCallBack");
    }
});

//Save event
function documentBeforeSaveCallBack() {
    console.log('preservation')
}

html(Excel)

 <div id="app" style="height:100%;width:100%" v-cloak>
     <div id="et" style="height:100%;width:100%"></div>
 </div>

js

var vm = new Vue({
	el: '#app',
	data: function () {
		return {
			//url parameter
			urlParams: null,
			DocFrame: null,
			office:null
		}
	},
	methods: {
		//Initialize obj
		init: function (tagID) {
			if (this.DocFrame != undefined)
				this.DocFrame.Application.Quit();
			var iframe;
			var obj;
			iframe = document.getElementById(tagID);
			var codes = [];
			codes.push('<object name="rpcet" id="id-et" type="application/x-et" wpsshieldbutton="false" width="100%" height="100%">');
			codes.push('<param name="quality" value="high" />');
			codes.push('<param name="bgcolor" value="#ffffff" />');
			codes.push('<param name="Enabled" value="1" />');
			codes.push('<param name="allowFullScreen" value="true" />');
			codes.push('</object>');
			iframe.innerHTML = codes.join("");
			obj = document.getElementById("id-et");
			window.onbeforeunload = function () {
				obj.Application.Quit();
			};
			return obj.Application
		},
		//Initialize plug-in
		initFrame: function () {
			this.DocFrame = this.init("et");
		},
		// New document
		createDocument: function () {
			this.DocFrame.Workbooks.Add();
		},
		// Open remote document
		// pathUrl is required
		// readOnly is not required. If it is true, it means to open as read-only; otherwise, it means to open as editable and not as read-only.
		openDocumentRemote: function (pathUrl, readOnly) {
			this.DocFrame.openDocumentRemote_s(pathUrl, readOnly == undefined ? true : readOnly);
		},
		cs:function () {
			console.log(666)
		}
	},
	created: function () {
		this.urlParams = getUrlParams()
	},
	mounted: function () {
		var _this = this;
		//Initialize plug-in
		this.initFrame();
		//If it exists, open the remote url
		if (this.urlParams.type) {
			this.openDocumentRemote('http://172.26.18.58:8088 / annual conference program & host registration information form xlsx')
		} else {
			this.createDocument()
		}
		//Register save event
		this.DocFrame.registerEvent("DIID_AppEvents", "WorkbookBeforeSave", 'workbookBeforeSaveCallBack');
	}
});
//Save event
function workbookBeforeSaveCallBack(){
	console.log('preservation')
}

html

<div id="app" style="height:100%;width:100%" v-cloak>
   <div id="wpp" style="height:100%;width:100%"></div>
</div>

js

var vm = new Vue({
    el: '#app',
    data: function () {
        return {
            //url parameter
            urlParams: null,
            DocFrame: null,
            office: null
        }
    },
    methods: {
        //Initialize obj
        init: function (tagID) {
            if (this.DocFrame != undefined)
                this.DocFrame.Application.Quit();
            var iframe;
            var obj;
            iframe = document.getElementById(tagID);
            var codes = [];
            codes.push('<object name="rpcwpp" id="id-wpp" type="application/x-wpp" wpsshieldbutton="false" wpspath="/opt/kingsoft/wps-office/office6/wpp" data="/opt/kingsoft/wps-office/office6/mui/default/templates/newfile.dps" width="100%" height="100%">');
            codes.push('<param name="quality" value="high" />');
            codes.push('<param name="bgcolor" value="#ffffff" />');
            codes.push('<param name="Enabled" value="1" />');
            codes.push('<param name="allowFullScreen" value="true" />');
            codes.push('</object>');
            iframe.innerHTML = codes.join("");
            obj = document.getElementById("id-wpp");
            window.onbeforeunload = function () {
                obj.Application.Quit();
            };
            return obj.Application
        },
        //Initialize plug-in
        initFrame: function () {
            this.DocFrame = this.init("wpp");
        },
        // New document
        createDocument: function () {
            this.DocFrame.Presentations.Add();
        },
        // Open remote document
        // pathUrl is required
        // readOnly is not required. If it is true, it means to open as read-only; otherwise, it means to open as editable and not as read-only.
        openDocumentRemote: function (pathUrl, readOnly) {
            this.DocFrame.openDocumentRemote(pathUrl, readOnly == undefined ? true : readOnly);
        },

    },
    created: function () {
        this.urlParams = getUrlParams()
    },
    mounted: function () {
        var _this = this;
        //Initialize plug-in
        this.initFrame();
        //If it exists, open the remote url
        if (this.urlParams.type) {
            this.openDocumentRemote('http://172.26.18.58:8088/architecture design v2 ppt')
        } else {
            this.createDocument()
        }
    }
});


WPS(NPAPI)

1. Usage scenario

Developers can write JavaScript to call plug-in functions, which can be loaded by browsers that support NPAPI mechanism. The plug-in provides the secondary development technical scheme of browser OA integration, and has the characteristics of rapid development and lightweight. For enterprise users, it can be quickly integrated into the existing Web system, simplify enterprise users' operation of documents and realize document automation; For individual users, it can provide more complete and complete personalized ability.

2. Requirements of plug-in for browser

Because the WPS plug-in uses NPAPI mechanism to interact with the browser, it is required that the browser using the plug-in must support NPAPI mechanism and turn on NPAPI mechanism.

The following are common supported browsers and their versions:

  • FireFox browser 52 and versions less than 52 (NPAPI is no longer supported for versions higher than 52)
  • Chrome browser 45 and versions less than 45 (NPAPI is no longer supported for versions higher than 45)
  • 360 browser (version supporting NPAPI)
  • UOS browser (version supporting NPAPI)

3. Use examples

<!DOCTYPE   html >
<html  lang = "en" >
<head>
     <meta  charset = "UTF-8" >
     <title> wps Secondary development demonstration  </title>
</head>
<body>
     <object  type = "application/x-wps"  width = "1024"  height = "768"  id = "wps" ></object>
     <!--Pass type“ application/x-wps" To load WPS browser NPAPI Plug in and pass the width and height value-->
     <script  type = "text/javascript" >
         //To get the plug-in object of wps
         var obj  = document.getElementById( "wps" );
         //Obtain the root node of the WPS object tree, and subsequent function calls are obtained step by step according to the Application
         var Application  = obj.Application;
         //Create a new blank document
         Application.createDocument( "wps" );
         //Get document content area
         var range   = Application.ActiveDocument.Content ;
         // Insert a table with 3 rows and 5 columns in the document content area and set the table display border
         Application.ActiveDocument.Tables.Add(range, 3, 5).Borders.Enable = 1 ;
     < /script>
</body>
</html>

4. Renderings

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-pxqvyfgl-164066214261) (/ images / pasted-62. PNG)]

5. Browser Integration plug-in

Demo address: https://code.aliyun.com/zouyingfeng/wps/tree/master/oaassist/WpsOAAssist

WPS development document address: https://qn.cache.wpscdn.cn/encs/doc/office_v13/index.htm

WPS new interface description document: https://www.kdocs.cn/l/cqVyOOjyWmm8

6. Sorting of methods used in the project (app stands for Application)

1. Printing method

app.CommandBars.ExecuteMso('FilePrint')

2. Undo the last action or the last series of actions that appear in the undo list. Returns True if the undo operation is successful.
expression. Undo(Times), optional Variant the number of actions to undo.

 app.ActiveDocument.Undo(time)

3. Replace the contents of the header and footer

function replaceHeaderFooterText(name, value) {
        var headerRange;
        var footerRange;
        headerRange = app.ActiveDocument.Sections.First.Headers.Item(1).Range; //Header Range object
        if (headerRange.Find.Execute(name)) {
            headerRange.Select()
            app.ActiveDocument.Selection.TypeText(value)
        }
        footerRange = app.ActiveDocument.Sections.First.Footers.Item(1).Range; //Header Range object
        if (footerRange.Find.Execute(name)) {
            footerRange.Select()
            app.ActiveDocument.Selection.TypeText(value)
        }
    }

4.wps document content replacement

// Get document content
var range = app.ActiveDocument.Content
	// Find specific information in the area, a Boolean value indicating whether the find operation is successful (name: data to be searched)
    if (range.Find.Execute("name")) {
    //Select
    range.Select()
    //Value substitution
    if (this.value) {
    app.ActiveDocument.Selection.TypeText(this.value)
    } else {
    // No value delete
    app.Selection.Delete()
    }
 }

5.wps replace bookmark content: expression \ replaceBookMarksText(Name, ReplaceBookMarksText, NameSplit, ReplaceBookMarksTextSplit)

  • Name: bookmark name. If you replace multiple bookmarks, you need to separate multiple bookmark names with separators.
  • ReplaceBookMarksText: replaces the bookmark content.
  • NameSplit: bookmark name separator.
  • ReplaceBookMarksTextSplit: bookmark content separator.
app.replaceBookMarksText(Name, ReplaceBookMarksText);

6. Judge whether the bookmark exists and return the bookmark content

Determine whether the bookmark exists
app.ActiveDocument.Bookmarks.Exists(name)
Return bookmark content
app.ActiveDocument.Bookmarks.Item(name).Range.Text;

WPS important address

  • WPS profile OEM Ini address
    oem.ini Directory address:
    windows:
        1. Installation path\WPS Offlce\A string of numbers (version number)\offlce6\cfgs\
        2. Right click the on the left wps Text Icon==>Open file location==>Found in sibling directory cfgs catalogue
    linux:
        ordinary linux Operating system:
             /opt/kingsoft/wps-office/office6/cfgs/
        uos operating system:
            /opt/apps/cn.wps.wps-office-pro/files/kingsoft/wps-office/office6/cfgs/
  • Add in management file storage location (jsaddons directory)
    jsaddons Directory address:
    windows:
        Enter in my computer address field:%appdata%\kingsoft\wps
    linux:
        Enter in my computer address field:~/.local/share/Kingsoft/wps/

### Debugger on and using

    1. to configure oem.ini,stay support Configuration under column JsApiShowWebDebugger=true
    2. linux Required on machine quickstartoffice restart restart WPS
        ordinary linux Operating system:
            Computer terminal execution quickstartoffice restart
        uos operating system:
            Computer terminal execution cd /opt/apps/cn.wps.wps-office-pro/files/bin
            ./quickstartoffice restart
    3. WPS After opening, press with a document alt+F12(index.html Page debugger)
    4. ShowDialog and Taskpane The debugger of the page, click the pop-up window or task pane, and press F12
    If the debugger cannot be opened, it indicates that the add-on failed to load. Check whether the add-on management file is generated and whether the add-on address in the add-on management file is correct


set up wps style
[feature]
iiZ07s39XJwKSU9I2xbCu5_o10=jiZ07s39XJwk99gTmjC7T-ZA10

[Jinshan document] Galaxy Kirin+arm framework:
 wps-office_11.8.2.10422.AK.preload.sw.withsn.JCY_arm64
https://kdocs.cn/l/cisGLdaajUQ4


[Jinshan document] win: setup_CN_2052_11.8.2.10912_Professional_VBA_GDJCY.exe 
https://kdocs.cn/l/cvBoKcngNQWV

Keywords: Javascript Front-end html

Added by isurgeon on Mon, 10 Jan 2022 03:15:20 +0200