SketchUcation Premium Membership

 

 

Observers WhishList

Re: Attribute Observers

Postby Dan Rathbun » Mon Dec 21, 2009 1:51 pm

thomthom wrote:
Whaat wrote:... For example, OnEntityChanged, what constitutes a 'change'?

Yea - I spent some time on this because I was setting attributes - which seems to be a change. Not sure if I want that to trigger. At least not most of the times. attributes are like meta data.
maybe onChange for geometric changes, and onAttribChange(dict, key, oldVal, newVal) for the attribute meta data?


Do changes to an Attribute currently fire onEntityChanged events?
What about adding or deleting an attribute from a Dictionary?
What about adding or deleting a Dictionary from an Entity?
User avatar
Dan Rathbun
Top SketchUcator
 
Posts: 4146
Joined: Tue Oct 06, 2009 3:06 am
Location: Florida, USA
Name: Dan Rathbun
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: education
Level of SketchUp: Advanced

Re: Attribute Observers

Postby Dan Rathbun » Sat Jan 02, 2010 3:16 am

Dan Rathbun wrote:
thomthom wrote:
Whaat wrote:... For example, OnEntityChanged, what constitutes a 'change'?

Yea - I spent some time on this because I was setting attributes - which seems to be a change. Not sure if I want that to trigger. At least not most of the times. attributes are like meta data.
maybe onChange for geometric changes, and onAttribChange(dict, key, oldVal, newVal) for the attribute meta data?

Do changes to an Attribute currently fire onEntityChanged events?
What about adding or deleting an attribute from a Dictionary?
What about adding or deleting a Dictionary from an Entity?

EDIT
I asked this because, it would lead to whether we need EntityObserver methods:
onBeforeAttributeAdd(entity, dict, key, value)
onAfterAttributeAdd(entity, dict, key, value,
result)
onBeforeAttributeDelete(entity, dict, key, value)
onAfterAttributeDelete(entity, dict, oldKey, oldVal,
result)
Also, ThomThom's example needs the entity handle passed.
onAttribChange(entity, dict, key, oldVal, newVal)*
* would assume change result was 'true' (successful)


onBeforeDictionaryAdd(entity, newDict)
onAfterDictionaryAdd(entity, dict,
result)
onBeforeDictionaryDelete(entity, dict)
onAfterDictionaryDelete(entity, oldDict,
result)

