Old 10-27-2018, 10:28 PM   #81
mpl
Human being with feelings
 
mpl's Avatar
 
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 2,196
Default

Is it possible to port/simulate "Save file window" like a GetUserFileNameForRead() with this?
__________________
SoundCloud | MPL Scripts discussion | ReaPack | Donate
mpl is offline   Reply With Quote
Old 10-28-2018, 03:53 AM   #82
amagalma
Human being with feelings
 
Join Date: Apr 2011
Posts: 1,324
Default

-- Could a MOD make this thread sticky please? --
amagalma is offline   Reply With Quote
Old 10-28-2018, 07:52 AM   #83
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 2,189
Default

Quote:
Originally Posted by Sexan View Post
ah,shame..... Just one more question, when drawing rectangle dynamically it does not refresh if you resize (to lower number) until the mouse is released.View is updated only if the rectangle has expanded,but not if its shrinked. Is this my error somewhere?
Could you post the code, so that we can try to check it?

To shrink or remove previously drawn GDI elements, either REAPER must redraw the underlying window, or if the window is static, you need to draw over your own GDI elements, using the original window content. The original window content can be stored in bitmap 1, combined with the rectangles in bitmap 2, and then blitted to the screen.

To see how SWS coded their marquee "Zoom tool", check out https://github.com/reaper-oss/sws/bl...Zoom.cpp#L1002.


Quote:
Originally Posted by amagalma View Post
-- Could a MOD make this thread sticky please? --
Done.


Quote:
Originally Posted by mpl View Post
Is it possible to port/simulate "Save file window" like a GetUserFileNameForRead() with this?
I do not quite understand - could you explain a bit more?
juliansader is online now   Reply With Quote
Old 10-28-2018, 08:02 AM   #84
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 7,450
Default

