View Full Version : Progress: CIU Designer
Carldric Clement
17-05-2022, 08:44
Previous here https://fileforums.com/showpost.php?p=481045&postcount=167
This is might take longer to finish. I lost the project before cause my laptop was stolen. Don't worry it would post updates here as well as I can. Coming soon.
@Carldric Clement, very good!
This will be very helpful!
If you need any information about Setup.ini keys or images in CIU send me PM.
Soon I'll share a new source code with some new features like 3 slider for volume control for songs/videos, so if you need the source code in advance to be able to work on it, just ask me.
Thank you!
Carldric Clement
17-05-2022, 22:04
Moving Image with following Left & Top
Carldric Clement
27-05-2022, 08:20
1st Issue: Music Button was not the same as the Autorun installer. I will try to figure it out later.
@Carldric Clement, in CIU the "MusicIcon" button when positioned over the "MusicButton" button (RectInRect) is set to disabled, so the actions of the "MusicButton" button change the state of "MusicIcon", but it behaves only visually (no Click or OnMouse actions ).
The same goes for MusicIconAR (together with MusicARButton) and also for MusicIconSI (together with SmallMusicButton).
- "MusicIconAR", "MusicIcon" and "MusicIconSI" is a normal Botva2 pot with 4 images (idle, selected, clicked, disabled) arranged vertically in an image (in the CIU theme example, only the disabled icon was created because it does not use the other images).
- "MusicButtonAR", "MusicButton" and "SmallMusicButton" is a CstmButtom by Yener90 with 4 images separately.
P.S: You can see the code at the end of the ButtonsTextures procedure in the CIU script.
BtnGetPosition(hMusicAR, Rt.Left, Rt.Top, Rt.Bottom, Rt.Right);
Rt.Bottom := Rt.Top + Rt.Bottom;
Rt.Right:= Rt.Left + Rt.Right;
if BtnY(MusicARBtn, CstmBtnInt) then
BtnSetEnabled(hMusicAR, not RectInRect(Rt, BoundsToRect(CstmBtn[CstmBtnInt].AreaX, CstmBtn[CstmBtnInt].AreaY, CstmBtn[CstmBtnInt].AreaW, CstmBtn[CstmBtnInt].AreaH)));
BtnGetPosition(hMusic, Rt.Left, Rt.Top, Rt.Bottom, Rt.Right);
Rt.Bottom := Rt.Top + Rt.Bottom;
Rt.Right:= Rt.Left + Rt.Right;
if BtnY(MusicBtn, CstmBtnInt) then
BtnSetEnabled(hMusic, not RectInRect(Rt, BoundsToRect(CstmBtn[CstmBtnInt].AreaX, CstmBtn[CstmBtnInt].AreaY, CstmBtn[CstmBtnInt].AreaW, CstmBtn[CstmBtnInt].AreaH)));
BtnGetPosition(hMusicSI, Rt.Left, Rt.Top, Rt.Bottom, Rt.Right);
Rt.Bottom := Rt.Top + Rt.Bottom;
Rt.Right:= Rt.Left + Rt.Right;
if BtnY(MusicSmallBtn, CstmBtnInt) then
BtnSetEnabled(hMusicSI, not RectInRect(Rt, BoundsToRect(CstmBtn[CstmBtnInt].AreaX, CstmBtn[CstmBtnInt].AreaY, CstmBtn[CstmBtnInt].AreaW, CstmBtn[CstmBtnInt].AreaH)));
BtnGetPosition(hPauseSI, Rt.Left, Rt.Top, Rt.Bottom, Rt.Right);
Rt.Bottom := Rt.Top + Rt.Bottom;
Rt.Right:= Rt.Left + Rt.Right;
if BtnY(PauseSmallBtn, CstmBtnInt) then
BtnSetEnabled(hPauseSI, not RectInRect(Rt, BoundsToRect(CstmBtn[CstmBtnInt].AreaX, CstmBtn[CstmBtnInt].AreaY, CstmBtn[CstmBtnInt].AreaW, CstmBtn[CstmBtnInt].AreaH)));
end;
I don't want to be intrusive in your work, I just want to try to help you understand some things that are not so visible in CIU's behavior.
Carldric Clement
28-05-2022, 00:21
@Carldric Clement, in CIU the "MusicIcon" button when positioned over the "MusicButton" button (RectInRect) is set to disabled, so the actions of the "MusicButton" button change the state of "MusicIcon", but it behaves only visually (no Click or OnMouse actions ).
The same goes for MusicIconAR (together with MusicARButton) and also for MusicIconSI (together with SmallMusicButton).
- "MusicIconAR", "MusicIcon" and "MusicIconSI" is a normal Botva2 pot with 4 images (idle, selected, clicked, disabled) arranged vertically in an image (in the CIU theme example, only the disabled icon was created because it does not use the other images).
- "MusicButtonAR", "MusicButton" and "SmallMusicButton" is a CstmButtom by Yener90 with 4 images separately.
P.S: You can see the code at the end of the ButtonsTextures procedure in the CIU script.
BtnGetPosition(hMusicAR, Rt.Left, Rt.Top, Rt.Bottom, Rt.Right);
Rt.Bottom := Rt.Top + Rt.Bottom;
Rt.Right:= Rt.Left + Rt.Right;
if BtnY(MusicARBtn, CstmBtnInt) then
BtnSetEnabled(hMusicAR, not RectInRect(Rt, BoundsToRect(CstmBtn[CstmBtnInt].AreaX, CstmBtn[CstmBtnInt].AreaY, CstmBtn[CstmBtnInt].AreaW, CstmBtn[CstmBtnInt].AreaH)));
BtnGetPosition(hMusic, Rt.Left, Rt.Top, Rt.Bottom, Rt.Right);
Rt.Bottom := Rt.Top + Rt.Bottom;
Rt.Right:= Rt.Left + Rt.Right;
if BtnY(MusicBtn, CstmBtnInt) then
BtnSetEnabled(hMusic, not RectInRect(Rt, BoundsToRect(CstmBtn[CstmBtnInt].AreaX, CstmBtn[CstmBtnInt].AreaY, CstmBtn[CstmBtnInt].AreaW, CstmBtn[CstmBtnInt].AreaH)));
BtnGetPosition(hMusicSI, Rt.Left, Rt.Top, Rt.Bottom, Rt.Right);
Rt.Bottom := Rt.Top + Rt.Bottom;
Rt.Right:= Rt.Left + Rt.Right;
if BtnY(MusicSmallBtn, CstmBtnInt) then
BtnSetEnabled(hMusicSI, not RectInRect(Rt, BoundsToRect(CstmBtn[CstmBtnInt].AreaX, CstmBtn[CstmBtnInt].AreaY, CstmBtn[CstmBtnInt].AreaW, CstmBtn[CstmBtnInt].AreaH)));
BtnGetPosition(hPauseSI, Rt.Left, Rt.Top, Rt.Bottom, Rt.Right);
Rt.Bottom := Rt.Top + Rt.Bottom;
Rt.Right:= Rt.Left + Rt.Right;
if BtnY(PauseSmallBtn, CstmBtnInt) then
BtnSetEnabled(hPauseSI, not RectInRect(Rt, BoundsToRect(CstmBtn[CstmBtnInt].AreaX, CstmBtn[CstmBtnInt].AreaY, CstmBtn[CstmBtnInt].AreaW, CstmBtn[CstmBtnInt].AreaH)));
end;
I didn't expect that code before. they just joined with some other point-like
(Bottom = Top + Bottom) and (Right = Left + Right).
I'm gonna try to do with these code on Designer.
I think I put it inverted (Rt.Bottom and Rt.Right) in BtnGetPosition. lol
I just realized this now, I'll fix it here.
BtnGetPosition(hMusicAR, Rt.Left, Rt.Top, Rt.Right, Rt.Bottom);
BtnGetPosition(hMusicSI, Rt.Left, Rt.Top, Rt.Right, Rt.Bottom);
BtnGetPosition(hPauseSI, Rt.Left, Rt.Top, Rt.Right, Rt.Bottom);
As the CIU CloseButton had the same Width and Height dimensions it worked, but it was wrong.
Carldric Clement
29-05-2022, 08:14
In case you guys need this app, well you got more bugs. Feel free to use it until it's finished the project.
Progress: 22.1%.
EDIT: It might be a slow update when the code is not easy to create. DM me for a source if you would need my help.
Carldric Clement
29-05-2022, 10:28
I think I put it inverted (Rt.Bottom and Rt.Right) in BtnGetPosition. lol
I just realized this now, I'll fix it here.
BtnGetPosition(hMusicAR, Rt.Left, Rt.Top, Rt.Right, Rt.Bottom);
BtnGetPosition(hMusicSI, Rt.Left, Rt.Top, Rt.Right, Rt.Bottom);
BtnGetPosition(hPauseSI, Rt.Left, Rt.Top, Rt.Right, Rt.Bottom);
As the CIU CloseButton had the same Width and Height dimensions it worked, but it was wrong.
It's ok as long as you need to correction code.
Carldric Clement
07-07-2022, 07:08
It might take slow to make this software. :)
It might take slow to make this software. :)
Yes, we are aware that developing a designer for CIU is hard and time consuming work.
The CIU has a lot of features and settings (some rarely used, but useful in some cases).
But we hope you don't give up on the project, because a designer for the CIU will be welcome, but as long as it's just a designer to load the configs from the "Setup.ini" file and the "Setup" folder (That doesn't become a parallel project, keeping users free to read/search or change the script).
P.S: Two new images have been added for each trackbar (TrackBarImg.png, TrackBarDImg.png) (D = Disabled state image).
So thank you very much for continuing, and don't give up.
Also added a new Stretch= key in the trackbar sections to work with this image (as is done in the progressbar).
Attached is the list of files supported by CIU.
In the attached list the characters:
"*" = 1,2,3, etc (indefinitely as long as it exists)
"|" = <LANG> = All 36 languages supported by CIU.
"+" = (Check mask "*" like: Video*.+ = Video1.*, Video2.*, etc)
So thank you very much for continuing, and don't give up.
Carldric Clement
08-07-2022, 10:38
the preview software was update here (https://fileforums.com/showpost.php?p=497039&postcount=10).
I really like the way the buttons are shaped to fit the corners, very nice and such a good idea for some designs.
Razor12911
30-07-2022, 05:02
I am not sure how far you have gone with development however there are some information that could be helpful which I'd like to share as I've created a similar project for installer creator once before.
Colors used by FireMonkey framework are reversed compared to VCL (what Inno uses) so the function RGBtoBGR will be useful to you when you decide to add color picker.
The font sizes are different as well because the DPI used in VCL (72 dpi) is different from FMX (96 dpi) whatever font values used during design mode should be multiplied by the factor 72/96 and by 96/72 when going from inno to fmx.
In order to make the code for paging through the wizard simple (welcome, system, install), introduce TTabControl and make tabs for each one of these pages and to make the tabcontrol itself transparent, you'll need to set its StyleLookup property to "transparentedit", this applies to everything that you want to make transparent in FMX, just set the StyleLookup value to this vale.
To get a list of fonts supported by Fmx you should use Printer from FMX.Printers.Win
var
Printer: TPrinterWin;
begin
Printer := TPrinterWin.Create;
ComboBox1.BeginUpdate;
try
ComboBox1.Items.AddStrings(Printer.Fonts);
finally
ComboBox1.EndUpdate;
end;
Printer.Free;
It's wise to introduce class objects for things such as buttons because not only does this mean you'll write less code but this way you can consolidate any bugs/issues encountered with one simple fix.
Something like this:
type
TDesignButton = class(TSelection)
private
FRectangle: TRectangle;
FLabel: TLabel;
procedure MyMouseEnter(Sender: TObject);
procedure MyMouseLeave(Sender: TObject);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure SetText(AText: String);
procedure SetFont(AName: String; ASize: Single; AColor: TAlphaColor);
procedure SetFontStyle(ABold, AItalic: Boolean);
procedure SetAlignment(AHorzAlign, AVertAlign: TTextAlign;
AOffsetX, AOffsetY: Single);
procedure SetImage(AFilename: String);
end;
constructor TDesignButton.Create(AOwner: TComponent);
begin
inherited Create(Owner);
Self.HideSelection := True;
Self.ShowHandles := False;
Self.OnMouseEnter := MyMouseEnter;
Self.OnMouseLeave := MyMouseLeave;
FRectangle := TRectangle.Create(Self);
FRectangle.Parent := Self;
FRectangle.Align := TAlignLayout.Client;
FRectangle.HitTest := False;
FRectangle.Fill.Bitmap.WrapMode := TWrapMode.TileStretch;
FRectangle.Stroke.Thickness := 0;
FLabel := TLabel.Create(FRectangle);
FLabel.Parent := FRectangle;
FLabel.Align := TAlignLayout.Client;
FLabel.HitTest := False;
FLabel.Text := '';
FLabel.StyledSettings := [];
end;
destructor TDesignButton.Destroy;
begin
inherited Destroy;
end;
procedure TDesignButton.MyMouseEnter(Sender: TObject);
begin
Self.HideSelection := False;
Self.ShowHandles := True;
end;
procedure TDesignButton.MyMouseLeave(Sender: TObject);
begin
Self.HideSelection := True;
Self.ShowHandles := False;
end;
procedure TDesignButton.SetText(AText: String);
begin
FLabel.Text := AText;
end;
procedure TDesignButton.SetFont(AName: String; ASize: Single;
AColor: TAlphaColor);
begin
FLabel.Font.Family := AName;
FLabel.Font.Size := ASize;
FLabel.FontColor := AColor;
end;
procedure TDesignButton.SetFontStyle(ABold, AItalic: Boolean);
begin
FLabel.Font.Style := [];
if ABold then
FLabel.Font.Style := FLabel.Font.Style + [TFontStyle.fsBold];
if AItalic then
FLabel.Font.Style := FLabel.Font.Style + [TFontStyle.fsItalic];
end;
procedure TDesignButton.SetAlignment(AHorzAlign, AVertAlign: TTextAlign;
AOffsetX, AOffsetY: Single);
begin
FLabel.TextAlign := AHorzAlign;
FLabel.VertTextAlign := AVertAlign;
FLabel.Margins.Left := AOffsetX;
FLabel.Margins.Right := -AOffsetX;
FLabel.Margins.Top := AOffsetY;
FLabel.Margins.Bottom := -AOffsetY;
end;
procedure TDesignButton.SetImage(AFilename: String);
begin
FRectangle.Fill.Kind := TBrushKind.Bitmap;
FRectangle.Fill.Bitmap.Bitmap.LoadFromFile(AFilena me);
end;
with its usage being:
var
BackButton, NextButton: TDesignButton;
procedure TForm2.FormShow(Sender: TObject);
begin
BackButton := TDesignButton.Create(Form2);
BackButton.Parent := Form2;
BackButton.SetBounds(20, 20, 100, 30);
BackButton.SetText('Back');
BackButton.SetFont('Agency FB', 14, claGreen);
BackButton.SetFontStyle(True, False);
BackButton.SetAlignment(TTextAlign.Center, TTextAlign.Center, -10, 0);
BackButton.SetImage('back.png');
NextButton := TDesignButton.Create(Form2);
NextButton.Parent := Form2;
NextButton.SetBounds(140, 20, 100, 30);
NextButton.SetText('Next');
NextButton.SetFont('Agency FB', 14, claDeepPink);
NextButton.SetFontStyle(True, False);
NextButton.SetAlignment(TTextAlign.Center, TTextAlign.Center, 10, 0);
NextButton.SetImage('Next.png');
end;
I have uploaded a compiled demo of what to expect as a result, but you can improve upon this by introducing Get* functions, eg. GetText, GetFontName, GetFontSize etc etc....
Thanks Razor for the information that might help.
A designer for the CIU has always been a complicated project, and often abandoned. I'm hoping that this time it can be completed, even if we have to wait a long time.
A suggestion of mine for the project is to include a "Reset Size" button or something like "Adjust To Image" so that when clicking the button display image or another component can be automatically resized to the real dimension of the png image.
Background images, LogoBG and some others cannot be resized, and those that can be resized by botva2 lose focus. So the design is better if it includes the dimensions of the components the same as the real image, but it should be allowed to freely adjust the dimensions so that the image file can be corrected later if necessary.
Carldric Clement
30-07-2022, 10:07
I am not sure how far you have gone with development however there are some information that could be helpful which I'd like to share as I've created a similar project for installer creator once before.
Colors used by FireMonkey framework are reversed compared to VCL (what Inno uses) so the function RGBtoBGR will be useful to you when you decide to add color picker.
The font sizes are different as well because the DPI used in VCL (72 dpi) is different from FMX (96 dpi) whatever font values used during design mode should be multiplied by the factor 72/96 and by 96/72 when going from inno to fmx.
In order to make the code for paging through the wizard simple (welcome, system, install), introduce TTabControl and make tabs for each one of these pages and to make the tabcontrol itself transparent, you'll need to set its StyleLookup property to "transparentedit", this applies to everything that you want to make transparent in FMX, just set the StyleLookup value to this vale.
To get a list of fonts supported by Fmx you should use Printer from FMX.Printers.Win
var
Printer: TPrinterWin;
begin
Printer := TPrinterWin.Create;
ComboBox1.BeginUpdate;
try
ComboBox1.Items.AddStrings(Printer.Fonts);
finally
ComboBox1.EndUpdate;
end;
Printer.Free;
It's wise to introduce class objects for things such as buttons because not only does this mean you'll write less code but this way you can consolidate any bugs/issues encountered with one simple fix.
Something like this:
type
TDesignButton = class(TSelection)
private
FRectangle: TRectangle;
FLabel: TLabel;
procedure MyMouseEnter(Sender: TObject);
procedure MyMouseLeave(Sender: TObject);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure SetText(AText: String);
procedure SetFont(AName: String; ASize: Single; AColor: TAlphaColor);
procedure SetFontStyle(ABold, AItalic: Boolean);
procedure SetAlignment(AHorzAlign, AVertAlign: TTextAlign;
AOffsetX, AOffsetY: Single);
procedure SetImage(AFilename: String);
end;
constructor TDesignButton.Create(AOwner: TComponent);
begin
inherited Create(Owner);
Self.HideSelection := True;
Self.ShowHandles := False;
Self.OnMouseEnter := MyMouseEnter;
Self.OnMouseLeave := MyMouseLeave;
FRectangle := TRectangle.Create(Self);
FRectangle.Parent := Self;
FRectangle.Align := TAlignLayout.Client;
FRectangle.HitTest := False;
FRectangle.Fill.Bitmap.WrapMode := TWrapMode.TileStretch;
FRectangle.Stroke.Thickness := 0;
FLabel := TLabel.Create(FRectangle);
FLabel.Parent := FRectangle;
FLabel.Align := TAlignLayout.Client;
FLabel.HitTest := False;
FLabel.Text := '';
FLabel.StyledSettings := [];
end;
destructor TDesignButton.Destroy;
begin
inherited Destroy;
end;
procedure TDesignButton.MyMouseEnter(Sender: TObject);
begin
Self.HideSelection := False;
Self.ShowHandles := True;
end;
procedure TDesignButton.MyMouseLeave(Sender: TObject);
begin
Self.HideSelection := True;
Self.ShowHandles := False;
end;
procedure TDesignButton.SetText(AText: String);
begin
FLabel.Text := AText;
end;
procedure TDesignButton.SetFont(AName: String; ASize: Single;
AColor: TAlphaColor);
begin
FLabel.Font.Family := AName;
FLabel.Font.Size := ASize;
FLabel.FontColor := AColor;
end;
procedure TDesignButton.SetFontStyle(ABold, AItalic: Boolean);
begin
FLabel.Font.Style := [];
if ABold then
FLabel.Font.Style := FLabel.Font.Style + [TFontStyle.fsBold];
if AItalic then
FLabel.Font.Style := FLabel.Font.Style + [TFontStyle.fsItalic];
end;
procedure TDesignButton.SetAlignment(AHorzAlign, AVertAlign: TTextAlign;
AOffsetX, AOffsetY: Single);
begin
FLabel.TextAlign := AHorzAlign;
FLabel.VertTextAlign := AVertAlign;
FLabel.Margins.Left := AOffsetX;
FLabel.Margins.Right := -AOffsetX;
FLabel.Margins.Top := AOffsetY;
FLabel.Margins.Bottom := -AOffsetY;
end;
procedure TDesignButton.SetImage(AFilename: String);
begin
FRectangle.Fill.Kind := TBrushKind.Bitmap;
FRectangle.Fill.Bitmap.Bitmap.LoadFromFile(AFilena me);
end;
with its usage being:
var
BackButton, NextButton: TDesignButton;
procedure TForm2.FormShow(Sender: TObject);
begin
BackButton := TDesignButton.Create(Form2);
BackButton.Parent := Form2;
BackButton.SetBounds(20, 20, 100, 30);
BackButton.SetText('Back');
BackButton.SetFont('Agency FB', 14, claGreen);
BackButton.SetFontStyle(True, False);
BackButton.SetAlignment(TTextAlign.Center, TTextAlign.Center, -10, 0);
BackButton.SetImage('back.png');
NextButton := TDesignButton.Create(Form2);
NextButton.Parent := Form2;
NextButton.SetBounds(140, 20, 100, 30);
NextButton.SetText('Next');
NextButton.SetFont('Agency FB', 14, claDeepPink);
NextButton.SetFontStyle(True, False);
NextButton.SetAlignment(TTextAlign.Center, TTextAlign.Center, 10, 0);
NextButton.SetImage('Next.png');
end;
I have uploaded a compiled demo of what to expect as a result, but you can improve upon this by introducing Get* functions, eg. GetText, GetFontName, GetFontSize etc etc....
Thanks for the information bro. Time to change a lot of code where I use the TImage from. :D
acal3000
30-07-2022, 12:02
Pretty Nice GUI Customized Installer
Carldric Clement
31-07-2022, 01:00
Gonna take a few changes to buttons from TImage to TDesignButton. Thanks again to Razor12911 who give some more details to make more progress button. Right now it's gonna be difficult to set the X, Y, Width, and Height from how to get the function from where I replace it.
Carldric Clement
31-07-2022, 06:13
I just upload some source files if you need my help with this solution. My brain got stuck for a moment. Link (https://github.com/CarldricGaming/CIU-Designer)
Also, I've just made a little progress to make work these buttons before. :)
Carldric Clement
17-09-2022, 07:30
Time to add some a few setup settings?
fabrieunko
26-12-2022, 10:29
Hello I hope the project is not dead?
Carldric Clement
26-12-2022, 22:57
Due to being a lot of busy for a few months, I've mostly forgotten that project is mostly dead... I'm back. Sorry for making you guys worried. :)
fabrieunko
27-12-2022, 08:53
ha the best news for the future year.. I follow you because the project interests me a lot. I don't know how to code. but didn't drop anything. I am starting to use ciu and your program will make my task much easier.
mausschieber
27-12-2022, 15:27
the main thing is that it continues
Carldric Clement
03-01-2023, 04:12
[InstallOptions] is complete. Only a few things to get finish the job.
Anyway, Here's the Update 3 (https://fileforums.com/showpost.php?p=497039&postcount=10) in case you would like to test the project. :)
At a glance only ApplicationName<LNG>= must not be correct snd functional.
ApplicationName<LNG>= there are 36 variations of the ApplicationName= key
Example: ApplicationNameAL=, ApplicationNameAR=, ApplicationNameBIA=, ApplicationNameCNS=, ApplicationNameCNT=, ApplicationNameCZ=, ApplicationNameDE=, etc
EDIT:
For the keys with boolean values (0/1), I particularly prefer a checkbox that is visually easier to understand. But either way it's good.
For the Lang= key it could be a checkbox group, one for each language and then when saving the INI it would form the key with the languages separated by a comma.
Hi @Carldric Clement...
Does the "CIU Designer" project continue?
Any updates for us?
Thanks!
Carldric Clement
04-05-2023, 07:06
I had to put the project on hold first. maybe this month I won't be able to continue for a while because there are many things that cannot be avoided from the busyness of problems that need to be taken care of for now. So maybe you want to ask about the project next month, I will continue.
Carldric Clement
08-06-2023, 07:15
VideoPlayerAR on Autorun incl. the animation of the source editor.
UPDATE (https://fileforums.com/showpost.php?p=497039&postcount=10) Preview is here again.
mausschieber
08-06-2023, 07:29
VideoPlayerAR on Autorun incl. the animation of the source editor.
UPDATE (https://fileforums.com/showpost.php?p=497039&postcount=10) Preview is here again.
nice to hear its going forward great thanks for this
Dev_0016
09-06-2023, 08:25
I really love this features and even more than better than perivous installer creater I not complaining. but your team and people is great and have keep it and God bless with you always.. One thing I have ask to when it complete please tell me that I waiting for it for long..
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.