Also would a DictionaryObserver be necessary?
(I'd think not as most Attribute and Dictionary functions are available thru the Entity object.)
User avatar
Dan Rathbun
Top SketchUcator
 
Posts: 4146
Joined: Tue Oct 06, 2009 3:06 am
Location: Florida, USA
Name: Dan Rathbun
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: education
Level of SketchUp: Advanced

Re: Observers WhishList

Postby thomthom » Mon Jan 04, 2010 11:40 am

So what's the latest gossip from the Google camp on this topic?
Thomas Thomassen — SketchUp Monkey & Coding addict
List of my plugins and link to the CookieWare fund
User avatar
thomthom
Global Moderator
 
Posts: 17909
Joined: Tue Nov 13, 2007 12:47 pm
Location: Trondheim, Norway
Name: Thomas Thomassen
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: architecture
Level of SketchUp: Advanced

need AppObserver.onCloseModel

Postby Dan Rathbun » Wed Jan 06, 2010 11:52 am

need AppObserver.onCloseModel
Sketchup Ruby API wrote:It is often used to attach other observers to each model as it is opened or started. This ensures that your observers are watching all open models.
http://code.google.com/apis/sketchup/docs/ourdoc/appobserver.html

In an MDI application (as the Mac is now, and hopefully the PC will be in upcoming versions,) there needs to be a way to detect that an MDI child window has been closed, so scripts can do cleanup, such as unattaching observers that may have been attached using onNewModel or onOpenModel.

Of course on the PC, at the current time, Sketchup is not yet an MDI application; and to close the active model, a user would either open a new model (firing the onNewModel event,) open another model from a file (firing the onOpenModel event,) OR shut down Sketchup (firing the onQuit event.)
_
User avatar
Dan Rathbun
Top SketchUcator
 
Posts: 4146
Joined: Tue Oct 06, 2009 3:06 am
Location: Florida, USA
Name: Dan Rathbun
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: education
Level of SketchUp: Advanced

Import / Export Observers

Postby Dan Rathbun » Wed Jan 06, 2010 3:51 pm

_
I've noticed there does not seem to be Observers for classes:
  • Importer
  • Exporter
  • TextureWriter
Anyone think there's any need here?
_
User avatar
Dan Rathbun
Top SketchUcator
 
Posts: 4146
Joined: Tue Oct 06, 2009 3:06 am
Location: Florida, USA
Name: Dan Rathbun
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: education
Level of SketchUp: Advanced

Re: Observers WhishList

Postby thomthom » Wed Jan 06, 2010 4:00 pm

Can't see any reason.
It's the changes in the model that we need to be aware of. Importer, Exporter, and TextureWriter doesn't affect the model.
..well, the importer imports geometry, but the EntitiesObserver and DefinitionObserver and InstanceObserver should take care of that.
Thomas Thomassen — SketchUp Monkey & Coding addict
List of my plugins and link to the CookieWare fund
User avatar
thomthom
Global Moderator
 
Posts: 17909
Joined: Tue Nov 13, 2007 12:47 pm
Location: Trondheim, Norway
Name: Thomas Thomassen
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: architecture
Level of SketchUp: Advanced

SelectionObserver needs fixing!

Postby Dan Rathbun » Tue Jan 12, 2010 5:56 pm

_
Sketchup::SelectionObserver

This observer needs fixing! I would put this in the high priority group.

Per ThomThom's Observer Review "State of Observers"
http://forums.sketchucation.com/viewtopic.php?f=180&t=20676&start=0#p173630

Sketchup::SelectionObserver

.onSelectionAdded never triggers
.onSelectionRemoved never triggers.

Instead,
.onSelectionBulkChange and .onSelectionCleared always triggers.
_
User avatar
Dan Rathbun
Top SketchUcator
 
Posts: 4146
Joined: Tue Oct 06, 2009 3:06 am
Location: Florida, USA
Name: Dan Rathbun
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: education
Level of SketchUp: Advanced

Re: Observers WhishList

Postby thomthom » Thu Jan 21, 2010 3:37 pm

Why doesn't this observer have its own class documented as the other observers? http://code.google.com/intl/nb/apis/ske ... e_observer
Thomas Thomassen — SketchUp Monkey & Coding addict
List of my plugins and link to the CookieWare fund
User avatar
thomthom
Global Moderator
 
Posts: 17909
Joined: Tue Nov 13, 2007 12:47 pm
Location: Trondheim, Norway
Name: Thomas Thomassen
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: architecture
Level of SketchUp: Advanced

Re: FrameChangeObserver

Postby Dan Rathbun » Thu Jan 21, 2010 8:15 pm

FrameChangeObserver
thomthom wrote:Why doesn't this observer have its own class documented as the other observers? http://code.google.com/intl/nb/apis/sketchup/docs/ourdoc/pages.html#add_frame_change_observer

I would guess that this was a pre-version 6 observer implementation, added before they 'set a standard' in version 6 for true observer prototypes defined under the Sketchup module. And that when they did add those formally defined Observer classes in version 6, this one fell through the cracks.

I checked the Object list... and there is no observer prototype named 'FrameChangeObserver' defined.
I checked the Sketchup::Pages class for it's methods:
Code: Select all
pages.public_methods(false).sort
["[]", "add", "add_matchphoto_page", "add_observer", "count", "each", "erase", "parent", "remove_observer", "selected_page", "selected_page=", "show_frame_at", "size", "slideshow_time"]
There are NO methods:
  • add_frame_change_observer
  • remove_frame_change_observer
This information is OBSOLETE in the API, and should be removed.

A coder (currently) would have to use the Sketchup::ViewObserver, onViewChanged method to detect when the change of view finished.

IF there is a need (for the functionality of a FrameChangeObserver,) you might propose a Sketchup::AnimationObserver class that has this callback function and perhaps others?

Jim might want to weigh in on this, as he has been working on Animation lately.

@Jim : Questions:
  • Would an attached AnimationObserver be expected to slow the framerates?
  • Would an AnimationObserver even be necessary? (As really the Animation interface, is somewhat like an observer itself. The pause, resume and stop methods act like observer callbacks.)
_
User avatar
Dan Rathbun
Top SketchUcator
 
Posts: 4146
Joined: Tue Oct 06, 2009 3:06 am
Location: Florida, USA
Name: Dan Rathbun
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: education
Level of SketchUp: Advanced

Re: SelectionObserver needs fixing!

Postby ptitjes » Fri Jan 29, 2010 12:25 pm

Dan Rathbun wrote:_
Sketchup::SelectionObserver

This observer needs fixing! I would put this in the high priority group.

I highly second that request! SelectionObserver is broken.

Dan Rathbun wrote:Per ThomThom's Observer Review "State of Observers"
http://forums.sketchucation.com/viewtopic.php?f=180&t=20676&start=0#p173630

Sketchup::SelectionObserver

.onSelectionAdded never triggers
.onSelectionRemoved never triggers.

Instead,
.onSelectionBulkChange and .onSelectionCleared always triggers.
_


Here even onSelectionCleared is not even triggered. (SU 7.1 (7.1.5803) on MacOS SnowLeaopard) This makes working on selections quite impossible and you can't do that in a right way.

Also, plugins should be loaded before any new model is created in SU. Because AppObservers are not triggered for the initial new model open when lauching sketchup.

Both those issues could be easily fixed. I don't know whether sketchup dev team is reading this forum, but please fix that!

Didier.
ptitjes
 
Posts: 1
Joined: Fri Jan 22, 2010 9:31 pm

Re: Observers WhishList

Postby thomthom » Fri Jan 29, 2010 12:35 pm

ptitjes wrote:Both those issues could be easily fixed. I don't know whether sketchup dev team is reading this forum, but please fix that!

This post was started by a Google Sketchup employee. ;)
Thomas Thomassen — SketchUp Monkey & Coding addict
List of my plugins and link to the CookieWare fund
User avatar
thomthom
Global Moderator
 