Quote:
Originally Posted by juliansader View Post
I do not quite understand - could you explain a bit more?
He wants to be able to open a file save dialog, which is not part of the Reaper provided ReaScript API. (GetUserFileNameForRead is only for a dialog to open files for reading, so it is not suitable for use with saving/writing new files.)
__________________
For info on SWS Reaper extension plugin (including Xenakios' previous extension/actions) :
http://www.sws-extension.org/
https://github.com/Jeff0S/sws
--
Xenakios blog (about HourGlass, Paul(X)Stretch and λ) :
http://xenakios.wordpress.com/
Xenakios is online now   Reply With Quote
Old 10-28-2018, 08:50 AM   #85
Sexan
Human being with feelings
 
Sexan's Avatar
 
Join Date: Jun 2009
Location: Croatia
Posts: 2,052
Default

Quote:
Originally Posted by juliansader View Post
Could you post the code, so that we can try to check it?

To shrink or remove previously drawn GDI elements, either REAPER must redraw the underlying window, or if the window is static, you need to draw over your own GDI elements, using the original window content. The original window content can be stored in bitmap 1, combined with the rectangles in bitmap 2, and then blitted to the screen.
Sure
https://stash.reaper.fm/34717/Area51.lua

Try dragging around, final rectangle shape only gets updated when mouse is released.Drawing is unrelated to mouse clicks it only waits to get first coordinate from first mouse down the rest is self updating. Thats why I don't get why everything is fine when mouse is released

Last edited by Sexan; 10-28-2018 at 09:01 AM.
Sexan is offline   Reply With Quote
Old 10-28-2018, 10:21 AM   #86
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 2,189
Default

Quote:
Originally Posted by Xenakios View Post
He wants to be able to open a file save dialog, which is not part of the Reaper provided ReaScript API. (GetUserFileNameForRead is only for a dialog to open files for reading, so it is not suitable for use with saving/writing new files.)
I will try to include such a function in the next update.
juliansader is online now   Reply With Quote
Old 10-29-2018, 06:01 AM   #87
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 5,210
Default

@juliansader


Quote:
(GetUserFileNameForRead is only for a dialog to open files for reading, so it is not suitable for use with saving/writing new files.)
Actually you can use it for file saving, you just need to select the file on which you want to save thing. The only confusing thing is that the label window is "Open" rather than "Save". The request is still valid then.



But, a multifile version of the Open function would be nice (we currently can only select one file with it)
and a Select Folder would also be very welcome !


Thx for taking a look
X-Raym is offline   Reply With Quote
Old 10-30-2018, 06:20 AM   #88
nofish
Human being with feelings
 
nofish's Avatar
 
Join Date: Oct 2007
Location: home is where the heart is
Posts: 8,230
Default

A question that came up (for me) here:

E.g. JS_MIDIEditor_ArrayAll() is listed in the API doc to take a reaper.array as argument, but reaper.arrays are only available in Lua (afaik), so does this work for the other scripting languages too?
nofish is online now   Reply With Quote
Old 10-31-2018, 07:01 AM   #89
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 2,189
Default

Quote:
Originally Posted by juliansader View Post
Quote:
Originally Posted by Sexan View Post
Just one more question, when drawing rectangle dynamically it does not refresh if you resize (to lower number) until the mouse is released.View is updated only if the rectangle has expanded,but not if its shrinked. Is this my error somewhere?

Thank you very much for this magical APIs
To shrink or remove previously drawn GDI elements, either REAPER must redraw the underlying window, or if the window is static, you need to draw over your own GDI elements, using the original window content. The original window content can be stored in bitmap 1, combined with the rectangles in bitmap 2, and then blitted to the screen.
Shrinking seems to work fine if I make these changes:

* I use ASbmp to store the underlying window content. This must be updated whenever the window changes and REAPER redraws the window (and removes the script's rectangles). IIRC, SWS checks GetScrollInfo for changes.
Code:
reaper.JS_GDI_Blit(ASbmpDC, 0, 0, track_window_dc, 0, 0, 5000, 5000)
* Add another combineBmp in which the window content will be combined with the script rectangles in each cycle (so that the original content of ASbmp is not overwritten):
Code:
if as_track then
    reaper.JS_LICE_Blit(combineBmp, 0, 0, ASbmp, 0, 0, 5000, 5000, 1, "COPY")
    reaper.JS_LICE_FillRect(combineBmp, X_start, Y_start, W, H, 0xFF0000, 0.5, "COPY")
    reaper.JS_GDI_Blit(track_window_dc, 0, 0, combineBmpDC, 0, 0, 5000, 5000 )
end

Result:

Last edited by juliansader; 10-31-2018 at 07:12 AM.
juliansader is online now   Reply With Quote
Old 10-31-2018, 07:04 AM   #90
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 2,189
Default

Quote:
Originally Posted by nofish View Post
A question that came up (for me) here:

E.g. JS_MIDIEditor_ArrayAll() is listed in the API doc to take a reaper.array as argument, but reaper.arrays are only available in Lua (afaik), so does this work for the other scripting languages too?
All the "Array" functions have "List" equivalents, which save the information in strings rather than reaper.arrays.

I'm not really familiar with EEL, but AFAIK reaper.arrays are simply 64bit double arrays, except for the first 64bits which give the max allocated size and currently used size as two 32bit ints, so any language that can read/write such constructs, should be able to use reaper.array functions.

Last edited by juliansader; 10-31-2018 at 07:10 AM.
juliansader is online now   Reply With Quote
Old 10-31-2018, 07:39 AM   #91
Sexan
Human being with feelings
 
Sexan's Avatar
 
Join Date: Jun 2009
Location: Croatia
Posts: 2,052
Default

Cool!

Last edited by Sexan; 10-31-2018 at 09:16 AM.
Sexan is offline   Reply With Quote
Old 10-31-2018, 09:03 AM   #92
nofish
Human being with feelings
 
nofish's Avatar
 
Join Date: Oct 2007
Location: home is where the heart is
Posts: 8,230
Default

Quote:
Originally Posted by juliansader View Post
All the "Array" functions have "List" equivalents, which save the information in strings rather than reaper.arrays.

I'm not really familiar with EEL, but AFAIK reaper.arrays are simply 64bit double arrays, except for the first 64bits which give the max allocated size and currently used size as two 32bit ints, so any language that can read/write such constructs, should be able to use reaper.array functions.
Thanks.
As I'm doing something similar currently (linked above) one more question if you don't mind..
Is it correct that say EEL scripters are then required to provide arrays to these functions strictly in the reaper.array format (i.e. as you said first 64bits which give the max allocated size and currently used size as two 32bit ints) as otherwise determing the array size would fail, no?
nofish is online now   Reply With Quote
Old 10-31-2018, 10:02 AM   #93
Sexan
Human being with feelings
 
Sexan's Avatar
 
Join Date: Jun 2009
Location: Croatia
Posts: 2,052
Default

Ok something is not right...empty project took 3gb of ram ??


Single project,nothing opened except this script
Sexan is offline   Reply With Quote
Old 10-31-2018, 10:28 AM   #94
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 2,189
Default

When the script exits, you should destroy/delete bitmaps (and other LICE and GDI objects), otherwise they remain in memory:
JS_LICE_DestroyBitmap(ASbmp) etc.

Last edited by juliansader; 10-31-2018 at 10:37 AM.
juliansader is online now   Reply With Quote
Old 10-31-2018, 02:47 PM   #95
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 2,189
Default

Quote:
Originally Posted by nofish View Post
Is it correct that say EEL scripters are then required to provide arrays to these functions strictly in the reaper.array format (i.e. as you said first 64bits which give the max allocated size and currently used size as two 32bit ints) as otherwise determing the array size would fail, no?
Correct. (I should probably add a sanity check to those functions.)

Last edited by juliansader; 10-31-2018 at 10:42 PM.
juliansader is online now   Reply With Quote
Old 11-02-2018, 10:22 AM   #96
mespotine
Human being with feelings
 
mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig, Germany
Posts: 570
Default

How do reaper.arrays work internally? Maybe it's possible to reimplement this to make these functions useable in Python and Eel as well.

And one other thing: Reaper and SWS have some kind of a definition-file, so Python can use the SWS-functions as well:

reaper_python.py and sws_python.py.

Is there something like that also available for your plugin?

And to all others in here: does anyone know, how these files work in detail? I might attempt an automatic generator for this file, but have too little knowledge on Python...
__________________
Reaper Fun Fact of the week: Font in the IDE is too small?
Change Config-variable edit_fontsize or the reaper.ini entry [REAPER]->edit_fontsize to the fontsize you need.
mespotine is offline   Reply With Quote
Old 11-02-2018, 10:51 AM   #97
nofish
Human being with feelings
 
nofish's Avatar
 
Join Date: Oct 2007
Location: home is where the heart is
Posts: 8,230
Default

The sws_python.py file is generated automatically when building SWS using these Perl scripts.:

https://github.com/reaper-oss/sws/bl...ript_python.pl

https://github.com/reaper-oss/sws/bl...ript_helper.pl
nofish is online now   Reply With Quote
Old 11-02-2018, 12:54 PM   #98
mespotine
Human being with feelings
 
mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig, Germany
Posts: 570
Default

Yes, but is it a file with some Python-code or something Reaper-specific?
And is it documented somewhere?
__________________
Reaper Fun Fact of the week: Font in the IDE is too small?
Change Config-variable edit_fontsize or the reaper.ini entry [REAPER]->edit_fontsize to the fontsize you need.
mespotine is offline   Reply With Quote
Old 11-02-2018, 03:04 PM   #99
nofish
Human being with feelings
 
nofish's Avatar
 
Join Date: Oct 2007
Location: home is where the heart is
Posts: 8,230
Default

You can open it with a text editor. It wraps the SWS ReaScript functions for Python.

https://github.com/reaper-oss/sws/wi...-to-ReaScripts
nofish is online now   Reply With Quote
Old 11-03-2018, 04:30 AM   #100
doppelganger
Human being with feelings
 
Join Date: Feb 2017
Posts: 282
Default

just want to say to all, be careful with Window_Destroy,
i accidentally removed right part of REAPER's IDE window, what was my surprise, when restart of computer didn't help

Tweaking of "reascriptedit" section in REAPER.ini helped me to restore showing data in that window.
doppelganger is offline   Reply With Quote
Old 11-03-2018, 05:27 AM   #101
Sexan
Human being with feelings
 
Sexan's Avatar
 
Join Date: Jun 2009
Location: Croatia
Posts: 2,052
Default

Code:
cur_view = reaper.JS_Window_FromPoint(reaper.GetMousePosition())

 retval, passedThrough, time, wParamLow, wParamHigh, lParamLow, lParamHigh = reaper.JS_WindowMessage_Peek( cur_view, "WM_LBUTTONDOWN" )
Why is this not returning anything? I'm interested in keyboard events (from types) but since it did not worked, tried ones that "worked" on first page examples and it still does not return any value
Sexan is offline   Reply With Quote
Old 11-03-2018, 07:05 AM   #102
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 2,189
Default

Before you can peek at a window message, you must first begin intercepting it, e.g.:
Code:
reaper.JS_WindowMessage_Intercept(cur_view,"WM_LBUTTONDOWN", true)
If no message of type "WM_LBUTTONDOWN" has been intercepted yet, the return time and params will be 0.
juliansader is online now   Reply With Quote
Old 11-03-2018, 07:31 AM   #103
Sexan
Human being with feelings
 
Sexan's Avatar
 
Join Date: Jun 2009
Location: Croatia
Posts: 2,052
Default

thank you
Sexan is offline   Reply With Quote
Old 11-09-2018, 09:38 AM   #104
Sexan
Human being with feelings
 
Sexan's Avatar
 
Join Date: Jun 2009
Location: Croatia
Posts: 2,052
Default

not sure if bug,limitation or I need a hack for my hack... When using "reaper.JS_Mouse_GetState" to trigger gfx.menu anywhere on the screen mouse state gets stuck on the point when gfx.menu is triggered until the mouse is pressed again:

Menu is triggered when right click is pressed (along with some modifier shift-crtl etc). As you see when menu is closed and mouse is pressed again (left click) it still thinks that right click is down.

Also tried with intercepting and WM_RBUTTONDOWN/UP to assure up state is reset but still experiencing same issue
Any solutions to this?

Edit: It looks like its only a problem when shift is involved

Last edited by Sexan; 11-09-2018 at 01:03 PM.
Sexan is offline   Reply With Quote
Old 11-12-2018, 01:40 AM   #105
Sexan
Human being with feelings
 
Sexan's Avatar
 
Join Date: Jun 2009
Location: Croatia
Posts: 2,052
Default

is there a reason why intercept and peek does not get all keys/characters (WM_KEYDOWN/UP)? It gets only few characters a,o,q...

Last edited by Sexan; 11-12-2018 at 02:05 AM.
Sexan is offline   Reply With Quote
Old 11-16-2018, 02:08 PM   #106
nappies
Human being with feelings
 
nappies's Avatar
 
Join Date: Dec 2017
Posts: 48
Default

juliansader, It seems that while these functions do not work?

JS_Window_GetScrollInfo - Just get zeros

JS_Window_RemoveXPStyle

nappies is offline   Reply With Quote
Old 11-16-2018, 02:43 PM   #107
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 2,189
Default

Quote:
Originally Posted by Sexan View Post
is there a reason why intercept and peek does not get all keys/characters (WM_KEYDOWN/UP)? It gets only few characters a,o,q...
Unfortunately I don't know how REAPER handles keystroke events. Mouse events are passed to the foreground window's "message queue" (where they can be intercepted), but keyboard shortcuts appear not to be.

In Windows, it should probably be possible to intercept or "hook" keyboard events at a lower level, but I don't know how to do this on other platforms. (cfillion/Xenakios/nofish/etc may know of better ways to do this.)
juliansader is online now   Reply With Quote
Old 11-16-2018, 03:10 PM   #108
Sexan
Human being with feelings
 
Sexan's Avatar
 
Join Date: Jun 2009
Location: Croatia
Posts: 2,052
Default

well I found that it will only intercept keys that are not assigned to any action,thats why I get only few. If you remove them from shortcuts they get intercepted

Last edited by Sexan; 11-17-2018 at 01:27 AM.
Sexan is offline   Reply With Quote
Old 11-16-2018, 03:32 PM   #109
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 2,189
Default

Quote:
Originally Posted by nappies View Post
juliansader, It seems that while these functions do not work?

JS_Window_GetScrollInfo - Just get zeros
Which window's scrollinfo are you trying to get?
juliansader is online now   Reply With Quote
Old 11-16-2018, 03:47 PM   #110
nappies
Human being with feelings
 
nappies's Avatar
 
Join Date: Dec 2017
Posts: 48
Default

Quote:
Originally Posted by juliansader View Post
Which window's scrollinfo are you trying to get?
Thanks for reply!

I tried Main Reaper window, Midi Editor, Actions and get zeros
Hope I do something wrong) JS_Window_GetClientRect works fine!

nappies is offline   Reply With Quote
Old 11-16-2018, 04:29 PM   #111
Xenakios
Human being with feelings
 
Xenakios's Avatar
 
Join Date: Feb 2007
Location: Oulu, Finland
Posts: 7,450
Default

Quote:
Originally Posted by juliansader View Post
In Windows, it should probably be possible to intercept or "hook" keyboard events at a lower level, but I don't know how to do this on other platforms. (cfillion/Xenakios/nofish/etc may know of better ways to do this.)
It's possible to do but it's been a while since I've last looked into it. (It doesn't even need an OS level hook, Reaper has a way to peek and steal keyboard events before they get into the Reaper shortcuts etc...)
__________________
For info on SWS Reaper extension plugin (including Xenakios' previous extension/actions) :
http://www.sws-extension.org/
https://github.com/Jeff0S/sws
--
Xenakios blog (about HourGlass, Paul(X)Stretch and λ) :
http://xenakios.wordpress.com/

Last edited by Xenakios; 11-16-2018 at 04:43 PM.
Xenakios is online now   Reply With Quote
Old 11-16-2018, 05:04 PM   #112
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 2,189
Default

Quote:
Originally Posted by nappies View Post
Thanks for reply!

I tried Main Reaper window, Midi Editor, Actions and get zeros
Hope I do something wrong) JS_Window_GetClientRect works fine!
The window argument for GetScrollInfo must be the window that actually contains the scrollbars -- typically some child window. In the case of the MIDI editor, for example, it will be the "midiview" child window, not the MIDI editor parent window.
juliansader is online now   Reply With Quote
Old 11-16-2018, 05:12 PM   #113
nappies
Human being with feelings
 
