Thread Tools Display Modes
10/13/18, 06:15 AM   #1
sirinsidiator
 
sirinsidiator's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 1,566
[implemented] addon manager improvements

It has been asked a few times already and I'd really like to see some improvements to the addon manager. It would be great if it could answer the following few questions about an addon.

Where was the addon loaded from?
I believe the best way to answer this question would be a function to return the path to the manifest file for an addon. Right now the only way to know if an addon was installed in the correct path is to use debug.traceback to find the file it was called from, but abusing debug functions for features is never a good idea.
In addition a function that allows to open the folder where all addons reside - with an optional manifest path to directly open go to an addon - in explorer/finder would also be great, seeing as many users struggle to find their addon folder.

Which version does the addon specify?
Addon authors have specified a version string via "##Version <string>" in the addon manifest since forever and the minion addon manager also uses that information to determine which version of an addon is installed, but there is still no way to retrieve this string ingame so it can be shown to the user. There is also no way to get the "##AddOnVersion <integer>" ingame. Both would be a great to know when troubleshooting addon issues, since more often than not, an addon bug report happens just because of an incorrectly installed addon. LibAddonMenu for example currently requires that the addon author manually puts this same version string into the Lua code a second time. If we could just use the string from the manifest, this would reduce potential confusion when an author forgets to update one or the other.

What is the status of each file specified in the manifest?
This last one is more for addon authors to debug during development. Many times when I create a new file and reload the UI and nothing happens, I am left wondering if I just misspelled or forgot the file in the manifest, or if the game loaded it but there is some other problem. Knowing which files have been detected in the manifest and if they could be loaded or are missing would be very helpful in these cases (e.g. "loaded", "error", "missing"). It could also help with cleaning up the manifest after restructuring an addon - e.g. AwesomeGuildStore has more than 300 files. Knowing which ones are specified in the manifest, but missing in the file system would make this a lot easier for me.

Is an addon a library?
Votan did a great job separating the list based on the names of addons, but it would make a lot of sense if the game itself could do this on its own. Let authors put a "##Library" in the manifest and move the entry to a second tab/list. Maybe also add a copy of dependency entries directly to the extended addon information, so users can enable missing dependencies without having to scroll around.