Posts: 17909
Joined: Tue Nov 13, 2007 12:47 pm
Location: Trondheim, Norway
Name: Thomas Thomassen
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: architecture
Level of SketchUp: Advanced

Sketchup::AppObserver

Postby Dan Rathbun » Sun Jan 31, 2010 12:12 am

Sketchup::AppObserver

Anyone interested in any of the following event methods?

Extensions
Sketchup.register_extension
onRegisterExtension( extObj, loadFlag, regResult )
onLoadExtension( extObj, loadResult )


* onUnloadExtension needs fixing. Currently passes the extension name, BUT text names are not necessarily unique, for example there are several extensions, by several different authors called "SelectionMemory".
In addition what would we do with a textname anyway? There is no method to find an ExtensionObject by searching using a textname, as well as even having access to the ExtensionsCollection/Manager.
We definately need the object handle passed, then we can access any of the extensions attributes, including the name, example:

onUnloadExtension( extObj )


Internet Connection
IF Sketchup.is_online returns false, an Observer could be used to watch for an when an Internet Connection is established. This may be needed for some extensions that download help information, or textures or other files from the internet (especially when the user has a dial-up connection.)
onInternetConnect
onInternetDisconnect



Send Action
fired by Sketchup.send_action
onBeforeSendAction( action )
onAfterSendAction( action, result )



Thumbnails Bulk events
Would likely be used by Gallery or webpage generator Plugin extensions.
onAfterSaveThumb( obj, img, result )
onBeforeSaveThumb( obj, img )


When fired by:
ComponentDefinition.save_thumbnail
Model.save_thumbnail
View.write_image
(if img is thumbSize)
  • obj is the source object handle
  • img is the output imgStringPathname
When fired by:
Sketchup.save_thumbnail
  • obj is the input skpStringPathname
  • img is the output imgStringPathname
_
User avatar
Dan Rathbun
Top SketchUcator
 