nappies's Avatar
 
Join Date: Dec 2017
Posts: 48
Default

Quote:
Originally Posted by juliansader View Post
The window argument for GetScrollInfo must be the window that actually contains the scrollbars -- typically some child window. In the case of the MIDI editor, for example, it will be the "midiview" child window, not the MIDI editor parent window.
Thanks a lot for explanation you are amazing!
nappies is offline   Reply With Quote
Old 11-28-2018, 01:09 AM   #114
Aleksandr_Oleynik
Human being with feelings
 
Join Date: Jan 2013
Location: Kiev, Ukraine
Posts: 61
Default

Quote:
Originally Posted by juliansader View Post
I have uploaded a new extension that may be of interest to other scripters: "js_ReaScriptAPI".
Hello juliansader!

Could you, please, add to your "js_ReaScriptAPI" a function to receive and send OSC-messages (OSC Client and Server)?
I use Reaper and LUA for creating live setups and I really need a function to hear outgoing OSC-commands with LUA-script (with specific port and IP and send OSC-messages to a specific port and IP).

The Reaper itself supports OSC, but today there’s no way to send OSC from script and to receive OSC to a script.

I would be very thankful for this help. And ready to pay for your time in any reasonable amount.

Best regards,
Aleksandr
Aleksandr_Oleynik is offline   Reply With Quote
Old 12-02-2018, 04:08 AM   #115
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 2,189
Default

