Показать полную графическую версию : [Архив - Часть 1.3] AutoIt скрипты
amel27
возможные параметры
Спасибо. Я только не совсем понимаю какой из них мне нужен (склоняюсь к INTERNET_OPEN_TYPE_DIRECT, но не уверен), и как быть с InetGet()? может есть такая же самодельная функция с подобным выходом в сеть как и у _InetGetSource()?
Creat0Rсклоняюсь к INTERNET_OPEN_TYPE_DIRECTправильно склоняешься :)может есть такая же самодельная функция с подобным выходом в сеть как и у _InetGetSource()?готовой чего-то не видать.... а все штатные очевидно используют настройки профиля. Как временный вариант могу предложить сугубо админский подход - запускать скрипт из-под другого узера, у которого в профиле отключен прокси (через RunAsSet)
Creat0R
Уф, добил таки самопальный _FileSelectFolder, только есть два замечания:
1. Внимание! В параметре $root передается код папки (CSIDL (http://msdn2.microsoft.com/en-us/library/ms649274.aspx)), но ни в коем случае не путь к ней!
2. Функция не поддерживает параметр каталога по умолчанию ("initial dir")... хотя теоретически эту фичу можно реализовать через GUICtrlSendMsg (), т.к. окно выбора может принимать сообщения пред-селекта и установки текста статус-бараFunc _FileSelectFolder ($title, $root = 0, $flags = 0, $hwnd = 0)
Local $ret, $pidl, $res = ''
; Создание структур данных
Local $ubi = DllStructCreate ("hwnd;ptr;ptr;ptr;int;ptr;ptr;int") ; управляющая структура BROWSEINFO
Local $utl = DllStructCreate ("char[512],char") ; заголовок окна
Local $urs = DllStructCreate ("char[260]") ; буфер для возвращаемого пути (длиной MAX_PATH)
Local $ulf = BitOR (BitShift(BitAnd ($flags,1),-9), _ ; 1: не позволять создавать новые каталоги
BitShift(BitAnd ($flags,2),-5), _ ; 2: использовать новый стиль диалога
BitShift(BitAnd ($flags,4),-2)) ; 4: включить cтроку редактирования
; Заполнение структур данных
DllStructSetData ($utl, 1, $title)
DllStructSetData ($ubi, 1, $hwnd)
DllStructSetData ($ubi, 3, DllStructGetPtr($urs))
DllStructSetData ($ubi, 4, DllStructGetPtr($utl))
DllStructSetData ($ubi, 5, $ulf)
$ret = DllCall ("shell32.dll", "ptr", "SHGetSpecialFolderLocation", _
"int", 0 , _
"int", $root , _
"ptr", DllStructGetPtr($ubi, 2))
If $ret[0] Then Return $res
; Открытие окна выбора каталога
$pidl = DllCall ("shell32.dll", "ptr", "SHBrowseForFolder", "ptr", DllStructGetPtr ($ubi))
If $pidl[0] Then
$ret = DllCall ("shell32.dll", "int", "SHGetPathFromIDList", _
"ptr", $pidl[0], _
"ptr", DllStructGetPtr ($urs))
If $ret[0] Then $res = DllStructGetData ($urs, 1)
DllCall ("ole32.dll", "int", "CoTaskMemFree", "ptr", $pidl[0]) ; чистим за собой
EndIf
DllCall ("ole32.dll", "int", "CoTaskMemFree", "ptr", DllStructGetData ($ubi, 2))
Return $res ; Вывод результата
EndFunc
amel27
Обнови версию AutoIT - это новая фича, еще не устаканиласьДело оказалось не в версии, видимо, код неправильно скопировался (почему-то полностью отсутствовали символы *, | и \) :blush: Наверное, когда копировал код с форума, страница не до конца загрузилась...
Приношу свои извинения. :)
Mihal> Можно ли с помощью AutoIt проделать такую операцию?
Mihal> То есть "взять некий WAV-файл мышкой" и "кинуть его на окошко этой проги"
amel27> обычно перетаскивание можно заменить на копировать/вставить через буфер обмена...
в этой проге (yamaha'вская wscma) нет "вставить" к сожалению.
amel27
добил таки самопальный _FileSelectFolder
:yahoo: Огромное челевечное спасибо!!!
Функция не поддерживает параметр каталога по умолчанию ("initial dir")...
Жалко, один из самых важных параметров этой функции...
хотя теоретически эту фичу можно реализовать через GUICtrlSendMsg ()
Хм... я пробовал, но что то не получается :cry: , во-первых я не очень понимаю как её использовать в данном случае, а во-вторых на момент вызова самой функции (_FileSelectFolder) скрипт как бы останавливается, и послать что либо просто невозможно... может нужно в самой функции где то ставить посылание параметров, но я так и не понял где.
Но всё же ещё раз огромное спасибо за эту долгожданную функцию :)
P.S
На офф форуме кстати, тоже вроде с нетерпением её ожидают ;)
Creat0R
я не очень понимаю как её использовать в данном случае
Подобные фокусы обычно реализуются через CallBack-функции для окон, но к сожалению пока AutoIT позволяет их регистрировать только для лист-контролов (GUICtrlRegisterListViewSort). По сути требуется лишь узнать точку входа AutoIT-функции и передать этот указатель как параметр.... но пока ничего кроме создания "фиктивного" лист-контрола ничего не приходит в голову, а это имхо из разряда извращений :)
FYI: "по горячему" немного оптимизировал код
amel27
кроме создания "фиктивного" лист-контрола ничего не приходит в голову, а это имхо из разряда извращений
Это тот самый лист котроль над которым я извращался тут (http://forum.oszone.net/post-548797-694.html)? :biggrin: (пост номер 694).
Немного поизвращался в другом направлении, и сделал нужные для себя функции связанные с массивами, но подумал может кому то ещё пригодятся :shuffle: (комментов нет, но думаю запустив примеры всё довольно быстро станет ясно):
#include <Array.au3>
Dim $Arr1[4]
$Arr1[0] = UBound($Arr1) - 1
$Arr1[1] = "Hello"
$Arr1[2] = "My"
$Arr1[3] = "Friend!"
Dim $Arr2[4]
$Arr2[0] = UBound($Arr2) - 1
$Arr2[1] = "AutoIt"
$Arr2[2] = "Is"
$Arr2[3] = "The best!"
_ArrayDisplay($Arr1, "Display the first array")
_ArrayDisplay($Arr2, "Display the second array")
_ArrayJoin($Arr1, $Arr2, 1)
_ArrayDisplay($Arr1, "Demo of _ArrayJoin() function")
_ArrayClone($Arr1, 2)
_ArrayDisplay($Arr1, "Demo of _ArrayClone() function")
_ArrayDeleteClones($Arr1)
_ArrayDisplay($Arr1, "Demo of _ArrayDeleteClones() function")
_ArrayClear($Arr1)
_ArrayDisplay($Arr1, "Demo of _ArrayClean() function")
Func _ArrayJoin(ByRef $Array1, ByRef $Array2, $JoinedArray=1)
If IsArray($Array1) And IsArray($Array2) Then
If $JoinedArray = 1 Then
For $iArr = 1 To UBound($Array2) - 1
ReDim $Array1[UBound($Array1) + 1]
$Array1[UBound($Array1) - 1] = $Array2[$iArr]
Next
$Array1[0] = UBound($Array1) - 1
Else
For $iArr = 1 To UBound($Array1) - 1
ReDim $Array2[UBound($Array2) + 1]
$Array2[UBound($Array2) - 1] = $Array1[$iArr]
Next
$Array2[0] = UBound($Array2) - 1
EndIf
SetError(0)
Else
SetError(1)
Return -1
EndIf
EndFunc
Func _ArrayClone(ByRef $Array, $Repeat=1)
If IsArray($Array) Then
Local $TempArr = $Array
For $iR = 1 To $Repeat
For $iArr = 1 To UBound($TempArr) - 1
ReDim $Array[UBound($Array) + 1]
$Array[UBound($Array) - 1] = $TempArr[$iArr]
Next
$Array[0] = UBound($Array) - 1
Next
SetError(0)
Return 1
Else
SetError(1)
Return -1
EndIf
EndFunc
Func _ArrayDeleteClones(ByRef $Array)
If IsArray($Array) Then
Local $StringWithDelValue
For $iD = 1 To UBound($Array) - 1
$FindInArr = _ArraySearch($Array, $Array[$iD])
If $FindInArr <> $iD Then $StringWithDelValue &= $Array[$iD] & "|"
Next
If $StringWithDelValue <> "" Then
$TempArrOfIndexesString = StringSplit($StringWithDelValue, "|")
If IsArray($TempArrOfIndexesString) Then
For $iI = 1 To $TempArrOfIndexesString[0]
$CurrentIndexToDel = _ArraySearch($Array, $TempArrOfIndexesString[$iI])
If $CurrentIndexToDel = -1 Then ExitLoop
_ArrayDelete($Array, $CurrentIndexToDel)
Next
Else
_ArrayDelete($Array, StringReplace($StringWithDelValue, "|", ""))
EndIf
$Array[0] = UBound($Array) - 1
SetError(0)
Return 1
Else
SetError(0)
Return 0
EndIf
Else
SetError(1)
Return -1
EndIf
EndFunc
Func _ArrayClear(ByRef $Array)
If IsArray($Array) Then
For $iArr = 1 To UBound($Array) - 1
_ArrayDelete($Array, $iArr)
Next
$Array[0] = 0
SetError(0)
Return 1
Else
SetError(1)
Return -1
EndIf
EndFunc
Ещё функция для работы с массивом - _ArrayReplace() - Кстати, предыдущие и эта функция, работают только с одномерным (с одним элементом) массивом:
Func _ArrayReplace(ByRef $Array, $ValueToReplace, $NewValue)
Local $IsReplaced = 0
If IsArray($Array) Then
For $iR = 1 To UBound($Array) - 1
$Array[$iR] = StringReplace($Array[$iR], $ValueToReplace, $NewValue)
If StringInStr($Array[$iR], $ValueToReplace) Then $IsReplaced = 1
Next
SetError(0)
If $IsReplaced = 1 Then
Return 1
Else
Return 0
EndIf
Else
SetError(1)
Return -1
EndIf
EndFunc
Эта функция позволяет произвести замену значении в массиве.
P.S
А как определять является ли массив двухмерным, или нет?
Всем всем!
Кому интересна фича отката скрытых папок и расширении файлов, посмотрите на эти два скрипта:
Для отката расширении файлов:
$RegKey = "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
If RegRead($RegKey, "HideFileExt") Then
RegWrite($RegKey, "HideFileExt", "REG_DWORD", 0)
Else
RegWrite($RegKey, "HideFileExt", "REG_DWORD", 1)
EndIf
UpdateExplorer()
Func UpdateExplorer()
$WinExpListArr = _ExplWinGetList()
If IsArray($WinExpListArr) Then
For $iWin = 1 To $WinExpListArr[0]
$GetWinState = WinGetState($WinExpListArr[$iWin])
$Hwnd = WinGetHandle($WinExpListArr[$iWin])
DllCall("user32.dll", "long", "SendMessage", "hwnd", $hWnd, "int", 0x111, "int", 28931, "int", 0)
Next
EndIf
Opt("WinTitleMatchMode", 4)
$Hwnd = WinGetHandle("classname=Progman")
DllCall("user32.dll", "long", "SendMessage", "hwnd", $hWnd, "int", 0x111, "int", 28931, "int", 0)
EndFunc
Func _ExplWinGetList()
Opt("WinTitleMatchMode", 4)
$WinList = WinList("classname=CabinetWClass")
If IsArray($WinList) Then
Local $WinListArr[$WinList[0][0]+1]
For $iW = 1 To $WinList[0][0]
$WinListArr[$iW] = $WinList[$iW][0]
Next
$WinListArr[0] = $WinList[0][0]
Return $WinListArr
Else
Return ""
EndIf
EndFunc
Для отката скрытых папок и файлов:
$RegKey = "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
If RegRead($RegKey, "Hidden") = 1 Then
RegWrite($RegKey, "Hidden", "REG_DWORD", 2)
Else
RegWrite($RegKey, "Hidden", "REG_DWORD", 1)
EndIf
UpdateExplorer()
Func UpdateExplorer()
$WinExpListArr = _ExplWinGetList()
If IsArray($WinExpListArr) Then
For $iWin = 1 To $WinExpListArr[0]
$GetWinState = WinGetState($WinExpListArr[$iWin])
$Hwnd = WinGetHandle($WinExpListArr[$iWin])
DllCall("user32.dll", "long", "SendMessage", "hwnd", $hWnd, "int", 0x111, "int", 28931, "int", 0)
Next
EndIf
Opt("WinTitleMatchMode", 4)
$Hwnd = WinGetHandle("classname=Progman")
DllCall("user32.dll", "long", "SendMessage", "hwnd", $hWnd, "int", 0x111, "int", 28931, "int", 0)
EndFunc
Func _ExplWinGetList()
Opt("WinTitleMatchMode", 4)
$WinList = WinList("classname=CabinetWClass")
If IsArray($WinList) Then
Local $WinListArr[$WinList[0][0]+1]
For $iW = 1 To $WinList[0][0]
$WinListArr[$iW] = $WinList[$iW][0]
Next
$WinListArr[0] = $WinList[0][0]
Return $WinListArr
Else
Return ""
EndIf
EndFunc
Процесс проходит практический незаметно, все открытые окна обновляются, и в конце также обновляется рабочий стол!
В сети можно найте несколько подобных расширении, но я ещё не видел подобное, чтобы весь процесс проходил незаметно.
Вот если бы ещё найти способ как внедрить пункт в контекстное меню папки, по нажатию которого и запускался бы этот скрипт (в закомпилированном виде), то это было бы вообще шикарно!
Creat0Rсделал нужные для себя функции связанные с массиваминесколько замечаний... и свой вариант. ;)
- во избежание проблем индексные переменные в функциях нужно объявлять как Local;
- пустые массивы (счетчик со значением 0) нужно обрабатывать отдельно перед входом в цикл;
- учитывая, что счет индекса идет всегда с единицы, одной проверки IsArray() явно недостаточно. На самом деле все приведенные функции работают с пользовательским типом данных - "массив со счетчиком"… вот на принадлежность этому типу и надо проверять. Более того, при наличии уверенности в корректности массива можно обойтись без лишнего пользования UBound() - достаточно взять значение по индексу 0.
- параметр $JoinedArray в функции _ArrayJoin() имхо избыточный, при нужде поменять параметры проблемы не составит:If $JoinedArray Then
_ArrayJoin ($arr1, $arr2)
Else
_ArrayJoin ($arr2, $arr1)
EndIf- зачем нужна _ArrayClear(), если можно обычным оператором присвоения переинициализировать массив?
- в функции _ArrayReplace две строки перепутаны местами.
#include <Array.au3>
Func _IsCountArray (ByRef $arr)
If IsArray ($arr) Then
If $arr[0] = UBound ($arr)-1 Then Return True
EndIf
Return False
EndFunc
Func _ArrayJoin (ByRef $arrFrom, ByRef $arrTo)
If _IsCountArray($arrFrom) And _IsCountArray($arrTo) Then
Local $i, $n=0
If $arrFrom[0] =0 Then Return 0
For $i=1 To $arrFrom[0]
$n+=_ArrayAdd ($arrTo, $arrFrom [$i])
Next
$arrTo[0]+=$n
Return $n
EndIf
SetError (1)
Return -1
EndFunc
Func _ArrayClone (ByRef $arr, $count = 1)
Local $i, $n=0, $tmp = $arr
If _IsCountArray ($arr) Then
For $i=1 To $count
$n+=_ArrayJoin ($tmp, $arr)
Next
Return $n
EndIf
SetError(1)
Return -1
EndFunc
Func _ArrayDeleteClones (ByRef $arr, $iCaseSense = 0)
If _IsCountArray ($arr) Then
Local $i, $n=0, $iClone
If $arr[0] <2 Then Return 0
For $i=$arr[0] To 2 Step -1
$iClone = _ArraySearch ($arr, $arr[$i], 1, $i-1, $iCaseSense)
If $iClone >0 Then
$n+=_ArrayDelete ($arr, $iClone)
$i-=1
EndIf
Next
$arr[0] = UBound($arr) -1
Return $n
EndIf
SetError(1)
Return -1
EndFunc
Func _ArrayReplace (ByRef $Array, $ValueToReplace, $NewValue)
Local $i, $n=0
If _IsCountArray($Array) And IsString ($ValueToReplace) Then
For $i = 1 To $Array[0]
If StringInStr ($Array[$i], $ValueToReplace) Then
$Array[$i] = StringReplace ($Array[$i], $ValueToReplace, $NewValue)
$n+=1
EndIf
Next
Return $n
EndIf
SetError(1)
Return -1
EndFunc
А как определять является ли массив двухмерным, или нет?UBound ($Array,0) вернет размерность массива
Creat0RКому интересна фича не стоит приводить код одной функции дважды, кстати я не вижу разницы между этими двумя примерами... ;)
Вот если бы ещё найти способ как внедрить пункт в контекстное меню папкиэто сюда: http://forum.oszone.net/showthread.php?t=62252
amel27
несколько замечаний
Спасибо!
во избежание проблем индексные переменные в функциях нужно объявлять как Local
Ну у меня вроде бы все так обьявляется.
достаточно взять значение по индексу 0
Я знаю, но мне казалось что Ubound надёжнее, и к тому же иногда в индексе 0 может ничего и не быть (не формальный массив :) ).
зачем нужна _ArrayClear(), если можно обычным оператором присвоения переинициализировать массив?
А вот тут поподробнее плиз, я что то не совсем понял, как это реализовать на практике? (нужно “опусташить” массив).
в функции _ArrayReplace две строки перепутаны местами.
Нет, я так специально сделал, ведь если нечего заменять, то ничего не будет тронуто, а проверка на наличие значения только лишь для того чтобы вернуть из функции статус о том, произошла ли замена - но твой пример куда продвинутый, в нём также подсчитывается количество замен!
UBound ($Array,0) вернет размерность массива
О! Спасибо, это я и хотел узнать.
не вижу разницы между этими двумя примерами
Упс! :shuffle: - перепутал при вставке из разукрашалки :biggrin: - поправил.
это сюда:
Уау! спасибо, будем смотреть.
P.S
Думаю мне можно простить ошибки которые я допустил в функциях, т.к совсем недавно я вовсе не мог работать с массивами (для меня это было что то страшное и неопознанное), и то что я осмелился написать сам нужные мне функции, это что то - и благодаря таким замечаням как твои, думаю я вскоре освою их основы :UP: .
Creat0RНу у меня вроде бы все так обьявляетсявозьми к примеру $iR - она используется в цикле без предварительного объявления
но мне казалось что Ubound надёжнеене спорю - надежней, но еще надежней ужесточить проверку на входе... :)
А вот тут поподробнее плиз, я что то не совсем понял, как это реализовать на практике? (нужно “опусташить” массив)легко... :) скажем, для случая массива со счетчиком:
Func _ArrayClear (ByRef $arr)
Dim $arr[1] = [0]
EndFunc...теперь вопрос: нужно ли для этого создавать отдельную функцию? ;)
думаю я вскоре освою их основыне сомневаюсь ;)
amel27
возьми к примеру $iR - она используется в цикле без предварительного объявления
Интересно, а я об этом не подумал, почему то считал что испольование переменной в цикле For (в начале) не объявляет её, а просто использует для конкретного цикла, но теперь если вдуматься, то далее после цикла можно будет использовать эту же переменную (и значение она будет иметь тоже что и значение поставленное после To - если конечно не прервать цикл), так что спасибо за подсказку, буду это учитывать :)
легко...
Действительнно легко! Спасибо!
нужно ли для этого создавать отдельную функцию?
Ну только разве что для проверки на массивность и возврата кода ошибочности (если к примеру пытаемся опусташить не массив) :)
amel27
На основе твоего примера для определения цифрового значения, я сделал функцию для обнажения всех НЕ числовых значении, т.е в результате возвращается значение содержащее только цифры:
Func _StringStripNotNumber($String, $RetType=0)
If StringLen($String) < 2 Then
If StringRegExp($String, '^ *([0-9]+\.{0,1}[0-9]*|0x[0-9]+) *$') Then Return $String
Return ""
EndIf
Local $i, $RetNumber, $AllStringArr = StringSplit($String, "")
For $i = 1 To $AllStringArr[0]
If StringRegExp($AllStringArr[$i], '^ *([0-9]+\.{0,1}[0-9]*|0x[0-9]+) *$') Then $RetNumber &= $AllStringArr[$i]
Next
If $RetType = 1 And StringLen($RetNumber) >= 1 Then
$AllStringArr = StringSplit($RetNumber, "")
Return $AllStringArr
EndIf
Return $RetNumber
EndFunc
Если в качестве второго параметра поставить 1, то функция вернёт массив с найденными цифрами, если оставить по умолчанию (0), то возвращается обычная переменная с найденными цифрами.
Может у кого то есть более оригинальное название для этой функции? :shuffle: мне если честно ничего другого в голову не пришло.
[hr]
А как можно получить весь путь до файла, за исключением самого имени файла?
Т.е к примеру, имеем путь C:\test\test.zip - и нужно получить только путь C:\test - хотел бы узнать как это можно осуществить исключительно регулярными вырожениями....
Я до сих пор обходился так:
$Path = "C:\test\test.zip"
$Path = StringTrimRight($Path, StringLen(StringRegExpReplace($Path, "^.*\\", ""))+1)
Но может есть путь по короче? я имею в виду так чтобы одной функцией StringRegExpReplace получить этот же эффект.
amel27
Извини что достаю тебя уже третьий пост подряд, но я нашел небольшой недочёт в функции _FileSelectFolder() - там заголовок (первый параметр $title) не отображается :shuffle:
Creat0Rсделал функцию для обнажения всех НЕ числовых значениичестно говоря не очень представляю назначение этой функции, но тем не менее.... можно и так:Func _StringStripNotNumber ($String, $RetType=0)
$String = StringRegExpReplace ($String,'[^0-9]','') ; Удаляем все не-цифры
If $RetType = 1 Then Return StringSplit ($String, "")
Return $String
EndFuncА как можно получить весь путь до файла, за исключением самого имени файла?например так:StringRegExpReplace ($file, '[^\\]*$', '')
Creat0Rнашел небольшой недочёт в функции _FileSelectFolder() - там заголовок (первый параметр $title) не отображается
спасибо, исправил... забыл я про него совсем :)
amel27
честно говоря не очень представляю назначение этой функции
Я позже выложу скрипт примера (там скрипт предназначен для выбора файлов (кстати обе твои функции используются), и затем их архивирования, весь процесс архивирования считывается через StdOutRead() и из полученного значения нужно получать только цифры, т.к их нужно использовать для прогресс бара ;) ).
можно и так:
Уау! в три раза короче, и в 10 раз правильнее! спасибо!
например так:
Класс! спасибо (см. ниже, выложил свою версию для функции _PathSplit())
спасибо, исправил... забыл я про него совсем
Да нет, это тебе спасибо за эту функцию, я уже успешно её имплонтировал в один из своих скриптов (тот что для архивирования) ;)
[hr]
Моя версия на функцию деления пути используя регулярные выражения:
#include <Array.au3>
$Path = "c:\my test\path\test.zip"
$PathArr = _PathSplitByRegExp($Path)
_ArrayDisplay($PathArr, "Demo of _PathSplitByRegExp()")
Func _PathSplitByRegExp($sPath, $pDelim="\")
Local $RetArray[8], $iArr
$pDelim = "\" & $pDelim
$RetArray[0] = $sPath
$RetArray[1] = StringRegExpReplace($sPath, $pDelim & '.*', $pDelim) ;Drive letter
$RetArray[2] = StringRegExpReplace($sPath, $pDelim & '[^' & $pDelim & ']*$', '') ;Path without FileName and extension
$RetArray[3] = StringRegExpReplace($sPath, '\.[^.]*$', '') ;Full path without File Extension
$RetArray[4] = StringRegExpReplace($sPath, '^.' & $pDelim & '*:', '') ;Full path without drive letter
$RetArray[5] = StringRegExpReplace($sPath, '^.*' & $pDelim, '') ;FileName and extension
$RetArray[6] = StringRegExpReplace(StringRegExpReplace($sPath, '^.*' & $pDelim, ''), '\.[^.]*$', '') ;Just Filename
$RetArray[7] = StringRegExpReplace($sPath, '^.*\.', '') ;Just Extension of a file
;Проверяем все значения (элементы массива), если в каком то из них небыла произведена замена, то присваеваем ему пустое значение ("")
For $iArr = 1 To 7
If $RetArray[$iArr] = $sPath Then $RetArray[$iArr] = ""
Next
Return $RetArray
EndFunc
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.