Posts: 4146
Joined: Tue Oct 06, 2009 3:06 am
Location: Florida, USA
Name: Dan Rathbun
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: education
Level of SketchUp: Advanced

Re: Observers WhishList

Postby thomthom » Sun Jan 31, 2010 2:26 am

Can't say I've ever wanted/needed those events. It's the events that relates to model changes that I'd wish where working reliably.
Thomas Thomassen — SketchUp Monkey & Coding addict
List of my plugins and link to the CookieWare fund
User avatar
thomthom
Global Moderator
 
Posts: 17909
Joined: Tue Nov 13, 2007 12:47 pm
Location: Trondheim, Norway
Name: Thomas Thomassen
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: architecture
Level of SketchUp: Advanced

Re: Observers WhishList

Postby dkendig » Thu Feb 25, 2010 6:27 pm

We have always had a hard time ensuring our plugin's data is properly serialized in to the scene prior to a save. Now we serialize after every - single - change... and it slows things down a little. The proposed solution for onSaveModel would be wonderful... oh please magical Google genies... please fix these observer issues. Here's a post we put in the discussion groups a while back when we were pulling our hair out:

http://groups.google.com/group/Ruby-API/browse_thread/thread/bf156b08bdb9ba71/5b9ac6cc4a3bb83c#5b9ac6cc4a3bb83c
dkendig
 
Posts: 179
Joined: Tue Jul 01, 2008 4:41 pm
Location: Baltimore, MD

Re: Observers WhishList

Postby tomot » Thu Jun 24, 2010 6:52 pm

It really bugs me! when I'm doing a load "Filename.rb" into the Ruby Console, that the revised "Filename.rb" may run as expected, only to find out that "Filename.rb" really didn't work. because I had not actually quit the currently running SU.

I'm not sure if this is an Observer issue: It would be really nice if there was a closer OBSERVATION on the part of the API that scripts work or don't work. I don't ever recall having to Quit AutoCad, and restarting it each time I was testing Lisp routines.

In fact GLD is Archicad's API, is even more elegant, the code is written totally within the ArchiCad application in its own GLD window, errors are flagged without ever having to quit the main ArchiCad application.
tomot
 
Posts: 615
Joined: Mon Apr 07, 2008 12:18 am
Operating system: Windows
SketchUp version: 8
License type: Free/Make
SketchUp use: architecture
Level of SketchUp: Advanced

Re: Observers WhishList

Postby Dan Rathbun » Thu Jun 24, 2010 10:12 pm

tomot wrote:It really bugs me! when I'm doing a load "Filename.rb" into the Ruby Console, that the revised "Filename.rb" may run as expected, only to find out that "Filename.rb" really didn't work. because I had not actually quit the currently running SU.

Is ALL of the code written in the "Filename.rb" wrapped within a second level module block?
It should be.
When it is, from the console, you can type:
<1stLevelModule>.module_eval('remove_const :<2ndLevelModule>')
and the entire 2nd Level module should be undefined. Then type
GC.start to run garbage collection.
Then you can reload your script, and redefine the second level module.

What I'm saying is that all of your plugins should be inside modules, which are ALL inside a master module that is YOUR namespace, such as "Tomot".
example:
Code: Select all
module Tomot
  module My_Plugin_One
    # CONSTANTS
    # @@module vars
    # class definitions
    # method definitions
    begin
      # run once code
    end
  end # My_Plugin_One
end # Tomot

