Extend Imacros with new commands?

Discussions and Tech Support specific to the iMacros Firefox add-on.
Forum rules
iMacros EOL - Attention!

The renewal maintenance has officially ended for Progress iMacros effective November 20, 2023 and all versions of iMacros are now considered EOL (End-of-Life). The iMacros products will no longer be supported by Progress (aside from customer license issues), and these forums will also no longer be moderated from the Progress side.

Thank you again for your business and support.

Sincerely,
The Progress Team

Before asking a question or reporting an issue:
1. Please review the list of FAQ's.
2. Use the search box (at the top of each forum page) to see if a similar problem or question has already been addressed.
3. Try searching the iMacros Wiki - it contains the complete iMacros reference as well as plenty of samples and tutorials.
4. We can respond much faster to your posts if you include the following information: CLICK HERE FOR IMPORTANT INFORMATION TO INCLUDE IN YOUR POST
Post Reply
kjemmo
Posts: 6
Joined: Fri Nov 25, 2011 1:15 pm

Extend Imacros with new commands?

Post by kjemmo » Wed Nov 20, 2013 8:44 am

Hi.

I really appreciate Imacros and all the options it delivers out of the box.

Still there is a few things that I would like to add and I wonder if it is possible to extend Imacros?

Here is what I want to achieve:

I need to fill some complex forms and have developed a simple FF plugin that fill in the all the fields with data from a sqlite DB. Now I wonder if I can make my workflow even easier by adding automation from Imacros.

The problem is that I can not access my plugin with Imacros.

So I wonder if I can extend Imacros with a custom command like FILLFORM, either by javascript or Imacros sripting.

Or is there any other way that I can call my plugin from Imacros.

Thanks.
chivracq
Posts: 10301
Joined: Sat Apr 13, 2013 1:07 pm
Location: Amsterdam (NL)

Re: Extend Imacros with new commands?

Post by chivracq » Sat Nov 23, 2013 6:44 pm

Very interesting question in my opinion, I'm very curious what the answer by TechSupport will be and I will give you my thoughts after that...
- (F)CI(M) = (Full) Config Info (Missing): iMacros + Browser + OS (+ all 3 Versions + 'Free'/'PE'/'Trial').
- FCI not mentioned: I don't even read the Qt...! (or only to catch Spam!)
- Script & URL help a lot for more "educated" Help...
kjemmo
Posts: 6
Joined: Fri Nov 25, 2011 1:15 pm

Re: Extend Imacros with new commands?

Post by kjemmo » Mon Nov 25, 2013 6:07 pm

Just bumping the thread in hope for a reply.
chivracq
Posts: 10301
Joined: Sat Apr 13, 2013 1:07 pm
Location: Amsterdam (NL)

Re: Extend Imacros with new commands?

Post by chivracq » Thu Nov 28, 2013 4:19 pm

Like 'kjemmo', any chance for a Reply / some Feedback from TechSupport on this Thread...?
- (F)CI(M) = (Full) Config Info (Missing): iMacros + Browser + OS (+ all 3 Versions + 'Free'/'PE'/'Trial').
- FCI not mentioned: I don't even read the Qt...! (or only to catch Spam!)
- Script & URL help a lot for more "educated" Help...
chivracq
Posts: 10301
Joined: Sat Apr 13, 2013 1:07 pm
Location: Amsterdam (NL)

Re: Extend Imacros with new commands?

Post by chivracq » Fri Dec 13, 2013 3:29 am

Bumping...!
- (F)CI(M) = (Full) Config Info (Missing): iMacros + Browser + OS (+ all 3 Versions + 'Free'/'PE'/'Trial').
- FCI not mentioned: I don't even read the Qt...! (or only to catch Spam!)
- Script & URL help a lot for more "educated" Help...
siniy
Posts: 118
Joined: Sat Nov 07, 2009 7:44 pm

Re: Extend Imacros with new commands?

Post by siniy » Mon Dec 16, 2013 12:39 pm

I'm not aware about extending commands. But we can access page DOM with javascript interface.
If you run this script on this page it will search word "javascript" on this forum. I think I saw somebody here using external libs like jQuery in his script.

Code: Select all

window.document.getElementById("search_keywords").value = "javascript";
iimPlay("CODE:WAIT SECONDS=3");
window.document.getElementsByClassName("button2")[0].click()
chivracq
Posts: 10301
Joined: Sat Apr 13, 2013 1:07 pm
Location: Amsterdam (NL)

Re: Extend Imacros with new commands?

Post by chivracq » Thu Dec 19, 2013 1:44 pm

OK, pity TechSupport never reacted on this Thread, I will give my thoughts:

Next to Siniy's Method and using External Libraries like jQuery (which doesn't seem to work smoothly OOTB with iMacros, see a few Threads on the Forum...) my idea for kjemmo was that, if you are at the technical knowledge of writing your own Plugin for Firefox, why, if calling it from iMacros is problematic, don't you (try to) include it natively into iMacros to create your own customized iMacros Add-on...?

(Don't expect Support from TechSupport of course if anything goes wrong!, but in my experience it's usually very clear when something went wrong as the Add-on becomes straight away unusable if you make the slightest mistake and you have to reinstall iMacros from scratch.)

I use this Technique myself to customize the GUI a bit in a fun way or sometimes to revert to a previous Functionality when new Changes are introduced in a new Version that I don't like and I was thinking of implementing myself some Enhancement Request I have filled about !LOOP_MAX if it takes too long from Development to implement it...
And of course, at each new Version of iMacros, you need to reapply your Customizations...