Which game version was the addon tested with?
The much discussed "allow outdated addons" checkbox is still a big pain for both authors and users. Instead of force-disabling all addons, it would be much more elegant to do an automated smoke test during the first login after a major game update. Just load the ui, check which addons throw errors, disable them, reload (don't store saved variables during this) - until all errors and/or addons are gone. In the addon list you'd then show the text "last tested with <game version>" for working addons that have an older api version and "this addon is outdated" if it produced errors and was disabled due to them. No need for the checkbox anymore.
 
10/16/18, 06:26 AM   #2
sirinsidiator
 
sirinsidiator's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 1,566
Maybe you could also just allow custom directives and add a method to get a string value for a key to the addon manager.
 
12/05/18, 03:23 PM   #3
Drakanwulf
 
Drakanwulf's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2017
Posts: 50
How about a "GetAddOnVersion()" call?

sirinsidiator has already brought up "AddOnVersion" under his "Which version does the addon specify?" paragraph. My request is but another complaint about the same subject.

ESO already has an API call to "GetAPIVersion()" to return the current ESO API Version, so how difficult could it be to add an API call to "GetAddOnVersion( "AddOnName" )" to return the current "addonversion" number (or nil whenever the AddOnVersion number cannot be found) for the "AddOnName" in question?

This would let ESO tell developers what the current version of their loaded add-on is. For example, add-on developers could use the return value to detect and deny duplicate or "out-of-date" add-on load requests caused by unnecessary add-on folders that have been embedded in poor (or bad or lazy) add-on packaging.

Right now, for example, the LibStub add-on, which many library add-ons use to bootstrap their loads, has to "guess" at what any add-on's latest version number is because ESO provides no internal reference to those values. Add-on developers know when the ESO API has been changed because they can invoke "GetAPIVersion()" to get the latest version. I think we should be able to get similar version information about any loaded add-on.
 
12/05/18, 03:44 PM   #4
sirinsidiator
 
sirinsidiator's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 1,566
Originally Posted by Drakanwulf View Post
This would let ESO tell developers what the current version of their loaded add-on is. For example, add-on developers could use the return value to detect and deny duplicate or "out-of-date" add-on load requests caused by unnecessary add-on folders that have been embedded in poor (or bad or lazy) add-on packaging.
What you are saying is plain wrong. The game uses the AddOnVersion to prevent multiple instances of the same addon from loading. Authors don't influence that with their packaging and don't have any need to "detect and deny" it.

Originally Posted by Drakanwulf View Post
Right now, for example, the LibStub add-on, which many library add-ons use to bootstrap their loads, has to "guess" at what any add-on's latest version number is because ESO provides no internal reference to those values.
LibStub has nothing to do with the AddOnVersion and won't ever use it. It's an old and deprecated system that did in the past what the game now does with the AddOnVersion and loading nested addons, so it's better to not use LibStub for new libraries anymore, since it cannot do it as well as the game itself.

Originally Posted by Drakanwulf View Post
Add-on developers know when the ESO API has been changed because they can invoke "GetAPIVersion()" to get the latest version. I think we should be able to get similar version information about any loaded add-on.
Addon devs also know which version of their addon is loaded if they have specified an AddOnVersion. It's always the one with the highest number, which you implicitly know in your code.
 
12/06/18, 12:27 PM   #5
Provision
 
Provision's Avatar
AddOn Author - Click to view addons
Join Date: May 2015
Posts: 43
I prefere semantic version like that : {major}.{minor}.{revision}

Given a version number MAJOR.MINOR.PATCH, increment the:

- MAJOR version when you make incompatible API changes,
- MINOR version when you add functionality in a backwards-compatible manner, and
- PATCH version when you make backwards-compatible bug fixes.

Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.

Last edited by Provision : 12/07/18 at 03:14 AM.
 
12/06/18, 09:55 PM   #6
Drakanwulf
 
Drakanwulf's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2017
Posts: 50
Originally Posted by sirinsidiator View Post
What you are saying is plain wrong. The game uses the AddOnVersion to prevent multiple instances of the same addon from loading. Authors don't influence that with their packaging and don't have any need to "detect and deny" it.
Exactly, and my suggestion was meant to promote actively not loading duplicates, which ZOS and ESO can't do, but add-on developers can and should do... but that's just my opinion. Of course, the backlash from the user community would affect some add-on developers more than others, if one were to follow that path.

Originally Posted by sirinsidiator View Post
LibStub has nothing to do with the AddOnVersion and won't ever use it. It's an old and deprecated system that did in the past what the game now does with the AddOnVersion and loading nested addons, so it's better to not use LibStub for new libraries anymore, since it cannot do it as well as the game itself.
The way LibStub's versioning works is the same way that ESO's AddOnVersion works. LibStub, however, does not care about duplicate versions; LibStub cares about only old, out-of-date, versions. However, as you said, LibStub is a dated product but that does not mean we cannot learn from it and what it did and did not do.

Originally Posted by sirinsidiator View Post
Addon devs also know which version of their addon is loaded if they have specified an AddOnVersion. It's always the one with the highest number, which you implicitly know in your code.
Right now, it is impossible to "legally" retrieve the AddOnVersion for any add-on. You have to "guess" at values that you cannot get. An optimal solution, in my view, would be for ESO to provide the current AddOnVersion and the manifest AddOnVersion to the add-on developer so they could make their decisions based on fact. And that was my point!
 
12/06/18, 09:59 PM   #7
Drakanwulf
 
Drakanwulf's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2017
Posts: 50
Originally Posted by Provision View Post
I prefere sementic version like that : {major}.{minor}.{revision}
^^ I agree. FYI, it's "semantic version" to be correct but don't ask me to spell "semantic" in Russian or Japanese because I do not speak nor write those languages.
 
12/07/18, 05:32 AM   #8
sirinsidiator
 
sirinsidiator's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 1,566
Originally Posted by Drakanwulf View Post
Exactly, and my suggestion was meant to promote actively not loading duplicates, which ZOS and ESO can't do, but add-on developers can and should do... but that's just my opinion. Of course, the backlash from the user community would affect some add-on developers more than others, if one were to follow that path.
I feel like I am talking against a wall again... You still don't seem to understand that ESO already actively not loads duplicates. When you have version 1 and version 2 of "SomeAddon" in different subfolders of your addon folder, only SomeAddon v2 is loaded by the game. There is no need for any code written by the addon author to prevent v1 from loading, since the game already takes care of that. That's exactly the reason why we need to get rid of LibStub, because LibStub is not capable of doing that.

Originally Posted by Drakanwulf View Post
Right now, it is impossible to "legally" retrieve the AddOnVersion for any add-on. You have to "guess" at values that you cannot get. An optimal solution, in my view, would be for ESO to provide the current AddOnVersion and the manifest AddOnVersion to the add-on developer so they could make their decisions based on fact. And that was my point!
It is true that you cannot retrieve the value from the manifest file, but you can simply copy the number you put in the manifest into any of your Lua files and you have EXACTLY the number you want with no guessing involved, since the game makes sure that only one version of your addon is loaded when you specify the AddOnVersion in the manifest. I repeat again, there is no uncertainty that the number you have in your code is the same as the one in the manifest when you take care that you update it in both the txt and lua file.
 
12/07/18, 04:20 PM   #9
Drakanwulf
 
Drakanwulf's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2017
Posts: 50
Originally Posted by sirinsidiator View Post
I feel like I am talking against a wall again... You still don't seem to understand that ESO already actively not loads duplicates. When you have version 1 and version 2 of "SomeAddon" in different subfolders of your addon folder, only SomeAddon v2 is loaded by the game. There is no need for any code written by the addon author to prevent v1 from loading, since the game already takes care of that. That's exactly the reason why we need to get rid of LibStub, because LibStub is not capable of doing that.
No walls, sirinsidiator, just a misunderstanding and some miscommunication between us. I do understand that ESO already does not load duplicates. That is not my issue. My point is that, what ESO does not do is to actively reject embedded folders that contain duplicate add-ons, nor does ESO provide an option to select whether we want to process and accept or reject duplicate folder packaging!

What I am trying to do is to eliminate the poor packaging and the substandard code that lets duplicate folders remain in poorly constructed and/or maintained add-on packages. Right now, for example, I use a stand-alone LibStub on PTS as a test bed to load my libraries. It is the only copy of LibStub in my PTS system and all my libraries share it. It works.

Problems arise, however, whenever my libraries use other developer's libraries and those other libraries contain unneeded and unnecessary, duplicate LibStub folders that those developers embedded to load their libraries. This folder duplication is not an issue, per se, because their add-ons also load and work so that is not the focus of my efforts.

My complaint is that processing these duplicate folders and their manifests only to dump their add-ons as duplicates wastes time and resources that could be better spent loading additional add-ons. If we could eliminate processing these duplicate folders, we would probably speed up starting the game, or "zoning", or anytime anything triggers an internal "/reloadui" event and we would probably reduce the possibility of add-on load failures or run-time errors as an additional bonus.

My irritation is that embedded folders often break loading my add-ons because their add-on developers "forgot" to maintain or replace an embedded add-on folder. I refer to this as an irritation only because I do it to myself all to often.

What I am trying to do within the stand-alone environment is to create a methodology for loading stand-alone add-ons that provides us developers (and ESO) with the option to accept or reject duplicate add-ons and their embedded folders. I think I may have succeeded. I shall be passing the latest LoadAddon stub by you and the other add-on developers for comments and critiques soon.

Originally Posted by sirinsidiator View Post
It is true that you cannot retrieve the value from the manifest file, but you can simply copy the number you put in the manifest into any of your Lua files and you have EXACTLY the number you want with no guessing involved, since the game makes sure that only one version of your addon is loaded when you specify the AddOnVersion in the manifest. I repeat again, there is no uncertainty that the number you have in your code is the same as the one in the manifest when you take care that you update it in both the txt and lua file.
And what happens when someone else modifies the AddOnVersion value in the manifest file of their copy of my add-on? Right! Suddenly, ESO refuses to load my add-on because "my" AddOnVersion number has become older than the ESO version. Since I have no access to the current ESO AddOnVersion value, I have to keep "guessing" at values until I find a randomly, larger number that works!

And what if some malicious, piece of work changes the AddOnVersion value in their manifest file to 2,147,483,647? There is no larger value that I can use to recover! Then what can I do? What would you do? Or what would ESO do should the same thing happen to one of our add-ons? Or to one of theirs, for that matter?

That is why I think "guessing" at AddOnVersion values is an incomplete approach to implementing version controls.

Last, I appreciate your patience and persistence, sirinsidiator. I learn something every time we engage in one of these discussions. And even should the effort I spent developing the LoadAddon stub prove to have been wasted effort on my part, I still will have learned something. I thank you.

Last edited by Drakanwulf : 12/07/18 at 04:22 PM. Reason: Typos... I hate typos...
 
12/09/18, 07:02 AM   #10
sirinsidiator
 
sirinsidiator's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 1,566
Originally Posted by Drakanwulf View Post
My complaint is that processing these duplicate folders and their manifests only to dump their add-ons as duplicates wastes time and resources that could be better spent loading additional add-ons. If we could eliminate processing these duplicate folders, we would probably speed up starting the game, or "zoning", or anytime anything triggers an internal "/reloadui" event and we would probably reduce the possibility of add-on load failures or run-time errors as an additional bonus.
No. Processing the manifest only saves you a few milliseconds at best. The majority of the time during load is used up by running the actual code and saved variables (table creation is very expensive in Lua).

Originally Posted by Drakanwulf View Post
My irritation is that embedded folders often break loading my add-ons because their add-on developers "forgot" to maintain or replace an embedded add-on folder. I refer to this as an irritation only because I do it to myself all to often.
Embedded addons don't do that. They are simply not loaded by the game when they are outdated and a newer version is present anywhere in the addon folder. Only the old LibStub based libraries worked that way since LibStub cannot know beforehand which version will be the highest and has to execute every version it comes across. That's why we want to get rid of LibStub, but that has nothing to do with this topic.

Originally Posted by Drakanwulf View Post
And what happens when someone else modifies the AddOnVersion value in the manifest file of their copy of my add-on? Right! Suddenly, ESO refuses to load my add-on because "my" AddOnVersion number has become older than the ESO version. Since I have no access to the current ESO AddOnVersion value, I have to keep "guessing" at values until I find a randomly, larger number that works!

And what if some malicious, piece of work changes the AddOnVersion value in their manifest file to 2,147,483,647? There is no larger value that I can use to recover! Then what can I do? What would you do? Or what would ESO do should the same thing happen to one of our add-ons? Or to one of theirs, for that matter?
This is simply not something an author should need to worry about. When a user modifies their local copy, they loose their warranty and if another author distributes a modified version of your library, it's a reason to get it taken down since it is a violation of your license (and honestly, there are no cases I know of in 4+ years where this has become an issue with any of my or any other authors libraries)
 
12/09/18, 04:32 PM   #11
Drakanwulf
 
Drakanwulf's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2017
Posts: 50
Thanks for filling in the reasons and giving me answers to the questions I have had. The information you chose to share should be put into a "'ESO .lua for Dummies" book because it is that good.

Nevertheless, I am going to test one of your answers because I think ESO does not work that way. I will be very happy when I find out that you were correct and that I was wrong... again...

Embedded addons don't do that. They are simply not loaded by the game when they are outdated and a newer version is present anywhere in the addon folder. Only the old LibStub based libraries worked that way since LibStub cannot know beforehand which version will be the highest and has to execute every version it comes across. That's why we want to get rid of LibStub, but that has nothing to do with this topic.
Because these two add-ons are both Stand-Alone add-ons and because neither use LibStub, per se, (LibMaps does use LibStub:GetLibrary to load LibGPS2) I am going to embed a LoadAddon folder within a copy of a LoadAddon folder and also embed a LibMaps folder within a copy of a LibMaps folder just to see what happens. I expect ESO to pass them on for loading which will invoke the .lua table creation time-wasting penalties you mentioned but I will be so very happy to have absolutely nothing happen when these deliberately botched up folders are loaded only one time.
 
12/09/18, 09:04 PM   #12
Drakanwulf
 
Drakanwulf's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2017
Posts: 50
Well, I was pleasantly surprised, sirinsidiator, to find that ESO quietly discarded my first attempt to load a duplicate "LoadAddon" via an embedded folder. So I was wrong, again... darn it! But now I know why I was wrong which I did not know before.

The good news is that I also proved to my satisfaction that the "LoadAddon" stub does not interfere with anything ESO does and it can help trap and debug really dumb packaging mistakes. In other words; it doesn't hurt anything and it can help in specific circumstances.

This is the content of a the first LoadAddon folder. This is the folder I would use on the Live servers. LoadAddon loaded without error and successfully created its "LoadAddon" global table. LoadAddon was left running as a Stand-Alone add-on while the other tests were completed.

Code:
## Title: LoadAddon
## Description: A Stand-Alone Stub for loading and updating Stand-Alone Add-ons. 
## Version: 1.0.0
## AddOnVersion: 100
## APIVersion: 100025 100026
## DependsOn:
## SavedVariables:
## Contributors: Seerah, sirinsidiator, Votan, Baertram, and many more
## Author: Drakanwulf & Hawkeye1889

LoadAddon.lua

; This Add-on was not created by, affiliated with, or sponsored by, ZeniMax Media Inc. or its affiliates. 
; The Elder Scrolls® and related logos are registered trademarks or trademarks of ZeniMax Media Inc. in the United States and/or other countries.
; All rights reserved
;
; You can read the full terms at https://account.elderscrollsonline.com/add-on-terms
And this is the content of the first test of the TestEmbedding folder and manifest file. As you can see, all it does is try to load a "LoadAddon" folder a second time. ESO caught this mistake and quietly disposed of the duplicate load attempt. This is a really good thing. I did not fully comprehend the significance of this improvement until I saw it for myself.

Code:
## Title: LoadAddon
## Description: A Stand-Alone Stub for loading and updating Stand-Alone Add-ons. 
## Version: 1.0.0
## AddOnVersion: 100
## APIVersion: 100025 100026
## DependsOn:
## SavedVariables:
## Contributors: Seerah, sirinsidiator, Votan, Baertram, and many more
## Author: Drakanwulf & Hawkeye1889

LoadAddon

; LoadAddon.lua

; This Add-on was not created by, affiliated with, or sponsored by, ZeniMax Media Inc. or its affiliates. 
; The Elder Scrolls® and related logos are registered trademarks or trademarks of ZeniMax Media Inc. in the United States and/or other countries.
; All rights reserved
;
; You can read the full terms at https://account.elderscrollsonline.com/add-on-terms
And this is the content of the second test of the TestEmbedding folder and manifest file. As you can see, this test contains a really stupid mistake because the manifest tries to load the "LoadAddon" folder a second time which ESO caught, but ESO did not catch the third attempt to load the "LoadAddon.lua" file itself. ESO passed the third try through to the add-on code when it loaded the add-on by mistake.

Code:
## Title: LoadAddon
## Description: A Stand-Alone Stub for loading and updating Stand-Alone Add-ons. 
## Version: 1.0.0
## AddOnVersion: 100
## APIVersion: 100025 100026
## DependsOn:
## SavedVariables:
## Contributors: Seerah, sirinsidiator, Votan, Baertram, and many more
## Author: Drakanwulf & Hawkeye1889

LoadAddon

LoadAddon.lua

; This Add-on was not created by, affiliated with, or sponsored by, ZeniMax Media Inc. or its affiliates. 
; The Elder Scrolls® and related logos are registered trademarks or trademarks of ZeniMax Media Inc. in the United States and/or other countries.
; All rights reserved
;
; You can read the full terms at https://account.elderscrollsonline.com/add-on-terms
The attachment is a cropped screenshot of a ZBug window showing the assertion trap message for the really stupid, duplicate attempt. This was a bad thing, in my opinion, because the first load of LoadAddon (AddOnVersion 100) was still running when the "third" load was requested. A "/tbug LoadAddon" command showed that the global "LoadAddon" link was still there after all the tests and rejections had been completed.

I think you can verify what I did by using one of your own Stand-Alone add-ons to corroborate the hiccup in the duplicate load detection and prevention methodology. Anyway, I am a happy camper again. Thanks for all your help and assistance. We can continue this discussion in private on the Gitter channel if you would like to do so.
Attached Thumbnails
Click image for larger version

Name:	ZBug1920x1080.png
Views:	778
Size:	1.24 MB
ID:	1066  
 
12/10/18, 03:19 AM   #13
Baertram
Super Moderator
 
Baertram's Avatar
WoWInterface Super Mod
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 4,912
Thanks for the inisights, to both of you.
I got one question though:

Are we able to load whole "folders" with the manifest files, like DrakanWulf did with his "LoadAddon" entry (without .lua or .xml file extension)?
What does lua do in this case? Load all supported files + files in subfolders automatically?
 
12/10/18, 05:53 AM   #14
sirinsidiator
 
sirinsidiator's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 1,566
An interesting question. I don't know the actual answer (yet), but my guess is the line would just get ignored by the game, since it's not a valid file.
 
12/11/18, 03:21 PM   #15
Drakanwulf
 
Drakanwulf's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2017
Posts: 50
^^ @Baertram and @sirinsidiator ...

The ability to load add-on .lua files from folder names is what I have always meant when I referred to "embedding" add-on folders within other folders. Otherwise, how could the "##DependsOn:" and "##OptionalDependsOn:"directives work since they use only folder names? These two directives imply an innate ability to find and load .lua add-on files from the manifest files contained within their folder names.

Thinking more about the test results, it appears to me that ESO is attaching the AddOnVersion number to the folder name, and/or its manifest file, and ignoring the .lua files; otherwise, neither the "LoadAddon" folder nor the "LoadAddon.lua" file should have loaded during the TestEmbedding tests. The folder test did not load the add-on file but the filename test did load the file a second time.

I think there is still something not quite correct with the ESO add-on loading logic. If, as sirinsidiator said, the first test ignored the "LoadAddOn" folder because it was not a file name, then that premise invalidates the behavior of the second test which loaded the same "LoadAddon.lua" file twice rather than ignoring or discarding the file.

According to the AddVersion number logic, as I understand it, this is not supposed to occur. The second, and successive, load attempts of any .lua add-on with a current (i.e. equal) AddOnVersion number are supposed to be "ignored" and/or "discarded" because a prior instance of "LoadAddon.lua" is already running.

I should like to run more test variations based on both of your comments and report the findings in the Gitter channel because this discussion has become more of a developmental issue rather than an ESO wish-list topic.

I have placed the "LoadAddon" .lua and manifest files into a GitHub repository. I shall try to wake up early tomorrow, Wednesday, so I can join both of you on the Gitter channel at a more decent hour for all of us.

FYI, @Baertram & sirinsidiator, it was your commentaries in answer to TomTomHotep's questions in the Comments page for the r5 version of the "LibStub" add-on that caused Hawkeye1889 and me to begin work on the "LoadAddon" stub as a template for loading Stand-Alone add-ons. Everything else since then has been caused by our misunderstandings of testing inconsistencies and what was written in the wiki or what we discovered while testing "LoadAddon" or what ESO were reputed to have said about loading .lua add-ons.

("If it isn't written down, it never happened!". This quotation is from Dr. Anne Ryan, wife of Jack Ryan, in response to a question about why she was always making notes. Mr. Ryan is the main protagonist in Tom Clancy's "Patriot Games" and other novels. Remembering this quotation and what it means, is why I am such a stickler about updating the ESOUI wiki accurately and often.).

Last edited by Drakanwulf : 12/11/18 at 04:07 PM. Reason: Syntax and accuracy improvements.
 

ESOUI » Developer Discussions » Wish List » [implemented] addon manager improvements

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off