Then when you wish to reload (at the console):
Tomot.module_eval('remove_const :My_Plugin_One')
GC.start
load 'tomot/plugin_one.rb'
(You might even put that in a temporary Tomot module method, to automate the cleanup and reload of any Tomot submodule or subclass, etc. Make a couple of constants Tomot::MODNAME and Tomot::MODPATH that you can change at will, and have the method use those constant's String values in the 1st and 3rd lines, respectively.) Sorta like this:
Code: Select all
Tomot.const_set(:MODNAME,'My_plugin_One')
Tomot.const_set(:MODPATH,'tomot/plugin_one.rb')
def Tomot.reload
  module_eval( "remove_const :#{MODNAME}" )
  GC.start
  load("#{MODPATH}")
end


You'd repeat the process, for other plugins, always defining them WITHIN your master namespace (module Tomot,) and each WITHIN it's own submodule. Yes if you create classes that are common to more than one of your plugins, they can be defined at the 2nd level, directly under Tomot, and they ALSO can be removed and reloaded because the name of a Class, is also a constant (just as a module identifier is.)

Top Level modules and classes (which should only be the Ruby base classes and modules,) cannot be removed (by design.)

Now this will not solve ALL of the challenges with SU API developement, because many objects are really C++ objects and cannot be garbage collected by Ruby. But we can reduce many of the problems, by at least coding on the Ruby side, in the proper Ruby way.
There have been many discussions in the forum on unattaching and 'cleaning up' observers.

As far as reloading SU. Sometimes it just must be done, especially if your working with menus. We cannot at present remove menu items.
To make things faster, in development, I have a bare-bones Sketchup copy with minimal development plugins only (and the DC extension,) that loads fast. On Windows, we can run Sketchup differently, by using extra user accounts, and using RunAs.. to access these differnt setups from the main user account.
See my posts Saving multiple workspaces (and run batch file from ruby as admistrator perhaps if you wanted to use a batchfile and icons.)

Now.. I agree with you and others, it would be great to have a good bridge between Ruby GC and C++ GC (if that's what it's called in C++.) So that things get cleaned on both sides when no longer in use.
User avatar
Dan Rathbun
Top SketchUcator
 
Posts: 4146
Joined: Tue Oct 06, 2009 3:06 am
Location: Florida, USA
Name: Dan Rathbun
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: education
Level of SketchUp: Advanced

Re: Observers WhishList

Postby tomot » Fri Jun 25, 2010 2:12 am

Dan: Thank you for your detailed explanation. Early on when I first looked at Ruby scripting, I knew nothing about Ruby and I still know very little. Many of the examples I used were from donated scripts, from which I borrowed and referenced code to develop my own self taught scripts, there were no module examples to speak or copy from. Its easy to see why not more people get engaged with Ruby.
To a novice trying to make sense of the current SU Ruby API descriptions and examples, is like shining a light on a subject without a battery in the flashlight. :)
tomot
 
Posts: 615
Joined: Mon Apr 07, 2008 12:18 am
Operating system: Windows
SketchUp version: 8
License type: Free/Make
SketchUp use: architecture
Level of SketchUp: Advanced

Re: Observers WhishList

Postby Dan Rathbun » Fri Jun 25, 2010 7:49 am

tomot wrote:Many of the examples I used were from donated scripts, from which I borrowed and referenced code to develop my own self taught scripts, there were no module examples to speak or copy from.

See this thread at GoogleGroups, begining with post 4, in which Harald asks the question "... so, are all my .rb scripts really just one huge script?"
He was having trouble with the Ruby environment getting corrupted with classes, objects, methods and so forth.. that he didn't want loaded.
Read my detailed responces, which explain how things get loaded (both in Sketchup Ruby, and Ruby in general,) and an example of file spanning.
User avatar
Dan Rathbun
Top SketchUcator
 
Posts: 4146
Joined: Tue Oct 06, 2009 3:06 am
Location: Florida, USA
Name: Dan Rathbun
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: education
Level of SketchUp: Advanced

Re: Observers WhishList

Postby thomthom » Fri Jun 25, 2010 8:08 am

Unfortunately, the Google examples does not encapsulate their code. But you'll find most plugins here at SCF are. Usually it's the older ones that doesn't.
The norm is encapsulate the script in a module which is prefixed with your initials - that goes a long way to prevent namespace collisions. I use TT_, Jim use JF_, Chris use Clf_, etc.
Thomas Thomassen — SketchUp Monkey & Coding addict
List of my plugins and link to the CookieWare fund
User avatar
thomthom
Global Moderator
 
Posts: 17909
Joined: Tue Nov 13, 2007 12:47 pm
Location: Trondheim, Norway
Name: Thomas Thomassen
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: architecture
Level of SketchUp: Advanced

Re: Observers WhishList

Postby thomthom » Fri Jun 25, 2010 8:09 am