I have uploaded v0.96 of the extension to its repository. [EDIT: Now v0.961.]

The reason why this update was somewhat delayed, is that I was trying to figure out how to return long strings (for example, if dozens of files are selected in an Open File dialog) and strings that contain \0 characters (for example, packed Lua strings). Fortunately, Justin noticed my threads, and the upcoming version of REAPER will allow API functions to return such strings. The extension will therefore require an up-to-date version of REAPER.

The update is not yet available via ReaPack, but in the meantime if anyone is interested in testing the new functions, it can be downloaded and installed manually. It requires one of the recent dev versions of REAPER.

New functions:

* FindChildByID: (Thanks to amagalma for reminding me about this.) IDs seem to be a more reliable cross-platform way of getting child windows (such as the arrange view within the main window, or the piano roll within an MIDI editor), than searching by title ("trackview" or "midiview") or by Z order.

* Localize: If searching for standard windows such as "Actions" or "Navigator" by window title, localized (translated) titles should be used.

* Several ListView functions: Useful for finding selected items in any list window, such as the FX chain.

* Open files, save file and select folder dialogs.

Changed functions:

* All the "List" functions that previously stored long strings in ExtStates. These functions now return the long strings directly.

Last edited by juliansader; 12-03-2018 at 02:51 AM.
juliansader is online now   Reply With Quote
Old 12-02-2018, 04:29 AM   #116
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 5,210
Default