The Method I use consists to unzip (I use 7-Zip but any "good" Zipper will do the job...) the .XPI File of the Add-on, then unzip again the 'imacros.jar' (located in the 'chrome' Directory), make the Changes I want to make using 'EDIT' from within 7-Zip, apply the Changes from within 7-Zip in order to rejar 'imacros.jar' (can be done manually but it's much easier from within 7-Zip) rezip the whole Root Directory with .XPI Extension and install my own customized iMacros to Firefox.

If locating the "raw" .XPI File before it gets installed more or less automatically by and to Firefox is problematic, you'll find the 'imacros.jar' File in the 'extensions' Folder in your Firefox Profile where you can modify it on the fly in the way I described above (and Firefox needs to be completely closed...).

jQuery Threads:
http://forum.imacros.net/viewtopic.php?f=11&t=18247
http://forum.imacros.net/viewtopic.php?f=2&t=20410
- (F)CI(M) = (Full) Config Info (Missing): iMacros + Browser + OS (+ all 3 Versions + 'Free'/'PE'/'Trial').
- FCI not mentioned: I don't even read the Qt...! (or only to catch Spam!)
- Script & URL help a lot for more "educated" Help...
chivracq
Posts: 10301
Joined: Sat Apr 13, 2013 1:07 pm
Location: Amsterdam (NL)

Re: Extend Imacros with new commands?

Post by chivracq » Tue Nov 24, 2015 5:26 pm

Well-well-well...! November 2015, 2 years exactly after this Current Thread was started, it's time to bump it a bit as we've had and are still having some interest about the Subject with 2 other interested Users ('sightunseen' and 'rethinkreality') in 2 different Threads:
- Unresponsive script warning while executing iim from js file
- iim/js replay bug OR missing syntax?

In the next 2 (reserved) Posts, I will quote the relevant parts from those 2 Threads...
- (F)CI(M) = (Full) Config Info (Missing): iMacros + Browser + OS (+ all 3 Versions + 'Free'/'PE'/'Trial').
- FCI not mentioned: I don't even read the Qt...! (or only to catch Spam!)
- Script & URL help a lot for more "educated" Help...
chivracq
Posts: 10301
Joined: Sat Apr 13, 2013 1:07 pm
Location: Amsterdam (NL)

Re: Extend Imacros with new commands?

Post by chivracq » Tue Nov 24, 2015 5:27 pm

Reserved 1

1st Thread with relevant Info:
- Unresponsive script warning while executing iim from js file ('sightunseen', Feb 2014)
sightunseen wrote:

Code: Select all

Hi I am using iMacros 8.6.0 in Firefox 24.
...

Could the developers consider setting dom.max_script_run_time to 0 maybe only when an iMacros js script is executing, and then revert it back to its original setting afterwards? or maybe could the warning be continually handled (press continue each time) when iimPlay() is called? The ONDIALOG solution in the other thread sounds great (to click continue every time) but it doesn't sound to be always reliable.

I've looked at the iMacros source but it's stripped of whitespace and newlines. Conceivably I could edit the iimPlay function myself to set the dom.max_script_run_time to 0 only when running an iim file. I just need a source file I can read and to know where the iimPlay function is so I can add some code.
chivracq wrote:Hum...!, I'm starting to like you!

...

And for the last part of your previous msg, see this Thread for the Technique I use myself to modify the iMacros Source Code and customize the Add-on. Welcome to the Club!! I may feel less lonely...!
Extend Imacros with new commands?

...
sightunseen wrote:
chivracq wrote:Other idea would be to set those 2 Settings programmaticly at the Beginning and the End of your Macro, but that's supposed to be impossible (or at least we didn't find a way and TechSupport didn't jump into the Thread...), see this Thread:
Can I edit about:config with iMacros?
Thanks I've reviewed that. Short of writing an extension to communicate with iMacros or hacking iMacros' extension I don't have any good ideas unfortunately. BTW I used to have external programs communicate with iMacros by setting the clipboard and then I'd have the external program loop GetClipboardSequenceNumber() and if change then GetClipboardData() to see if it contained my special string. Not that it's relevant for here.

...
chivracq wrote:And for the last part of your previous msg, see this Thread for the Technique I use myself to modify the iMacros Source Code and customize the Add-on. Welcome to the Club!! I may feel less lonely...!
Extend Imacros with new commands?
Thanks. I've also done the same thing. I unzipped the jar file. I'm pretty sure you can leave them unzipped and do away with the jar. I have a js-beautifier that I could run on the javascript but it seems like a lot of work to go in and find out what's going on so I was hoping for an easy fix.

...
chivracq wrote:OK, Reply took a while, as I wanted to give you some structured Answer and I needed to find some older Threads for Reference...
sightunseen wrote:
chivracq wrote:Other idea would be to set those 2 Settings programmaticly at the Beginning and the End of your Macro, but that's supposed to be impossible (or at least we didn't find a way and TechSupport didn't jump into the Thread...), see this Thread:
Can I edit about:config with iMacros?
Thanks I've reviewed that. Short of writing an extension to communicate with iMacros or hacking iMacros' extension I don't have any good ideas unfortunately. BTW I used to have external programs communicate with iMacros by setting the clipboard and then I'd have the external program loop GetClipboardSequenceNumber() and if change then GetClipboardData() to see if it contained my special string. Not that it's relevant for here.
OK, interesting Technique, and you actually gave me some interesting Idea, to palliate in a way to some imo shortcoming of iMacros (Variables Scope) and I will need to test it, but I'm nearly sure it will work...
sightunseen wrote:
chivracq wrote:And for the last part of your previous msg, see this Thread for the Technique I use myself to modify the iMacros Source Code and customize the Add-on. Welcome to the Club!! I may feel less lonely...!
Extend Imacros with new commands?
Thanks. I've also done the same thing. I unzipped the jar file. I'm pretty sure you can leave them unzipped and do away with the jar. I have a js-beautifier that I could run on the javascript but it seems like a lot of work to go in and find out what's going on so I was hoping for an easy fix.
OK, "js-beautifier" sounds interesting, the inner Code of the Add-on is indeed not very fun and easy to read, you need to get drunk or very motivated before you want to dig in it...!
I use File-Diff to check the Changes between Versions (and revert some I don't like...) and simple Text Search at the Root of the Add-on to locate the Functions I'm looking for and I slowly begin to know where most Functionalities are located...
sightunseen wrote:
chivracq wrote:OK, "js-beautifier" sounds interesting, the inner Code of the Add-on is indeed not very fun and easy to read, you need to get drunk or very motivated before you want to dig in it...!
FYI I tried to use js beautifier and it spit out all kinds of errors trying to beautify the javascript files. If any dev is reading this it would be great if we could get them unpacked, or at least more information on the packer you guys are using.
chivracq wrote:
sightunseen wrote:
chivracq wrote:OK, "js-beautifier" sounds interesting, the inner Code of the Add-on is indeed not very fun and easy to read, you need to get drunk or very motivated before you want to dig in it...!
FYI I tried to use js beautifier and it spit out all kinds of errors trying to beautify the javascript files. If any dev is reading this it would be great if we could get them unpacked, or at least more information on the packer you guys are using.
Maybe none!! LOL...!!

OK, I was up to going to give it a try using Sublime Text and/or Notepad++ with some jsBeautifuler Plugin following the Tips here, but it works straight away using the online jsBeautifuler at http://jsbeautifier.org/

Example on ControlPanel.js (still from v8.60 (for FF), I haven't unpacked v8.8.1 yet...):

Code: Select all

//*/
/*
(c) Copyright 2008 iOpus Software GmbH - http://www.iopus.com
*/
iMacros.panel = (function () {
    var scope = {};
    Components.utils.import("resource://imacros/utils.js", scope);
    var __loginf = scope.__loginf;
    var imns = scope.imns;

    function iMacrosControlPanel() {
        this._statLine1 = "";
        this._statLine2 = "";
        this._statLine3 = "";
        this._statLine1Status = "";
        this._statLine2Status = "";
        this._statLine3Status = "";
        this._errorMessage = "";
        this._infoMessage = "";
        this._mboxType = "message";
        this._mboxStatus = "closed";
        this._currentLoop = 1;
        this._currentLine = 0;
        this.sidebar = null;
        this.registerObservers();
    };
    iMacrosControlPanel.prototype.registerObservers = function () {
        imns.osvc.addObserver(this, "imacros-sidebar-loaded", false);
        imns.osvc.addObserver(this, "imacros-sidebar-closed", false);
    };
    iMacrosControlPanel.prototype.unregisterObservers = function () {
        imns.osvc.removeObserver(this, "imacros-sidebar-loaded", false);
        imns.osvc.removeObserver(this, "imacros-sidebar-closed", false);
    };
    window.addEventListener("unload", function () {
        iMacros.panel.unregisterObservers();
    }, false);
    iMacrosControlPanel.prototype.observe = function (subject, topic, data) {
        if (topic == "imacros-sidebar-loaded") {
            var t = document.getElementById("sidebar").contentWindow;
            var sidebar_url = "chrome://imacros/content/iMacrosSidebar.xul";
            if (t.location.href != sidebar_url) return;
            if (t == subject) {
                if (this.panelIsOpen) this.closePanel();
                this.sidebar = subject;
                this.sidebar.mainwindow = window;
                if (this.treeViewState) {
                    var mtree = this.sidebar.getMTreeObject();
                    mtree.applyState(this.treeViewState);
                }
                if (this.sidebarIsOpening) this.sidebarIsOpening = false;
                if (this.sidebarLoadedCallback) {
                    this.sidebarLoadedCallback();
                    this.sidebarLoadedCallback = null;
                }
            }
        } else if (topic == "imacros-sidebar-closed") {
            if (subject != window) return;
            this.treeViewState = JSON.parse(data);
            this.sidebar = null;
        }
        this.updateControlPanel();
    };
    iMacrosControlPanel.prototype.ensureSidebarIsOpen = function (callback) {
        var broadcaster = document.getElementById("imacros_ControlPanel");
        var checked = broadcaster.getAttribute("checked") == "true";
        if (this.sidebarIsOpen) {
            setTimeout(callback, 0);
        } else if (!this.sidebarIsOpening) {
            this.sidebarLoadedCallback = callback;
            if (!checked) {
                imns.Pref.setBoolPref("close-sidebar", true);
                this.sidebarIsOpening = true;
                toggleSidebar("imacros_ControlPanel");
                setTimeout(function () {
                    if (!iMacros.panel.sidebarIsOpen) iMacros.panel.ensureSidebarIsOpen(callback);
                }, 200);
            }
        }
    };
    iMacrosControlPanel.prototype.closeSidebar = function () {
        if (!this.sidebar) return;
        toggleSidebar("imacros_ControlPanel");
    };
    iMacrosControlPanel.prototype.__defineGetter__("sidebarIsOpen", function () {
        return !!this.sidebar;
    });
    iMacrosControlPanel.prototype.showPanel = function () {
        if (!this.panelIsOpen) this.panel.openPopup(document.getElementById('imacros-toggle-button'), "after_end", 0, 0, false, false, null);
    };
    iMacrosControlPanel.prototype.__defineGetter__("panelIsOpen", function () {
        return (this.panel.state == "open" || this.panel.state == "showing");
    });
    iMacrosControlPanel.prototype.__defineGetter__("list", function () {
        if (this.sidebarIsOpen) {
            var doc = this.sidebar.document;
            var list = doc.getElementById('listbox');
            return list;
        }
        return null;
    });
    iMacrosControlPanel.prototype.showLines = function (code) {
        try {
            if (!this.sidebarIsOpen) return;
            var doc = this.sidebar.document;
            this.clearAllLines();
            if (code) {
                var lines = code.split("\n");
                for (var i = 0; i < lines.length; i++) {
                    this.list.appendItem(imns.str.trim(lines[i]));
                }
            }
            var deck = doc.getElementById("tree-box-deck");
            deck.selectedIndex = 1;
            var edit = doc.getElementById('editname');
            var rename = doc.getElementById('im-rename-button');
            edit.collapsed = true;
            rename.collapsed = true;
            this.list.scrollToIndex(0);
        } catch (e) {
            Components.utils.reportError(e);
        }
    };
    iMacrosControlPanel.prototype.addLine = function (line) {
        try {
            if (iMacros.recording) {
                this.statLine3 = this._statLine3.replace(/(\s+\(\d+\))?$/, " (" + iMacros.recorder.actions.length + ")");
            }
            if (!this.sidebarIsOpen) return;
            this.list.appendItem(line);
            var count = this.list.getRowCount();
            this.list.ensureIndexIsVisible(count - 1);
        } catch (e) {
            Components.utils.reportError(e);
        }
    };
    iMacrosControlPanel.prototype.removeLastLine = function () {
        if (iMacros.recording) {
            this.statLine3 = this._statLine3.replace(/(\s+\(\d+\))?$/, " (" + iMacros.recorder.actions.length + ")");
        }
        if (!this.sidebarIsOpen) return;
        this.list.removeItemAt(this.list.getRowCount() - 1);
    };
    iMacrosControlPanel.prototype.highlightLine = function (line) {
        this._currentLine = line;
        if (this.sidebarIsOpen) {
            this.statLine1 = imns.strings('imacrosreplaystep') + (line);
            this.list.ensureIndexIsVisible(line - 1);
            this.list.selectedIndex = line - 1;
        } else if (this.panelIsOpen) {
            this.statLine3 = this._statLine3.replace(/(\s+\(\d+\))?$/, " (" + line + ")");
        }
    };
    iMacrosControlPanel.prototype.clearAllLines = function () {
        if (!this.sidebarIsOpen) return;
        while (this.list.getRowCount()) this.list.removeChild(this.list.firstChild);
    };
    iMacrosControlPanel.prototype.__defineSetter__("statLine1", function (str) {
        this._statLine1 = str;
        if (this.sidebarIsOpen) {
            var doc = this.sidebar.document;
            var stat = doc.getElementById('replaystat');
            stat.value = str;
        } else {
            var stat = document.getElementById("imacros-info-panel-status2");
            if (/^Waiting:\s+\d+/.test(str)) {
                stat.setAttribute("state", "waiting");
                stat.value = str;
            } else {
                stat.removeAttribute("state");
                stat.value = "";
            }
        }
    });
    iMacrosControlPanel.prototype.__defineSetter__("statLine1Status", function (val) {
        this._statLine1Status = val;
        if (this.sidebarIsOpen) {
            var doc = this.sidebar.document;
            var stat = doc.getElementById('replaystat');
        } else {
            var stat = document.getElementById("imacros-info-panel-status2");
        } if (/playing|recording/.test(val.toString())) {
            stat.setAttribute("status", val);
        } else {
            stat.value = "";
            stat.removeAttribute("status");
        }
    });
    iMacrosControlPanel.prototype.__defineSetter__("statLine2", function (str) {
        this._statLine2 = str;
        if (this.sidebarIsOpen) {
            var doc = this.sidebar.document;
            var stat = doc.getElementById('delaystat');
        } else {
            var stat = document.getElementById("imacros-info-panel-status2");
        }
        stat.value = str;
    });
    iMacrosControlPanel.prototype.__defineSetter__("statLine2Status", function (val) {
        this._statLine2Status = val;
        if (this.sidebarIsOpen) {
            var doc = this.sidebar.document;
            var stat = doc.getElementById('delaystat');
        } else {
            var stat = document.getElementById("imacros-info-panel-status2")
        } if ("loading" == val.toString()) {
            stat.setAttribute("state", "loading");
        } else {
            stat.value = "";
            stat.removeAttribute("state");
        }
    });
    iMacrosControlPanel.prototype.__defineSetter__("statLine3", function (str) {
        this._statLine3 = str;
        if (!this.sidebarIsOpen) {
            var stat = document.getElementById("imacros-info-panel-status3");
            stat.value = str;
        }
    });
    iMacrosControlPanel.prototype.__defineSetter__("statLine3Status", function (val) {
        this._statLine3Status = val;
        if (this.sidebarIsOpen) return;
    });
    iMacrosControlPanel.prototype.__defineGetter__("panel", function () {
        return document.getElementById('imacros-info-panel');
    });
    iMacrosControlPanel.prototype.closePanel = function () {
        if (this.panelIsOpen) this.panel.hidePopup();
    };
    iMacrosControlPanel.prototype.onPanelClick = function () {
        if (this.panelIsOpen) this.panel.hidePopup();
        if (!this.sidebarIsOpen) toggleSidebar("imacros_ControlPanel");
    };
    iMacrosControlPanel.prototype.showMacroTree = function () {
        this.statLine1Status = "idle";
        this.statLine2Status = "idle";
        this.statLine3Status = "idle";
        if (this.panelIsOpen) {
            if (this._mboxStatus != "open") {
                var self = this;
                this.closePanelTimeout = setTimeout(function () {
                    self.closePanelTimeout = null;
                    self.closePanel();
                }, 2000);
            }
        }
        if (this.sidebarIsOpen) {
            var doc = this.sidebar.document;
            var deck = doc.getElementById("tree-box-deck");
            deck.selectedIndex = 0;
            if (imns.Pref.getBoolPref("close-sidebar")) {
                imns.Pref.setBoolPref("close-sidebar", false);
                this.closeSidebar();
            }
        }
        this.updateControlPanel();
    };
    iMacrosControlPanel.prototype.__defineGetter__("selectedItem", function () {
        if (!this.sidebarIsOpen) return null;
        var mtree = this.sidebar.getMTreeObject();
        return mtree.getSelectedItem();
    });
    iMacrosControlPanel.prototype.updateMacroTree = function () {
        if (this.sidebarIsOpen) {
            this.sidebar.initMTree();
        }
    };
    iMacrosControlPanel.prototype.updateControlPanel = function () {
        if (this.sidebarIsOpen) {
            this.updateSidebarState();
        } else {
            var __x = function (btns, state) {
                if (typeof btns == "string") btns = [btns];
                for (let n = 0; n < btns.length; n++) {
                    let btn = document.getElementById("imacros-info-panel-" + btns[n] + "-button");
                    btn.collapsed = state;
                }
            };
            var on = function (btns) {
                __x(btns, null);
            };
            var off = function (btns) {
                __x(btns, true);
            };
            if (iMacros.playing || iMacros.jsplaying || iMacros.recording || iMacros.paused == "playing" || iMacros.paused == "jsplaying" || iMacros.paused == "recording") {
                if (!this.panelIsOpen) {
                    this.showPanel();
                } else if (this.closePanelTimeout) {
                    clearTimeout(this.closePanelTimeout);
                    this.closePanelTimeout = null;
                }
            } else {
                this.statLine3 = this._statLine3.replace(/(?:\s+\(\d+\))$/, "");
                on(["play", "record"]);
                off(["pause", "stop"]);
                return;
            }
            let pause_btn = document.getElementById("imacros-info-panel-pause-button");
            if (iMacros.paused == "playing" || iMacros.paused == "jsplaying") {
                on(['pause', 'stop']);
                off(['play', 'record']);
                pause_btn.setAttribute("icon", "play");
                pause_btn.setAttribute("label", "Continue");
            } else if (iMacros.paused == "recording") {
                on(['stop', 'pause']);
                off(['play', 'record']);
                pause_btn.setAttribute("icon", "record");
                pause_btn.setAttribute("label", "Continue");
            } else if (iMacros.playing || iMacros.jsplaying) {
                this.statLine3 = this._statLine3.replace(/(\s+\(\d+\))?$/, " (" + this._currentLine + ")");
                on(['pause', 'stop']);
                off(['play', 'record']);
                pause_btn.setAttribute("icon", "pause");
                pause_btn.setAttribute("label", "Pause");
            } else if (iMacros.recording) {
                this.statLine3 = this._statLine3.replace(/(\s+\(\d+\))?$/, " (" + iMacros.recorder.actions.length + ")");
                on(['stop', 'pause']);
                off(['play', 'record']);
                pause_btn.setAttribute("icon", "pause");
                pause_btn.setAttribute("label", "Pause");
            }
        }
        this.statLine1 = this._statLine1;
        this.statLine1Status = this._statLine1Status;
        this.statLine2 = this._statLine2;
        this.statLine2Status = this._statLine2Status;
        this.statLine3 = this._statLine3;
        this.statLine2Status = this._statLine3Status;
        if (this._mboxStatus == "open") {
            if (this._mboxType == "error") this.showErrorMessage(this._errorMessage);
            else if (this._mboxType == "message") this.showInfoMessage(this._infoMessage);
        }
    };
    iMacrosControlPanel.prototype.updateSidebarState = function () {
        if (!this.sidebarIsOpen) return;
        var doc = this.sidebar.document;
        var deck = doc.getElementById("tree-box-deck");
        var makeObject = function (constructor) {
            var obj = new Object();
            for (var x = 1; x < arguments.length; x++) obj[arguments[x]] = constructor(arguments[x]);
            return obj;
        };
        var butts = makeObject(function (name) {
            return doc.getElementById("im-" + name + "-button");
        }, "play", "pause", "stopplay", "playloop", "record", "save", "stoprecord", "waitreplay", "edit", "share");
        var tabs = makeObject(function (name) {
            return doc.getElementById("im-" + name + "-tab");
        }, "play", "record", "edit");
        var off = function (obj) {
            for (var x = 1; x < arguments.length; x++) obj[arguments[x]].disabled = true;
        };
        var on = function (obj) {
            for (var x = 1; x < arguments.length; x++) obj[arguments[x]].disabled = null;
        };
        var tabbox = doc.getElementById("im-tabbox");
        if (iMacros.playing || iMacros.jsplaying || iMacros.paused == "playing" || iMacros.paused == "jsplaying") {
            off(butts, "play", "playloop");
            on(butts, "pause", "stopplay");
            off(tabs, "record", "edit");
            tabbox.selectedIndex = 0;
            butts["pause"].label = iMacros.paused ? imns.strings('imacrospausestate2') : imns.strings('imacrospausestate1');
            if (deck.selectedIndex != 1) {
                if (iMacros.playing) this.showLines(iMacros.player.source);
                else if (iMacros.jsplaying) this.showLines(iMacros.jssrc);
                this.highlightLine(this.currentLine);
            }
        } else if (iMacros.recording || iMacros.paused == "recording") {
            off(butts, "record", "save");
            on(butts, "stoprecord", "waitreplay");
            off(tabs, "play", "edit");
            tabbox.selectedIndex = 1;
            if (deck.selectedIndex != 1) {
                this.showLines(iMacros.recorder.getRecordedMacro());
            }
        } else {
            on(tabs, "play", "record", "edit");
            var item = this.selectedItem;
            if (item && !item.isContainer) {
                on(butts, "play", "playloop", "save", "edit", "share");
            } else {
                off(butts, "play", "playloop", "save", "edit", "share");
            }
            on(butts, "record");
            off(butts, "pause", "stopplay", "stoprecord", "waitreplay");
            deck.selectedIndex = 0;
        }
        var rec_mode = imns.Pref.getCharPref("record-mode");
        var elem = doc.getElementById("im-record-label");
        if (elem) {
            if (rec_mode == "auto") elem.value = "Auto";
            else if (rec_mode == "conventional") elem.value = "HTM";
            else if (rec_mode == "events") elem.value = "Event";
            else {
                elem.value = "Auto";
                imns.Pref.setCharPref("record-mode", "auto");
            }
        }
    };
    iMacrosControlPanel.prototype.mboxClose = function () {
        this.mboxClearMessage();
        if (this.panelIsOpen) {
            this.closePanel();
        }
    };
    iMacrosControlPanel.prototype.mboxHelp = function () {
        if (this.mboxErrorNumber == 31415) iMacros.addTab("http://www.iopus.com/imacros/home/fx/rd.asp?helpid=macrotoolong");
        else iMacros.addTab("http://www.iopus.com/imacros/home/fx/e.asp?browser=fx&error=" + this.mboxErrorNumber);
    };
    iMacrosControlPanel.prototype.mboxEdit = function () {
        var macro = iMacros.currentMacro;
        if (!macro.path) {
            var t = imns.Cc["@mozilla.org/file/directory_service;1"].getService(imns.Ci.nsIProperties).get("TmpD", imns.Ci.nsILocalFile);
            t.append("iMacros_tmpfile.iim");
            imns.FIO.writeTextFile(t, iMacros.player.source);
            macro.path = t.path;
        }
        iMacros.edit(macro, this.mboxErrorLine);
    };
    iMacrosControlPanel.prototype.mboxResetError = function () {
        if (this._mboxType != "error") return;
        this.mboxClearMessage();
    };
    iMacrosControlPanel.prototype.mboxClearMessage = function () {
        if (this.sidebarIsOpen) {
            var doc = this.sidebar.document;
            var box = doc.getElementById("imacros-message-box");
            var deck = doc.getElementById("logo-message-deck");
            if (deck.selectedIndex == 0) {
                deck.selectedIndex = 1;
            }
        } else if (this.panelIsOpen) {
            document.getElementById("imacros-message-box-container").collapsed = true;
        }
        this._mboxType = "message";
        this._mboxStatus = "closed";
        this._errorMessage = "";
        this._infoMessage = "";
    };
    iMacrosControlPanel.prototype.showInfoMessage = function (msg) {
        this._infoMessage = msg;
        this._mboxType = "message";
        this._mboxStatus = "open";
        if (this.sidebarIsOpen) {
            var doc = this.sidebar.document;
            var tabbox = doc.getElementById("im-tabbox");
            tabbox.selectedIndex = 0;
            var deck = doc.getElementById("logo-message-deck");
            deck.selectedIndex = 0;
            var msgbox = doc.getElementById("imacros-message-box");
            var help_btn = doc.getElementById("message-box-button-help");
            var edit_btn = doc.getElementById("message-box-button-edit");
            help_btn.collapsed = true;
            edit_btn.collapsed = true;
            msgbox.setAttribute("msgtype", this._mboxType);
            msgbox.value = msg;
        } else {
            if (!this.panelIsOpen) this.showPanel();
            var con = document.getElementById("imacros-message-box-container");
            con.collapsed = null;
            var msgbox = document.getElementById("imacros-message-box");
            var help_btn = document.getElementById("imacros-message-box-button-help");
            var edit_btn = document.getElementById("imacros-message-box-button-edit");
            help_btn.collapsed = true;
            edit_btn.collapsed = true;
            msgbox.setAttribute("msgtype", this._mboxType);
            msgbox.value = msg;
        }
    };
    iMacrosControlPanel.prototype.showErrorMessage = function (msg, errnum) {
        if (errnum && !/\(error code: -?\d+\)$/i.test(msg)) {
            msg += " (Error code: " + errnum + ")";
        }
        this._errorMessage = msg;
        this._mboxType = "error";
        this._mboxStatus = "open";
        if (this.sidebarIsOpen) {
            var doc = this.sidebar.document;
            var tabbox = doc.getElementById("im-tabbox");
            tabbox.selectedIndex = 0;
            var deck = doc.getElementById("logo-message-deck");
            deck.selectedIndex = 0;
            var msgbox = doc.getElementById("imacros-message-box");
            var help_btn = doc.getElementById("message-box-button-help");
            var edit_btn = doc.getElementById("message-box-button-edit");
            help_btn.collapsed = null;
            edit_btn.collapsed = null;
            msgbox.setAttribute("msgtype", this._mboxType);
            msgbox.value = msg;
        } else {
            if (!this.panelIsOpen) this.showPanel();
            var con = document.getElementById("imacros-message-box-container");
            con.collapsed = null;
            var msgbox = document.getElementById("imacros-message-box");
            var help_btn = document.getElementById("imacros-message-box-button-help");
            var edit_btn = document.getElementById("imacros-message-box-button-edit");
            help_btn.collapsed = null;
            edit_btn.collapsed = null;
            msgbox.setAttribute("msgtype", this._mboxType);
            msgbox.value = msg;
        }
        this.mboxErrorNumber = errnum;
        this.mboxErrorLine = 0;
        if (/, line:\s*(\d+)(?:\s+\(.*\))?$/.test(msg)) this.mboxErrorLine = parseInt(RegExp.$1);
    };
    iMacrosControlPanel.prototype.onLoopValueInput = function () {
        var textbox = this.sidebar.document.getElementById('im-loopval-textbox');
        textbox.value = textbox.value.replace(/^0+|[^\d]/g, "");
    };
    iMacrosControlPanel.prototype.onLoopValueChange = function () {
        var textbox = this.sidebar.document.getElementById('im-loopval-textbox');
        if (!textbox.value.length) textbox.value = "3";
    };
    iMacrosControlPanel.prototype.__defineGetter__("maxLoopValue", function () {
        if (!this.sidebarIsOpen) return this._maxLoopValue;
        var doc = this.sidebar.document;
        var value = doc.getElementById('im-loopval-textbox');
        return (this._maxLoopValue = imns.s2i(value.value));
    });
    iMacrosControlPanel.prototype.__defineSetter__("currentLoopValue", function (val) {
        this._currentLoopValue = val;
        if (!this.sidebarIsOpen) return;
        var doc = this.sidebar.document;
        var value = doc.getElementById('im-curloop-textbox');
        value.value = val;
    });
    return new iMacrosControlPanel();
})();
sightunseen wrote:
chivracq wrote:it works straight away using the online jsBeautifuler at http://jsbeautifier.org/
Interesting. I tried the python version of that script but it spit out all kinds of errors. I tried via FOREACH on every js file in chrome and its subdirectories.
chivracq wrote:
sightunseen wrote:
chivracq wrote:it works straight away using the online jsBeautifuler at http://jsbeautifier.org/
Interesting. I tried the python version of that script but it spit out all kinds of errors. I tried via FOREACH on every js file in chrome and its subdirectories.
I just got lucky I would say with that online jsBeautifuler because I was already studying the Code of the Add-on and modifying it (in its raw Version!), but that makes it now indeed a bit easier, at least to understand and to locate where I have to modify things... And I asked a while ago to have access to !LOOP_MAX in Scripts, never got any Answer, said I was going to implement it myself, that makes it closer...!

I normally don't really get excited by online Compilers and Decompilers and same kind, though I once helped a Web-Site I use a lot with my Macros to locate and get rid of a Virus that had infected one of their Flash-Objects..., yes using an online Russian Flash-Decompiler...
chivracq wrote:How to make things complicated when they can be so simple!?

I was doing some digging yesterday, looking for an Archive on Internet for older Versions of iMacros for Chrome for this Thread (and I didn't find any...) but at some point, I landed (again) on the Mozilla Archive for iMacros for Firefox (where btw I downloaded all 79 (-3 with no Link) current and older Versions of iMacros for FF when I saw the hassle it is to downgrade iMacros on CR...) and I noticed that iMacros is advertised as being "Open Source" (at least on the Chrome Add-ons Web-Store, I didn't check for Firefox), so I thought, if it's Open Source, the Source Code must be found somewhere..., with all (older) Versions..., and that's how I landed again on the Mozilla Archive for iMacros for FF where indeed all JavaScript Files are already "jsBeautified" by Mozilla or delivered in a clean State by iOpus.

Example (for the same 'ControlPanel.js' that I already jsBeautified and posted earlier, except this time from v8.8.1):
https://addons.mozilla.org/en-us/firefo ... nel.js#top
(Accessed from the "View the source" Link underneath each Version...)

Related Threads:
- iMacros source (2008)
- How is iMacros Open Source? (2011-2012)
sightunseen wrote:
chivracq wrote:and that's how I landed again on the Mozilla Archive for iMacros for FF where indeed all JavaScript Files are already "jfBeautified" by Mozilla or delivered in a clean State by iOpus.

Example (for the same 'ControlPanel.js' that I already jsBeautified and posted earlier, except this time from v8.8.1):
https://addons.mozilla.org/en-us/firefo ... nel.js#top
(Accessed from the "View the source" Link underneath each Version...)
I just went there in my browser (FIrefox 24) and it's not beautified. Line 5 is one long line containing all the code. I can beautify it using the python js beautify utility or the online version (which I think uses the same code). Only problem is a lot of the iMacros files the beautifier will choke on. The developers know we're here maybe they could release it unpacked.
chivracq wrote:Hi SightUnseen, nice to see that you follow the interesting Threads...! :D

OK, yes indeed, you are right, there are lots of differences between the Display on the Mozilla Add-ons Archive and the Display after "proper" js-Beautifying like I posted some time ago. (I notice btw some ugly Quote of mine where I use "jfBeautified", I'm going to correct it..., I used once as well "jsBeautiful", but I left it, as I realize that yesterday I was trying to locate this current Thread again and I used "jsBeautiful(ed)" (instead of "jsBeautify([y/i]ed)"!) (again) as a Search-Term...! Oups!)

So OK, the Display on the Mozilla Add-on Archived is not completely jsBeautified like on http://jsbeautifier.org/ but it is still readable, or at least much more than the whole .js Script on 1 Line...

>>> Stg else, you once posted/started an interesting Thread on the EVENT Mode, I still owe you a Reply on that one, but it takes some time, because I need to find several References and related Threads, and I never find the time to do it...!

>>>

JFC_TAG:
jsBeautifier, js-Beautifier, jsBeautify, js-Beautify, jsBeautified, js-Beautified, jsBeautifuler, js-Beautifuler, jsBeautifuled, js-Beautifuled, Mozilla_Archive, Decompile, Decompile_Script, Decompile_iMacros...
OK, that should be it for that Thread...! :shock:
Last edited by chivracq on Thu Nov 26, 2015 4:57 am, edited 2 times in total.
- (F)CI(M) = (Full) Config Info (Missing): iMacros + Browser + OS (+ all 3 Versions + 'Free'/'PE'/'Trial').
- FCI not mentioned: I don't even read the Qt...! (or only to catch Spam!)
- Script & URL help a lot for more "educated" Help...
chivracq
Posts: 10301
Joined: Sat Apr 13, 2013 1:07 pm
Location: Amsterdam (NL)

Re: Extend Imacros with new commands?

Post by chivracq » Tue Nov 24, 2015 5:28 pm

Reserved 2

2nd Thread with relevant Info:
- iim/js replay bug OR missing syntax? ('rethinkreality', Novb 2015)
rethinkreality wrote:

Code: Select all

FF [42.0]
iMacros [8.9.4] 
OS [Snow Leopard, Mountain Lion, Mavericks]
chivracq wrote:...

Or if you compute dynamically the Name of the next Macro to run, following the Technique I explained in this Thread/Post:
- Re: IE Plugin Loop
rethinkreality wrote:...

PS: Nice thread, you constantly amaze me with what you can do with pure iim.
chivracq wrote:...

But the moral is that when you are Creative, you don't need any Help from anybody else, you always come up with a Solution, unless you really encounter a Bug..., that's actually how I came to the Forum about 2 or 3 years ago, feeling very modest and shy to report a Bug but I was a bit surprised then to see that most Threads were about Questions/Pb's I had had myself previously and had solved by myself quite easily. And I was then already doing "things" with iMacros that were way more complex than all Threads I saw/read then when I joined, and now even more of course...

And even the "Bug" Argument, I would now be able to solve them by myself, I've run my own customized Version of iMacros for a while, that might be a very interesting Thread for you to read, you seem like you are much-much more "fluent" than me at JavaScript (that I only use for 'EVAL()' Statements), look for a Thread with Participation by / initiated by 'Sightunseen' (and me of course, but's it's easier to search on this other very talented User) and "js-beautifier / js-beautifuler /decompile" etc...

Here I gave the Method that I use:
- Unresponsive script warning while executing iim from js file
- Extend Imacros with new commands?

(And now I need to bookmark those 2 threads myself to find them back a bit more easily next time I need them...! :idea: )
rethinkreality wrote:...

I spent the last little while reading yours and sightunseen's messages. (those very post too! lol) I think it's time for me to make some personalized edits to iMacros, thanks for that.
chivracq wrote:
rethinkreality wrote:I spent the last little while reading yours and sightunseen's messages. (those very post too! lol) I think it's time for me to make some personalized edits to iMacros, thanks for that.
Yep, I've been asking for too long to have a '!LOOP_MAX' Var that could be set (and retrieved if set from the 'Play Loop' Field in the Side Panel) from within a Macro, superseding or not the Value set in 'Play Loop', I "threatened" months ago to implement it myself, I don't think it will happen from Dev, so I guess I need to dig into the "mud"...

I have several Macros where I want to do stg special only in the last Run, and I can only do it if I specify the '!LOOP_MAX' Value from within the Macro with a Negative Value... Or use a PROMPT in the first Run, but again there is a Bug ('alert()' doesn't work in 'URL GOTO' even if advertised in the Wiki...), it's not possible to use a Conditional PROMPT only for one specific run, I have a Workaround, but it's cumbersome and it should be much easier... I guess I'm never taken seriously when I report a Bug because I always find a Workaround..., Grrr...!! :twisted:

"... I think it's time for me to make some personalized edits to iMacros..."
=> Yes, do it...! And share, I'll be of course very-very interested..., oops...! 8)
rethinkreality wrote:
chivracq wrote:"... I think it's time for me to make some personalized edits to iMacros..."
=> Yes, do it...! And share, I'll be of course very-very interested..., oops...! 8)
I'm not sure ipswitch would like me posting a mod on the forum, but i'm not opposed to sharing the results. We should talk about this in greater detail.
chivracq wrote:
rethinkreality wrote:I'm not sure ipswitch would like me posting a mod on the forum, but i'm not opposed to sharing the results. We should talk about this in greater detail.
It shouldn't be a Pb, I think... In one of the Threads I referred to, I even decompiled and posted one of the iMacros Add-on Modules (for FF) and I wasn't sure at that time if that would be OK or not with the Moderation/TechSupport but I did some Research on the Forum and iMacros is officially Open-Source (I must have referred to it in one of those 2 Threads, there is some "official" Statement about that from TechSupport in some older Thread), even if iOpus/Ipswitch's Definition of "Open-Source" is a bit of a grey area... But you are officially allowed to modify the Add-on, but don't expect TechSupport to support your customized Version if anything goes wrong of course...!
rethinkreality wrote:Got some source code reading to do then, lol I remember you compared it to mud in one post. Should be exciting, maybe sightunseen will like to tackle this with me or even yourself if you're not too busy.
chivracq wrote:I mentioned which Decompile Web-Service/Site I was using to js-beautify Modules in the other Thread...

Maybe we should continue the Discussion in that other Thread as it has anyway nothing to do anymore with your Original Question in this Current Thread, in the Thread that was dedicated to extending iMacros with new Commands, and I'll quote there all relevant parts from this Current Thread and the Thread with 'sightunseen' and I will ping him in his Thread, I think he's got Notifications ON for that Thread and he will come to the Forum on a Horse, ah-ah...!
And if he doesn't receive any Notification nor comes to the Forum, I think we had already communicated by Mail before, so I may have his E-Mail Address somewhere... But he checks the Forum from time to time anyway and he will notice the Thread...
- Extend Imacros with new commands?

And yep, I will have some time for some Fun Project of course, even if I'm pretty busy indeed, but I find the time to monitor the Forum regularly as well, "Everything is a Question of Motivation...!", I always say...

Tja, and talking about Horses, I'm going tonight to a nice Concert in Amsterdam by a Friend of mine:
- Curtis Eller: Sugar for the Horses Enjoy...! :D
OK, that should be it for that Thread...! :shock:
- (F)CI(M) = (Full) Config Info (Missing): iMacros + Browser + OS (+ all 3 Versions + 'Free'/'PE'/'Trial').
- FCI not mentioned: I don't even read the Qt...! (or only to catch Spam!)
- Script & URL help a lot for more "educated" Help...
rethinkreality
Posts: 30
Joined: Thu Nov 12, 2015 9:50 pm

Re: Extend Imacros with new commands?

Post by rethinkreality » Thu Nov 26, 2015 4:07 am

I think we should start by making a list of commands or functionality that we could really like from a software like iMacros. I remember you wanted a loop_max function chivracq but can you get into specifics of what you want it to do? Once we have a list of them, then we can prioritize and start like that. These are some of my ideas, what do you guys think?

-I want to look into the possibility of having iMacros communicate a "Macro finished" message when executed from the command-line/terminal.
-Easier stand-alone scheduling options
-Easier conditionals for iim scripts
-XPATH record method
-Free encryptions for scripts
-Cleaner Macros Edit window, with a better color scheme because you simply can't tell if you have something selected or if it's because the cursor is on that line. (On mac Add cmd+s hotkey for saving macro and cmd+w for closing edit window)
-Include "stubs" of macros for faster creation
If you want help, make sure to add this information. If you don't, answers may not work for your specific setup.
- (F)CIM = (Full) Config Info Missing: iMacros + Browser + OS with all Versions
rethinkreality
Posts: 30
Joined: Thu Nov 12, 2015 9:50 pm

Re: Extend Imacros with new commands?

Post by rethinkreality » Fri Nov 27, 2015 9:06 pm

rethinkreality wrote:I remember you wanted a loop_max function chivracq but can you get into specifics of what you want it to do?
Bump because I want to know Chiv, I've seen you posting about lol. I don't think I understand it. Or can you skype/email?
If you want help, make sure to add this information. If you don't, answers may not work for your specific setup.
- (F)CIM = (Full) Config Info Missing: iMacros + Browser + OS with all Versions
chivracq
Posts: 10301
Joined: Sat Apr 13, 2013 1:07 pm
Location: Amsterdam (NL)

Re: Extend Imacros with new commands?

Post by chivracq » Sat Nov 28, 2015 1:59 am

rethinkreality wrote:
rethinkreality wrote:I remember you wanted a loop_max function chivracq but can you get into specifics of what you want it to do?
Bump because I want to know Chiv, I've seen you posting about lol. I don't think I understand it. Or can you skype/email?
Yep sorry, WE is always very busy for me, DJ'ing soon, I'm late already...

Sorry, I need some time to post a useful well thought Post...

But yes, '!LOOP_MAX' is an easy target..., sorry I'm a bit blind now, I've got 10 Targets, but I have to go now... DJ-Time...!!! Come and dance in Amsterdam...! (I was supposed to start at 03h, I'm still home (03h01) and a bit late, obviously..., oops...!)
- (F)CI(M) = (Full) Config Info (Missing): iMacros + Browser + OS (+ all 3 Versions + 'Free'/'PE'/'Trial').
- FCI not mentioned: I don't even read the Qt...! (or only to catch Spam!)
- Script & URL help a lot for more "educated" Help...
chivracq
Posts: 10301
Joined: Sat Apr 13, 2013 1:07 pm
Location: Amsterdam (NL)

Re: Extend Imacros with new commands?

Post by chivracq » Sun Apr 03, 2016 11:14 am

Hum, I see from my previous Reply that I wanted to post a List of Commands/Features/EnhReqs that would be nice to be implemented, but I got caught in some busy life things and never followed up anymore...

But I posted recently (2 months ago) a List of EnhReqs in this Thread:
- Feedback - Take the iMacros Add-on(s) Survey!

>>>

But the Reason I was bumping this Thread is that some new mini-Duplicate/Relevant Thread was started about the Subject:
- Source code of iMacros for Firefox
alex686 wrote:Hi developers!

AFAIK iMacros addon for Firefox is an open source project. But I can't seem to find it's source repo. Does it exist in public access (github, bitbucket or smth)? If not, are there any plans to make it public? I would like to hack on the source code...
chivracq wrote:
alex686 wrote:

Code: Select all

iMacros for Firefox: 8.9.6
Firefox: 45.0.1
OS: Arch Linux, Windows 10
Hi developers!

AFAIK iMacros addon for Firefox is an open source project. But I can't seem to find it's source repo. Does it exist in public access (github, bitbucket or smth)? If not, are there any plans to make it public? I would like to hack on the source code...
I went this way a few years ago already... You'll find everything you wanted to know about iMacros for FF being an Open Source Project but were afraid to ask in this Thread...:
- Extend Imacros with new commands?

I'm surprised btw the way that you didn't manage to locate this Thread and/or the "Unresponsive Script..." Thread if you searched the Forum a mini-bit... What Search Keywords did you use...? :o

The Thread I refer to was quite advanced and compiled all relevant Info from all relevant Threads on the Forum about the Subject...
If you care to share some of your Tweaks/Hacks/Implementations and/or contribute to the "Project" with more Ideas, it will be more relevant to do it there I think rather than starting a new Discussion from scratch in your Current Thread which is just a mini-Duplicate...
- (F)CI(M) = (Full) Config Info (Missing): iMacros + Browser + OS (+ all 3 Versions + 'Free'/'PE'/'Trial').
- FCI not mentioned: I don't even read the Qt...! (or only to catch Spam!)
- Script & URL help a lot for more "educated" Help...
Post Reply