tomot wrote:To a novice trying to make sense of the current SU Ruby API descriptions and examples, is like shining a light on a subject without a battery in the flashlight. :)

Yea - :D - that description sounds just about right.
Thomas Thomassen — SketchUp Monkey & Coding addict
List of my plugins and link to the CookieWare fund
User avatar
thomthom
Global Moderator
 
Posts: 17909
Joined: Tue Nov 13, 2007 12:47 pm
Location: Trondheim, Norway
Name: Thomas Thomassen
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: architecture
Level of SketchUp: Advanced

Re: Observers WhishList

Postby PurpLev » Wed Jun 30, 2010 8:45 pm

+1 for EntityObserver currently it's pretty much unusable as it crashes SU when it intercepts anything and tries to perform more than a single printout to the console.
PurpLev
 
Posts: 20
Joined: Tue Jun 22, 2010 6:25 pm
Location: Boston, MA
Name: Sharon

Re: Observers WhishList

Postby kwalkerman » Mon Jul 26, 2010 4:42 pm

I definitely add my vote for an onBeforeSave for the Model Observer. Right now, I am doing some stuff and then re-saving...

A few things I came across:

1. re-saving triggers the onSave method in your application, and in any other plugins that have a Model Observer. This can lead to an annoying infinite loop. I fixed this problem by requiring that the times between saves be greater than a certain set time.

2. Once you re-save your model, the model observer immediately calls the onSave method. This means that any code below Sketchup.active_model.save "my model.skp" will not be executed until after the onSave is called and executed again... so any infinite loop prevention should be above the save command.


--
Karen
kwalkerman
 
Posts: 135
Joined: Mon Feb 08, 2010 9:48 pm
Name: Karen

Re: Observers WhishList

Postby Aerilius » Sat Oct 01, 2011 2:30 am

When hiding a layer that contains selected entities, these entities get un-selected. This seems not to trigger onSelectionBulkChange (or even onSelectionCleared).
Aerilius
Top SketchUcator
 
Posts: 1178
Joined: Tue Dec 23, 2008 11:00 pm
Location: Kaiserslautern
Name: Aerilius

Re: Observers WhishList

Postby Dan Rathbun » Sat Oct 01, 2011 9:40 am

The SelectionObserver still seems to be the most problematic of all the observers.
http://www.thomthom.net/software/sketch ... onObserver
User avatar
Dan Rathbun
Top SketchUcator
 
Posts: 4146
Joined: Tue Oct 06, 2009 3:06 am
Location: Florida, USA
Name: Dan Rathbun
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: education
Level of SketchUp: Advanced

Re: Observers WhishList

Postby havanasud » Mon Feb 27, 2012 2:53 pm

Hi, ViewObserver works on mac?
havanasud
 
Posts: 1
Joined: Fri Jul 01, 2011 3:08 pm
Name: Angel Danton

Re: Observers WhishList

Postby thomthom » Mon Feb 27, 2012 4:01 pm

havanasud wrote:Hi, ViewObserver works on mac?

Hi

Are you experiencing any problems or unforeseen behavior?

I've not heard of any issues. Think I've used it a couple of times and so far not received any reports of issues.

http://www.thomthom.net/software/sketch ... ewObserver (Note - not everything here is tested. So if you find an issue, please let me know so I can update the chart.)
Thomas Thomassen — SketchUp Monkey & Coding addict
List of my plugins and link to the CookieWare fund
User avatar
thomthom
Global Moderator
 
Posts: 17909
Joined: Tue Nov 13, 2007 12:47 pm
Location: Trondheim, Norway
Name: Thomas Thomassen
Operating system: Windows
SketchUp version: 2013
License type: Pro
SketchUp use: architecture
Level of SketchUp: Advanced

SketchUcation One-Liner Adverts

by Ad Machine » 5 minutes ago

Artisan Organic Toolset - a set of powerful organic modeling tools.

Premium Members get 20% discount!

Ad Machine
Robot
 
Posts: 2012

Previous

Return to Developers' Forum

Who is online

Users browsing this forum: No registered users and 6 guests