Quote:
* Open files, save file and select folder dialogs.
Finally !!!


Thx !
X-Raym is offline   Reply With Quote
Old 12-02-2018, 04:59 PM   #117
lb0
Human being with feelings
 
Join Date: Apr 2014
Posts: 2,741
Default

Great stuff! Thanks for all your hard work!

Would the listview functions be any good for getting the command id of the selected item in the action list?
__________________
Projects - Reascripts - Lua:
LBX Stripper | LBX Chaos Engine | LBX Floating FX Positioner | LBX SRD Smart Knobs
Donate via Paypal
lb0 is offline   Reply With Quote
Old 12-03-2018, 02:58 AM   #118
juliansader
Human being with feelings
 
Join Date: Jul 2009
Posts: 2,189
Default

Quote:
Originally Posted by lb0 View Post
Would the listview functions be any good for getting the command id of the selected item in the action list?
I have uploaded a quick update v0.961, and now you can: if the commandID is visible in the Actions list, you can get it as subitem 3:
Code:
commandID = reaper.JS_ListView_GetItemText(window, index, 3)
juliansader is online now   Reply With Quote
Old 12-03-2018, 03:06 AM   #119
lb0
Human being with feelings
 
Join Date: Apr 2014
Posts: 2,741
Default

Quote:
Originally Posted by juliansader View Post
I have uploaded a quick update v0.961, and now you can: if the commandID is visible in the Actions list, you can get it as subitem 3:
Code:
commandID = reaper.JS_ListView_GetItemText(window, index, 3)
Fantastic - thank you!

EDIT: Tested it out - absolutely perfect - so much neater than having to manually copy and paste the command id into my scripts. Also being able to grab the action description is really great too! No more cryptic command id's for descriptions!
__________________
Projects - Reascripts - Lua:
LBX Stripper | LBX Chaos Engine | LBX Floating FX Positioner | LBX SRD Smart Knobs
Donate via Paypal

Last edited by lb0; 12-03-2018 at 03:56 AM.
lb0 is offline   Reply With Quote
Old 12-03-2018, 12:07 PM   #120
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: USA
Posts: 757
Default

Quote:
Originally Posted by juliansader View Post
I have uploaded a quick update v0.961,
Nice updates!
Edgemeal is offline   Reply With Quote
Reply

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

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

Forum Jump


All times are GMT -7. The time now is 09:23 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2018, vBulletin Solutions Inc.