1 (изменено: teadrinker, 2021-03-26 03:56:54)

Тема: AHK: Онлайн переводчик

Скрипт переводит выделенный текст при двойном нажатии Ctrl + C с одного языка на другой с помощью онлайн-сервиса, предоставляемого Google.

#NoEnv
#SingleInstance, force
DetectHiddenWindows, On
SetBatchLines, -1
Menu, Tray, Icon, % "HICON:" . ExtractIcon("Google16", 16)
SendMessage, WM_SETICON := 0x80, ICON_BIG := 1, ExtractIcon("Google32", 32),, ahk_id %A_ScriptHwnd%

global Info := { PID: DllCall("GetCurrentProcessId")
					, ini: A_ScriptDir . "\GoogleTranslator.ini"
					, GUIs: [], Streams: [], MediaSessions: []
					, Sizing: {}, LangArray: CreateLangArray() }

CreateTrayMenu()
SetHotkey()

Hook := new WinEventHook(EVENT_SYSTEM_MOVESIZEEND := 0xB, 0xB, "GetPos", 0, Info.PID)
OnMessage(0x201, "WM_LBUTTONDOWN")
OnMessage(0x20A, "WM_MOUSEWHEEL")
OnMessage(0x111, "WM_COMMAND")
OnMessage(0x100, "WM_KEYDOWN")
OnMessage(0x214, "WM_SIZING")
Return

CreateTrayMenu() {
	Menu, Tray, NoStandard
	Handler := Func("CreateNewGui").Bind("", "", "en", "ru")
	Menu, Tray, Add, Open New Window, % Handler
	Menu, Tray, Default, Open New Window
	Menu, Tray, Icon, Open New Window, % "HICON:" . ExtractIcon("Google16", 16)
	
	Menu, Tray, Add
	Menu, Tray, Add, Use Ctrl + Ins + Ins, SetHotkey
	Menu, Tray, Add, Use Ctrl + C + C, SetHotkey
	IniRead, CtrlC  , % Info.ini, Hotkeys, CtrlC  , % " "
	IniRead, CtrlIns, % Info.ini, Hotkeys, CtrlIns, % " "
	if !(CtrlC || CtrlIns)
		CtrlC := true
	if CtrlC
		Menu, Tray, Check, Use Ctrl + C + C
	if CtrlIns
		Menu, Tray, Check, Use Ctrl + Ins + Ins
	Menu, Tray, Add
	if !A_IsCompiled {
		Menu, Tray, Add, Edit This Script, ScriptCommands
		Menu, Tray, Add
	}
	Menu, Tray, Add, Reload, ScriptCommands
	Menu, Tray, Add, Exit, ScriptCommands
}

SetHotkey() {
	if A_ThisMenuItem
		Menu, Tray, ToggleCheck, % A_ThisMenuItem
	CtrlC   := IsMenuChecked("Tray", "Use Ctrl + C + C")
	CtrlIns := IsMenuChecked("Tray", "Use Ctrl + Ins + Ins")
	for k, v in ["CtrlC", "CtrlIns"] {
		IniWrite, % %v%, % Info.ini, Hotkeys, % v
		hk := "~^" . SubStr(v, 5)
		if %v%
			Hotkey, % hk, Translate, On
		else
			try Hotkey, % hk, Off
	}
}

IsMenuChecked(menuName, itemNumberOrText) {
   static MIIM_STATE := 1, MFS_CHECKED := 0x8, MF_BYPOSITION := 0x400
   hMenu := MenuGetHandle(menuName)
   if itemNumberOrText is number
      itemNumber := itemNumberOrText - 1
   else {
      Loop % DllCall("GetMenuItemCount", "Ptr", hMenu) {
         itemNumber := A_Index - 1
         len := DllCall("GetMenuString", "Ptr", hMenu, "UInt", itemNumber, "Ptr", 0, "Int", 0, "UInt", MF_BYPOSITION) + 1
         VarSetCapacity(buff, len << !!A_IsUnicode)
         DllCall("GetMenuString", "Ptr", hMenu, "UInt", itemNumber, "Ptr", &buff, "Int", len, "UInt", MF_BYPOSITION)
      } until StrGet(&buff) = itemNumberOrText
   }
   VarSetCapacity(MENUITEMINFO, size := 4*4 + A_PtrSize*8, 0)
   NumPut(size, MENUITEMINFO)
   NumPut(MIIM_STATE, MENUITEMINFO, 4)
   DllCall("GetMenuItemInfo", "Ptr", hMenu, "UInt", itemNumber, "UInt", true, "Ptr", &MENUITEMINFO)
   Return !!(NumGet(MENUITEMINFO, 4*3, "UInt") & MFS_CHECKED)
}

Translate() {
	if A_Gui {
		for k, v in ["from", "to"] {
			GuiControlGet, lang,, ComboBox%k%
			%v% := Info.LangArray[lang]
		}
		GuiControlGet, sourceText,, Edit1
		GuiControl,, Edit2, % GoogleTranslate(sourceText, from, to)
	}
	else if (A_ThisHotkey = A_PriorHotkey && A_TimeSincePriorHotkey < 400) {
		sourceText := Clipboard
		from := RegExMatch(sourceText, "[А-Яа-я]") ? "ru" : "auto"
		to := from = "ru" ? "en" : "ru"
		transText := GoogleTranslate(sourceText, from, to)
		CreateNewGui(sourceText, transText, from, to)
	}
}

ScriptCommands() {
	if (A_ThisMenuItem = "Edit This Script")
		Edit
	if (A_ThisMenuItem = "Reload")
		Reload
	if (A_ThisMenuItem = "Exit")
		ExitApp
}

CreateNewGui(sourceText := "", transText := "", from := "en", to := "ru") {
	static ES_NOHIDESEL := 0x100, BS_ICON := 0x40, IMAGE_ICON := 1, BM_SETIMAGE := 0xF7, Icons
	( !Icons && Icons := [ ExtractIcon("Swap"     , 16)
					         , ExtractIcon("PlayPause", 25)
					         , ExtractIcon("Stop"     , 12)
					         , ExtractIcon("Translate", 16) ] )
	for k, v in Info.LangArray
		sourceLangNames .= (A_Index = 1 ? "" : "|") . k . (v = from ? "|" : "")
	 , targetLangNames .= (A_Index = 1 ? "" : "|") . k . (v = to   ? "|" : "")
	sourceLangNames := RegExReplace(sourceLangNames, "\|$", "||")
	targetLangNames := RegExReplace(targetLangNames, "\|$", "||")

	Gui, New, +AlwaysOnTop +LastFound +Resize +hwndhGui +Owner +MinSize199x237 -MaximizeBox, Google Translate
	Loop 2 {
		i := A_Index, b := i = 1
		Gui, Font, q5 s8, Verdana
		Gui, Add, Text, % "x10 y+15", % b ? "Исходный язык:" : "Язык перевода:"
		Gui, Add, DDL, x112 yp-4 w182, % b ? sourceLangNames : targetLangNames
		Gui, Add, Button, x297 yp-1 w23 h23 gSwapLang %BS_ICON%
		
		IniRead, edit%i%_fontSize, % Info.ini, Settings, Edit%i% FontSize, 8
		Gui, Font, % "q5 s" . edit%i%_fontSize, Verdana
		Info["edit" . i . "_fontSize"] := edit%i%_fontSize
		Gui, Add, Edit, x10 y+9 w310 Multi %ES_NOHIDESEL%, % b ? sourceText : transText
		GuiControlGet, Edit%i%, Pos
		( (Edit%i%H < 45 || (i = 1 && sourceText = "") || (i = 2 && transText = "")) && Edit%i%H := 45 )
		( Edit%i%H > 250 && Edit%i%H := 250 )
		GuiControl, Move, Edit%i%, % "h" . Edit%i%H

		Gui, Font, q5 s8, Verdana
		Gui, Add, Button, % "x10 w52 h23 gPlayPause y" (Edit%i%Y + Edit%i%H + 5) . " " . BS_ICON
		Gui, Add, Button, x+3 yp wp hp Disabled %BS_ICON%
		Gui, Add, Button, % "x250 yp w70 hp g" . (b ? "Translate Default " . BS_ICON : "GuiClose"), % b ? "" : "OK"
	}
	Loop 7
		PostMessage, BM_SETIMAGE, IMAGE_ICON, Icons[ mod(A_Index - 1, 4) + 1 ], Button%A_Index%
	Sizing := Info["Sizing", hGui] := {}
	GuiControlGet, Edit2, Pos
	height := Sizing.height := Edit2Y + Edit2H + 34
	GetPos()
	if Info.GUIs[1] {
		WinGetPos, X, Y,,, % "ahk_id" . Info.GUIs[1]
		X += 50, Y += 30
	}
	else {
		IniRead, X, % Info.ini, Coords, X, % " "
		IniRead, Y, % Info.ini, Coords, Y, % " "
	}
	if b := (X != "" && Y != "") {
		Gui, Show, % "Hide x" . X . " y" . Y . " h" . height
		WinGetPos,,, W, H, ahk_id %hGui%
		(X + W > A_ScreenWidth  && X := 0)
		(Y + H > A_ScreenHeight && Y := 0)
	}
	Info.GUIs.InsertAt(1, hGui)
	GuiControl, Focus, Edit1
	Gui, Show, % (b ? "x" . X . " y" . Y : "") . " h" . height
}

WM_KEYDOWN(wp, lp, msg, hwnd) {
	static VK_TAB := 0x9, VK_ENTER := 0xD, EN_SETFOCUS := 0x100
	if ( wp = VK_TAB && GetKeyState("Ctrl", "P") ) {
		SwapLang()
		WM_COMMAND(EN_SETFOCUS << 16)
		Return 0
	}
	if ( wp = VK_ENTER && !(GetKeyState("Shift", "P") || GetKeyState("Ctrl", "P")) ) {
		WinGetClass, winClass, ahk_id %hwnd%
		if (winClass = "Edit") {
			Translate()
			Return 0
		}
	}
}

WM_LBUTTONDOWN() {
	PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2
}

WM_MOUSEWHEEL(wp, lp, msg, hwnd) {
	static MK_CONTROL := 0x8, EM_GETSEL := 0xB0, Timer
	if !( wp & MK_CONTROL )
		Return
	
	Loop 2
		GuiControlGet, hEdit%A_Index%, hwnd, Edit%A_Index%
	if !hEdit := hEdit1 = hwnd ? hEdit1 : hEdit2 = hwnd ? hEdit2 : 0
		Return
	
	nn := (hEdit = hEdit2) + 1
	key := "edit" . nn . "_fontSize"
	turn := wp >> 16
	Info[key] += (turn > 0 && turn <= 0x7FFF ? 1 : -1)
	(Info[key] < 8 && Info[key] := 8)
	fontSize := Info[key]
	Gui, Font, s%fontSize%
	GuiControl, Font, %hEdit%
	if !Info.prevText {
		Info.prevText := {}
		GuiControlGet, prevText,, %hEdit%
		Info.prevText.text := prevText
		SendMessage, EM_GETSEL,,,, ahk_id %hEdit%
		Info.prevText.start := ErrorLevel & 0xFFFF
		Info.prevText.end   := ErrorLevel >> 16
	}
	GuiControl,, %hEdit%, %fontSize% размер шрифта
   DllCall("HideCaret", "Ptr", hEdit)
	try SetTimer, % Timer, Delete
	Timer := Func("SaveFontSize").Bind(fontSize, hEdit, nn)
	SetTimer, % Timer, -800
}

SaveFontSize(fontSize, hEdit, nn) {
	static EM_SETSEL := 0xB1, EM_SCROLLCARET := 0xB7
	GuiControl,, %hEdit%, % Info.prevText.text
	DllCall("ShowCaret", "Ptr", hEdit)
	SendMessage, EM_SETSEL, Info.prevText.start, Info.prevText.end,, ahk_id %hEdit%
	SendMessage, EM_SCROLLCARET,,,, ahk_id %hEdit%
	Info.Delete("prevText")
	IniWrite, % fontSize, % Info.ini, Settings, % "Edit" . nn . " FontSize"
}

WM_COMMAND(wp) {
	static EN_SETFOCUS := 0x100, CBN_SETFOCUS := 3, WM_INPUTLANGCHANGEREQUEST := 0x50
	notify := wp >> 16
	if (notify = CBN_SETFOCUS)
		PostMessage, WM_INPUTLANGCHANGEREQUEST,, 0x419,, ahk_id %A_ScriptHwnd%
	if (notify = EN_SETFOCUS) {
		GuiControlGet, focus, Focus
		n := SubStr(focus, 0)
		GuiControlGet, lang,, ComboBox%n%
		PostMessage, WM_INPUTLANGCHANGEREQUEST,, lang = "Русский" ? 0x419 : 0x409,, ahk_id %A_ScriptHwnd%
	}
}

WM_SIZING(wp) {
	Info.Sizing.edge := ["left", "right", "top", "topLeft", "topRight", "bottom", "bottomLeft", "bottomRight"][wp]
}

GuiSize(hwnd, eventInfo, width, height) {
	if (eventInfo = 1)
		Return
	Critical
	if (Info.Sizing.edge ~= "i)right|left") {
		Loop 2 {
			d := (width - 330)/2
			if (width > 330) {
				GuiControl, Move, %   "Static" . A_Index      , % "x"  10 + d
				GuiControl, Move, % "ComboBox" . A_Index      , % "x" 112 + d
				GuiControl, Move, %   "Button" . A_Index*4 - 3, % "x" 297 + d
			}
			GuiControl, Move, %   "Edit" . A_Index  , % "w" width - 20
			GuiControl, Move, % "Button" . A_Index*4, % "x" width - 80
		}
	}
	dH := height - Info["Sizing", hwnd, "prevHeight"]
	if (Info.Sizing.edge ~= "bottom")
		ResizeBottom(hwnd, height, dH)
	if (Info.Sizing.edge ~= "top")
		ResizeTop(hwnd, height, dH)
	Info["Sizing", hwnd, "height"] := height
	CorrectEditHeight(hwnd)
}

ResizeTop(hwnd, height, dH, fromBottom := false) {
	Sizing := Info["Sizing", hwnd]
	if ( (edit1H := Sizing.edit1H + dH) < 45 ) {
		if !Info.Sizing.flag
			GetPos(), Info.Sizing.flag := true
		if !fromBottom
			ResizeBottom(hwnd, height, dH, true)
	}
	else {
		GuiControl, Move, Edit1, h%edit1H%
		edit2Y := Sizing.edit2Y
		Loop 3 {
			GuiControl, Move, % "Button" . A_Index + 1, % "y" edit2Y - 65 + dH
			GuiControl, MoveDraw, % "Button" . A_Index + 5, % "y" height - 30
		}
		GuiControl, MoveDraw,   Static2, % "y" edit2Y - 27 + dH
		GuiControl, Move    , ComboBox2, % "y" edit2Y - 31 + dH
		GuiControl, MoveDraw,   Button5, % "y" edit2Y - 32 + dH
		GuiControl, Move    ,     Edit2, % "y" edit2Y + dH
	}
}

ResizeBottom(hwnd, height, dH, fromTop := false) {
	Sizing := Info["Sizing", hwnd]
	if ( (edit2H := Sizing.edit2H + dH) < 45 ) {
		if !Info.Sizing.flag
			GetPos(), Info.Sizing.flag := true
		if !fromTop
			ResizeTop(hwnd, height, dH, true)
	}
	else {
		GuiControl, Move, Edit2, h%edit2H%
		Loop 3
			GuiControl, MoveDraw, % "Button" . A_Index + 5, % "y" height - 30
	}
}

GetPos() {
	Info.Sizing.flag := false
	WinGet, list, List, % "Google Translate ahk_class AutoHotkeyGUI ahk_pid " . Info.PID
	Loop % List {
		hGui := List%A_Index%, Sizing := Info["Sizing", hGui]
		Loop 2 {
			GuiControlGet, Pos, %hGui%: Pos, Edit%A_Index%
			Sizing["edit" . A_Index . "Y"] := PosY
			Sizing["edit" . A_Index . "H"] := PosH
		}
		Sizing.prevHeight := Sizing.height
	}
}

CorrectEditHeight(hGui) {
	GuiControlGet,   editPos, %hGui%: Pos, Edit2
	GuiControlGet, buttonPos, %hGui%: Pos, Button6
	H := buttonPosY - editPosY - 5
	if (H != editPosH)
		GuiControl, %hGui%: Move, Edit2, h%H%
}

SwapLang() {
	GuiControlGet, from,, ComboBox1
	GuiControlGet,   to,, ComboBox2
	GuiControl, Choose, ComboBox1, % to
	GuiControl, Choose, ComboBox2, % from
	GuiControlGet, focus, Focus
	GuiControl, Focus, % "Edit" . !(focus ~= "Button[1-4]|Edit1") + 1
}

PlayPause() {
	GuiControlGet, buttonNN, Focus
	GuiControlGet, hButton, hwnd, % buttonNN
	if !Info.MediaSessions[hButton]
		PlayText(buttonNN, hButton)
	else
		Info.MediaSessions[hButton].Pause()
}

PlayText(buttonNN, key) {
	static MFCLOCK_STATE_RUNNING := 1
	Gui, +OwnDialogs
	textToSpeach := GetTextToSpeach(buttonNN, lng)
	if (textToSpeach = "")
		Return
	if !pIStream := GetStream(textToSpeach, lng)
		Return
	Session := Info.MediaSessions[key] := new MediaSession()
	Session.InitializeWithStream(pIStream)
	(lng = "ru" && Session.SetRate(1.3))
	start := false, Session.Start()
	Loop
		Sleep, 50
	until A_Index = 20 || (Session.GetState() = MFCLOCK_STATE_RUNNING && start := true)
	if !start {
		Info.MediaSessions.Delete(key)
		MsgBox, 48, Warning, Can't start media session, try again
		Return
	}
	stopNN := "Button" . SubStr(buttonNN, 0) + 1
	GuiControl, -g, % stopNN
	StopHandler := Func("Stop").Bind(key, stopNN)
	GuiControl, +g, % stopNN, % StopHandler
	GuiControl, Enable, % stopNN
	Timer := Func("DeleteSession").Bind(key, A_Gui, stopNN)
	SetTimer, % Timer, 300
}

DeleteSession(key, hGui, stopNN) {
   static MFCLOCK_STATE_INVALID := 0
        , MFCLOCK_STATE_STOPPED := 2
	state := Info.MediaSessions[key].GetState()
	if (!state || state = MFCLOCK_STATE_STOPPED) {
		SetTimer,, Delete
		GuiControl, %hGui%: Disable, % stopNN
		Info.MediaSessions.Delete(key)
	}
}

GetTextToSpeach(buttonNN, ByRef lng) {
	editNN := "Edit" . !(buttonNN ~= "2") + 1
	GuiControlGet, hEdit, hwnd, % editNN
	ControlGet, textToSpeach, Selected,,, ahk_id %hEdit%
	if (textToSpeach = "")
		GuiControlGet, textToSpeach,, % editNN
	GuiControlGet, lang,, % "ComboBox" . SubStr(editNN, 0)
	lng := Info.LangArray[lang]
	textToSpeach := Trim(textToSpeach, " `t`n`r")
	if (textToSpeach = "")
		MsgBox, 48, Warning, Text to speach is empty
	Return textToSpeach
}

GetStream(textToSpeach, lng) {
	for k, v in Info.Streams {
		if (textToSpeach = v.text && lng = v.lng) {
			pIStream := v.stream
			break
		}
	}
	if !pIStream {
		try pIStream := GetMp3StreamFromGoogle(textToSpeach, lng, dataSize)
		catch e {
			MsgBox, 48, Warning, % e
			Return
		}
		size := 0
		for k, v in Info.Streams
			size += v.size
		if (size + dataSize > 0x100000) {
			Obj := Info.Streams.RemoveAt(1)
			ObjRelease(Obj.stream)
		}
		Info.Streams.Push( {text: textToSpeach, lng: lng, stream: pIStream, size: dataSize} )
	}
	Return pIStream
}

Stop(key, stopNN) {
	Info.MediaSessions[key].Stop()
	Info.MediaSessions.Delete(key)
	GuiControl, Disable, % stopNN
}

GuiClose() {
	RemoveGui()
}

GuiEscape() {
	RemoveGui()
}

RemoveGui() {
	Info.Sizing.Delete(A_Gui)
	for k, v in Info.GUIs
		if (v = A_Gui)
			break
	hGui := Info.GUIs.RemoveAt(k)
	Loop 2 {
		GuiControlGet, hPlayPause, hwnd, % "Button" . A_Index*4 - 2
		Info.MediaSessions[hPlayPause].Stop()
		Info.MediaSessions.Delete(hPlayPause)
	}
	if !Info.GUIs[1] {
		WinGetPos, X, Y,,, ahk_id %hGui%
		IniWrite, % X, % Info.ini, Coords, X
		IniWrite, % Y, % Info.ini, Coords, Y
	}
	Gui, Destroy
	if !Info.GUIs[1]
		DllCall("SetProcessWorkingSetSize", "Ptr", DllCall("GetCurrentProcess"), "Ptr", -1, "Ptr", -1)
}

GoogleTranslate(str, ByRef from, to := "en") {
   static JS := CreateScriptObj()
	
   if !Ping4("translate.google.com")
		Return "Error: Ping4(""translate.google.com"") failed with error: " . ErrorLevel
	
   json := SendRequest(JS, str, to, from)
   try oJSON := JS.JSON.parse(json)
	catch {
		Clipboard := json
		Return "Error: Can't parse json, full error text is in ClipBoard`n`n" . SubStr(json, 1, 500)
	}
   if !IsObject(oJSON[1])  {
      Loop % oJSON[0].length
         trans .= oJSON[0][A_Index - 1][0]
   }
   else  {
      MainTransText := oJSON[0][0][0]
      Loop % oJSON[1].length  {
         trans .= "`n+"
         obj := oJSON[1][A_Index-1][1]
         Loop % obj.length  {
            txt := obj[A_Index - 1]
            trans .= (MainTransText = txt ? "" : "`n" txt)
         }
      }
   }
   if !IsObject(oJSON[1])
      MainTransText := trans := Trim(trans, ",+`n ")
   else
      trans := MainTransText . "`n+`n" . Trim(trans, ",+`n ")

   from := oJSON[2]
   trans := Trim(trans, ",+`n ")
   Return trans
}

SendRequest(JS, str, tl, sl, proxy := "") {
   static Whr, userAgent := "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0"
   ComObjError(false)
   if !Whr {
      Whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
      ( proxy && Whr.SetProxy(2, proxy) )
      Whr.Open("GET", "https://translate.google.com", true)
      Whr.SetRequestHeader("User-Agent", userAgent)
      Whr.Send()
      Whr.WaitForResponse(-1)
   }
   Whr.Open("POST", "https://translate.googleapis.com/translate_a/single?client=gtx"
                ; or https://clients5.google.com/translate_a/t?client=dict-chrome-ex
      . "&sl=" . sl . "&tl=" . tl . "&hl=" . tl
      . "&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t&ie=UTF-8&oe=UTF-8&otf=0&ssel=0&tsel=0&pc=1&kc=1"
      . "&tk=" . JS.eval("tk").(str), true)

   Whr.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
   Whr.SetRequestHeader("User-Agent", userAgent)
   Whr.Send("q=" . EncodeDecodeURI(str))
   Whr.WaitForResponse(-1)
   Return Whr.responseText
}

Ping4(Addr, ByRef Result := "", Timeout := 1024) {
   Static WSADATAsize := (2 * 2) + 257 + 129 + (2 * 2) + (A_PtrSize - 2) + A_PtrSize
   OrgAddr := Addr
   Result := "" 
   VarSetCapacity(WSADATA, WSADATAsize, 0)
   if (Err := DllCall("Ws2_32\WSAStartup", "UShort", 0x0202, "Ptr", &WSADATA, "Int")) {
      ErrorLevel := "WSAStartup failed with error " . Err
      Return
   }
   if !RegExMatch(Addr, "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$") {
      if !(HOSTENT := DllCall("Ws2_32\gethostbyname", "AStr", Addr, "UPtr")) {
         DllCall("Ws2_32\WSACleanup")
         ErrorLevel := "gethostbyname failed with error " . DllCall("Ws2_32\WSAGetLastError", "Int")
         Return
      }
      PAddrList := NumGet(HOSTENT + 0, (2 * A_PtrSize) + 4 + (A_PtrSize - 4), "UPtr")
      PIPAddr := NumGet(PAddrList + 0, 0, "UPtr")
      Addr := StrGet(DllCall("Ws2_32\inet_ntoa", "UInt", NumGet(PIPAddr + 0, 0, "UInt"), "UPtr"), "CP0")
   }
   INADDR := DllCall("Ws2_32\inet_addr", "AStr", Addr, "UInt")
   if (INADDR = 0xFFFFFFFF) {
      ErrorLevel := "inet_addr failed for address " . Addr
      Return
   }
   DllCall("Ws2_32\WSACleanup")
   HMOD := DllCall("LoadLibrary", "Str", "Iphlpapi.dll", "UPtr")
   Err := ""
   if (HPORT := DllCall("Iphlpapi\IcmpCreateFile", "UPtr")) {
      REPLYsize := 32 + 8
      VarSetCapacity(REPLY, REPLYsize, 0)
      if DllCall("Iphlpapi\IcmpSendEcho", "Ptr", HPORT, "UInt", INADDR, "Ptr", 0, "UShort", 0, "Ptr", 0
													 , "Ptr", &REPLY, "UInt", REPLYsize, "UInt", Timeout, "UInt")
		{
         Result := {}
         Result.InAddr := OrgAddr
         Result.IPAddr := StrGet(DllCall("Ws2_32\inet_ntoa", "UInt", NumGet(Reply, 0, "UInt"), "UPtr"), "CP0")
         Result.RTTime := NumGet(Reply, 8, "UInt")
      }
      else
         Err := "IcmpSendEcho failed with error " . A_LastError
      DllCall("Iphlpapi\IcmpCloseHandle", "Ptr", HPORT)
   }
   else
      Err := "IcmpCreateFile failed to open a port!"
	DllCall("FreeLibrary", "Ptr", HMOD)
   if (Err) {
      ErrorLevel := Err
      Return
   }
   ErrorLevel := 0
   Return Result.RTTime
}

EncodeDecodeURI(str, encode := true, component := true) {
	static JS
	( !JS && JS := CreateScriptObj() )
   for k, v in [["\", "\\"], ["'", "\'"], ["`r", "\r"], ["`n", "\n"]]
      str := StrReplace(str, v[1], v[2])
   Return JS.eval( (encode ? "en" : "de") . "codeURI" . (component ? "Component" : "") . "('" . str . "')" )
}

GetJScript()
{
   script =
   (
      var TKK = ((function() {
        var a = 561666268;
        var b = 1526272306;
        return 406398 + '.' + (a + b);
      })());

      function b(a, b) {
        for (var d = 0; d < b.length - 2; d += 3) {
            var c = b.charAt(d + 2),
                c = "a" <= c ? c.charCodeAt(0) - 87 : Number(c),
                c = "+" == b.charAt(d + 1) ? a >>> c : a << c;
            a = "+" == b.charAt(d) ? a + c & 4294967295 : a ^ c
        }
        return a
      }

      function tk(a) {
          for (var e = TKK.split("."), h = Number(e[0]) || 0, g = [], d = 0, f = 0; f < a.length; f++) {
              var c = a.charCodeAt(f);
              128 > c ? g[d++] = c : (2048 > c ? g[d++] = c >> 6 | 192 : (55296 == (c & 64512) &&
				  f + 1 < a.length && 56320 == (a.charCodeAt(f + 1) & 64512) ?
              (c = 65536 + ((c & 1023) << 10) + (a.charCodeAt(++f) & 1023), g[d++] = c >> 18 | 240,
              g[d++] = c >> 12 & 63 | 128) : g[d++] = c >> 12 | 224, g[d++] = c >> 6 & 63 | 128), g[d++] = c & 63 | 128)
          }
          a = h;
          for (d = 0; d < g.length; d++) a += g[d], a = b(a, "+-a^+6");
          a = b(a, "+-3^+b+-f");
          a ^= Number(e[1]) || 0;
          0 > a && (a = (a & 2147483647) + 2147483648);
          a `%= 1E6;
          return a.toString() + "." + (a ^ h)
      }
   )
   Return script
}

CreateScriptObj() {
   static doc, JS
   if !doc {
      doc := ComObjCreate("htmlfile")
      doc.write("<meta http-equiv='X-UA-Compatible' content='IE=9'>")
      JS := doc.parentWindow
      (doc.documentMode < 9 && JS.execScript())
		JS.eval("delete ActiveXObject; delete GetObject;")
		JS.eval( GetJScript() )
   }
   Return JS
}

ExtractIcon(name, size) {
	Base64 := GetBase64String(name)
	Return hIcon := CreateIconFromBase64(Base64, size)
}

CreateIconFromBase64(StringBASE64, Size) {
   CryptStringToBinary(StringBASE64, IconData)
   Return DllCall("CreateIconFromResourceEx", "Ptr", &IconData + 4
      , "UInt", NumGet(&IconData, "UInt"), "UInt", true, "UInt", 0x30000, "Int", Size, "Int", Size, "UInt", 0)
}

CryptStringToBinary(string, ByRef outData, formatName := "CRYPT_STRING_BASE64") {
   static formats := { CRYPT_STRING_BASE64: 0x1
                     , CRYPT_STRING_HEX:    0x4
                     , CRYPT_STRING_HEXRAW: 0xC }
   fmt := formats[formatName]
   chars := StrLen(string)
   if !DllCall("Crypt32\CryptStringToBinary", "Ptr", &string, "UInt", chars, "UInt", fmt
                                            , "Ptr", 0, "UIntP", bytes, "UIntP", 0, "UIntP", 0)
      throw "CryptStringToBinary failed. LastError: " . A_LastError
   VarSetCapacity(outData, bytes)
   DllCall("Crypt32\CryptStringToBinary", "Ptr", &string, "UInt", chars, "UInt", fmt
                                        , "Str", outData, "UIntP", bytes, "UIntP", 0, "UIntP", 0)
   Return bytes
}

class WinEventHook
{
   __New(eventMin, eventMax, hookProc, eventInfo := 0, idProcess := 0, idThread := 0, dwFlags := 0) {
      this.pCallback := RegisterCallback(hookProc, "F",, eventInfo)
      this.hHook := DllCall("SetWinEventHook", "UInt", eventMin, "UInt", eventMax, "Ptr", 0, "Ptr", this.pCallback
                                             , "UInt", idProcess, "UInt", idThread, "UInt", dwFlags, "Ptr")
   }
   __Delete() {
      DllCall("UnhookWinEvent", "Ptr", this.hHook)
      DllCall("GlobalFree", "Ptr", this.pCallback, "Ptr")
   }
}

class MediaSession {
   __New() {
      static MF_VERSION := 0x2, MFSTARTUP_NOSOCKET := 0x1
      DllCall("Mfplat\MFStartup", "UInt", MF_VERSION, "UInt", MFSTARTUP_NOSOCKET, "UInt")
      this.MFSession := IMFMediaSession.Create()
   }
   __Delete() {
      this.Topology := ""
      this.PresentationDescriptor := ""
      this.MediaSource := ""

      this.MFSession.Shutdown()
      this.MFSession := ""
      DllCall("Mfplat\MFShutdown")
   }
   InitializeWithStream(pIStream, fileType := "mp3") {
      static MF_RESOLUTION_MEDIASOURCE := 1
      SourceResolver := IMFSourceResolver.Create()
      ByteStream := IMFByteStream.CreateFromStream(pIStream)

      this.MediaSource := SourceResolver.CreateObjectFromByteStream( ByteStream.ptr, "file." . fileType
                                                                   , MF_RESOLUTION_MEDIASOURCE, 0, MF_OBJECT_TYPE )
      SourceResolver := ByteStream := ""

      this.PresentationDescriptor := this.MediaSource.CreatePresentationDescriptor()
      this.Topology := IMFTopology.Create()
      descriptorCount := this.PresentationDescriptor.GetStreamDescriptorCount()
      Loop % descriptorCount
         this._AddBranchToPartialTopology(A_Index - 1)
      this.MFSession.SetTopology(0, this.Topology.ptr)
   }
   Start(atBeginning := true) {
      VarSetCapacity(GUID_NULL, 16, 0)
      VarSetCapacity(PROPVARIANT, 8 + A_PtrSize*2, 0)
      if atBeginning
         NumPut(VT_I8 := 0x14, PROPVARIANT, "UShort")
      this.MFSession.Start(&GUID_NULL, &PROPVARIANT)
   }
   Pause() {
      state := this.GetState()
      if (state != 1)
         this.Start(false)
      else
         this.MFSession.Pause()
   }
   Stop() {
      this.MFSession.Stop()
   }
   GetState() {
      static MFCLOCK_STATE_INVALID := 0
           , MFCLOCK_STATE_RUNNING := 1
           , MFCLOCK_STATE_STOPPED := 2
           , MFCLOCK_STATE_PAUSED  := 3
      Clock := this.MFSession.GetClock()
      Return Clock.GetState()
   }
   SetRate(rate) {
      RateControl := this.MFSession.GetRateControl()
      RateControl.SetRate(rate)
   }
   _AddBranchToPartialTopology(i) {
      static MFMediaType_Audio := "{73647561-0000-0010-8000-00AA00389B71}"
      StreamDescriptor := this.PresentationDescriptor.GetStreamDescriptorByIndex(i, selected)
      if selected {
         MediaTypeHandler := StreamDescriptor.GetMediaTypeHandler()
         VarSetCapacity(GUID, 16, 0)
         MediaTypeHandler.GetMajorType(GUID)
         if StringFromGUID(GUID) = MFMediaType_Audio
            MFActivate := IMFActivate.Create()
         SourceTopologyNode := this._AddSourceNode(StreamDescriptor)
         OutputTopologyNode := this._AddOutputNode(MFActivate)
         SourceTopologyNode.ConnectOutput(0, OutputTopologyNode.ptr, 0)
      }
   }
   _AddSourceNode(StreamDescriptor) {
      static MF_TOPOLOGY_SOURCESTREAM_NODE := 1
           , MF_TOPONODE_SOURCE                  := "{835C58EC-E075-4BC7-BCBA-4DE000DF9AE6}"
           , MF_TOPONODE_PRESENTATION_DESCRIPTOR := "{835C58ED-E075-4BC7-BCBA-4DE000DF9AE6}"
           , MF_TOPONODE_STREAM_DESCRIPTOR       := "{835C58EE-E075-4BC7-BCBA-4DE000DF9AE6}"
      SourceTopologyNode := IMFTopologyNode.Create(MF_TOPOLOGY_SOURCESTREAM_NODE)
      SourceTopologyNode.SetUnknown( CLSIDFromString(MF_TOPONODE_SOURCE                 , GUID), this.MediaSource.ptr )
      SourceTopologyNode.SetUnknown( CLSIDFromString(MF_TOPONODE_PRESENTATION_DESCRIPTOR, GUID), this.PresentationDescriptor.ptr )
      SourceTopologyNode.SetUnknown( CLSIDFromString(MF_TOPONODE_STREAM_DESCRIPTOR      , GUID), StreamDescriptor.ptr )
      this.Topology.AddNode(SourceTopologyNode.ptr)
      Return SourceTopologyNode
   }
   _AddOutputNode(MFActivate) {
      static MF_TOPOLOGY_OUTPUT_NODE := 0
           , MF_TOPONODE_STREAMID             := "{14932F9B-9087-4BB4-8412-5167145CBE04}"
           , MF_TOPONODE_NOSHUTDOWN_ON_REMOVE := "{14932F9C-9087-4BB4-8412-5167145CBE04}"
      OutputTopologyNode := IMFTopologyNode.Create(MF_TOPOLOGY_OUTPUT_NODE)
      OutputTopologyNode.SetObject(MFActivate.ptr)
      OutputTopologyNode.SetUINT32( CLSIDFromString(MF_TOPONODE_STREAMID            , GUID), 0 )
      OutputTopologyNode.SetUINT32( CLSIDFromString(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, GUID), 0 )
      this.Topology.AddNode(OutputTopologyNode.ptr)
      Return OutputTopologyNode
   }
}

class IMFMediaSession extends InterfaceBase {
   Create() {
      DllCall("Mf\MFCreateMediaSession", "Ptr", 0, "PtrP", pIMFMediaSession)
      Return new IMFMediaSession(pIMFMediaSession)
   }
   GetRateControl() {
      static MF_RATE_CONTROL_SERVICE := "{866FA297-B802-4BF8-9DC9-5E3B6A9F53C9}"
           , IID_IMFRateControl      := "{88DDCD21-03C3-4275-91ED-55EE3929328F}"
      hr := DllCall("Mf\MFGetService", "Ptr", this.ptr, "Ptr", CLSIDFromString(MF_RATE_CONTROL_SERVICE, _)
                                                      , "Ptr", CLSIDFromString(IID_IMFRateControl, __)
                                                      , "PtrP", pIMFRateControl)
      this.IsError("IMFMediaSession::GetRateControl", hr)
      Return new IMFRateControl(pIMFRateControl)
   }
   SetTopology(flags, pIMFTopology) {
      hr := DllCall(this.VTable(7), "Ptr", this.ptr, "UInt", flags, "Ptr", pIMFTopology)
      this.IsError("IMFMediaSession::SetTopology", hr)
   }
   Start(pGUID, pVariant) {
      hr := DllCall(this.VTable(9), "Ptr", this.ptr, "Ptr", pGUID, "Ptr", pVariant)
      this.IsError("IMFMediaSession::Start", hr)
   }
   Pause() {
      hr := DllCall(this.VTable(10), "Ptr", this.ptr)
      this.IsError("IMFMediaSession::Pause", hr)
   }
   Stop() {
      hr := DllCall(this.VTable(11), "Ptr", this.ptr)
      this.IsError("IMFMediaSession::Stop", hr)
   }
   Shutdown() {
      hr := DllCall(this.VTable(13), "Ptr", this.ptr)
      this.IsError("IMFMediaSession::Shutdown", hr)
   }
   GetClock() {
      hr := DllCall(this.VTable(14), "Ptr", this.ptr, "PtrP", pIMFClock)
      this.IsError("IMFMediaSession::GetClock", hr)
      Return new IMFClock(pIMFClock)
   }
}

class IMFClock extends InterfaceBase {
   GetState() {
      hr := DllCall(this.VTable(6), "Ptr", this.ptr, "UInt", 0, "UIntP", state)
      this.IsError("IMFClock::GetState", hr)
      Return state
   }
}

class IMFSourceResolver extends InterfaceBase {
   Create() {
      DllCall("Mfplat\MFCreateSourceResolver", "PtrP", pIMFSourceResolver)
      Return new IMFSourceResolver(pIMFSourceResolver)
   }
   CreateObjectFromByteStream(pIMFByteStream, URL, flags, pIPropertyStore, ByRef MF_OBJECT_TYPE) {
      static IID_IMFMediaSource := "{279A808D-AEC7-40C8-9C6B-A6B492C78A66}"
      hr := DllCall(this.VTable(4), "Ptr", this.ptr, "Ptr", pIMFByteStream, "WStr", URL, "UInt", flags
                                  , "Ptr", pIPropertyStore, "UIntP", MF_OBJECT_TYPE, "PtrP", pIUnknown)
      this.IsError("IMFSourceResolver::CreateObjectFromByteStream", hr)
      pIMFMediaSource := ComObjQuery(pIUnknown, IID_IMFMediaSource)
      ObjRelease(pIUnknown)
      Return new IMFMediaSource(pIMFMediaSource)
   }
}

class IMFByteStream extends InterfaceBase {
   CreateFromStream(pIStream) {
      hr := DllCall("Mfplat\MFCreateMFByteStreamOnStream", "Ptr", pIStream, "PtrP", pIMFByteStream)
      IMFByteStream.IsError("IMFByteStream::MFCreateMFByteStreamOnStream", hr)
      Return new IMFByteStream(pIMFByteStream)
   }
}

class IMFMediaSource extends InterfaceBase {
   CreatePresentationDescriptor() {
      hr := DllCall(this.VTable(8), "Ptr", this.ptr, "PtrP", pIMFPresentationDescriptor)
      this.IsError("IMFMediaSource::CreatePresentationDescriptor", hr)
      Return new IMFPresentationDescriptor(pIMFPresentationDescriptor)
   }
}

class IMFPresentationDescriptor extends InterfaceBase {
   GetStreamDescriptorCount() {
      hr := DllCall(this.VTable(33), "Ptr", this.ptr, "UIntP", descriptorCount)
      this.IsError("IMFPresentationDescriptor::GetStreamDescriptorCount", hr)
      Return descriptorCount
   }
   GetStreamDescriptorByIndex(idx, ByRef selected) {
      hr := DllCall(this.VTable(34), "Ptr", this.ptr, "UInt", idx, "UIntP", selected, "PtrP", pIMFStreamDescriptor)
      this.IsError("IMFPresentationDescriptor::GetStreamDescriptorByIndex", hr)
      Return new IMFStreamDescriptor(pIMFStreamDescriptor)
   }
}

class IMFTopology extends InterfaceBase {
   Create() {
      DllCall("Mf\MFCreateTopology", "PtrP", pIMFTopology)
      Return new IMFTopology(pIMFTopology)
   }
   AddNode(pNode) {
      hr := DllCall(this.VTable(34), "Ptr", this.ptr, "Ptr", pNode)
      this.IsError("IMFTopology::AddNode", hr)
   }
}

class IMFStreamDescriptor extends InterfaceBase {
   GetMediaTypeHandler() {
      hr := DllCall(this.VTable(34), "Ptr", this.ptr, "PtrP", pIMFMediaTypeHandler)
      this.IsError("IMFStreamDescriptor::GetMediaTypeHandler", hr)
      Return new IMFMediaTypeHandler(pIMFMediaTypeHandler)
   }
}

class IMFMediaTypeHandler extends InterfaceBase {
   GetMajorType(ByRef GUID) {
      hr := DllCall(this.VTable(8), "Ptr", this.ptr, "Ptr", &GUID)
      this.IsError("IMFMediaTypeHandler::GetMajorType", hr)
   }
}

class IMFActivate extends InterfaceBase {
   Create() {
      hr := DllCall("Mf\MFCreateAudioRendererActivate", "PtrP", pIMFActivate)
      Return new IMFActivate(pIMFActivate)
   }
}

class IMFTopologyNode extends InterfaceBase {
   Create(type) {
      hr := DllCall("Mf\MFCreateTopologyNode", "UInt", type, "PtrP", pIMFTopologyNode)
      IMFTopologyNode.IsError("IMFTopologyNode::Create", hr)
      Return new IMFTopologyNode(pIMFTopologyNode)
   }
   SetUINT32(riid, value) {
      hr := DllCall(this.VTable(21), "Ptr", this.ptr, "Ptr", riid, "UInt", value)
      this.IsError("IMFTopologyNode::SetUINT32", hr)
   }
   SetUnknown(riid, pi) {
      hr := DllCall(this.VTable(27), "Ptr", this.ptr, "Ptr", riid, "Ptr", pi)
      this.IsError("IMFTopologyNode::SetUnknown", hr)
   }
   SetObject(pi) {
      hr := DllCall(this.VTable(33), "Ptr", this.ptr, "Ptr", pi)
      this.IsError("IMFTopologyNode::SetObject", hr)
   }
   ConnectOutput(OutputIndex, pDownstreamNode, dwInputIndexOnDownstreamNode) {
      hr := DllCall(this.VTable(40), "Ptr", this.ptr, "UInt", OutputIndex
                                   , "Ptr", pDownstreamNode, "UInt", dwInputIndexOnDownstreamNode)
      this.IsError("IMFTopologyNode::ConnectOutput", hr)
   }
}

class IMFRateControl extends InterfaceBase {
   SetRate(rate, fThin := true) {
      hr := DllCall(this.VTable(3), "Ptr", this.ptr, "UInt", fThin, "Float", rate)
      this.IsError("IMFRateControl::SetRate", hr)
   }
}

class InterfaceBase {
   __New(ptr) {
      this.ptr := ptr
   }
   __Delete() {
      ObjRelease(this.ptr)
   }
   VTable(idx) {
      Return NumGet(NumGet(this.ptr + 0) + A_PtrSize*idx)
   }
   IsError(method, result, exc := true) {
      if (result = 0)
         Return 0
      this.error := method . " failed. Result: " . ( result = "" ? "No result" : Format("{:#x}", result & 0xFFFFFFFF) )
                              . "`nErrorLevel: " . ErrorLevel
      if !exc
         Return this.error
      throw Exception(this.error)
   }
}

StringFromGUID(ByRef VarOrAddress) {
   pGuid := IsByRef(VarOrAddress) ? &VarOrAddress : VarOrAddress
   VarSetCapacity(sGuid, 78) ; (38 + 1) * 2
   if !DllCall("ole32\StringFromGUID2", "Ptr", pGuid, "Ptr", &sGuid, "Int", 39)
      throw Exception("Invalid GUID", -1, Format("<at {1:p}>", pGuid))
   return StrGet(&sGuid, "UTF-16")
}

CLSIDFromString(IID, ByRef CLSID) {
   VarSetCapacity(CLSID, 16, 0)
   if res := DllCall("ole32\CLSIDFromString", "WStr", IID, "Ptr", &CLSID, "UInt")
      throw Exception("CLSIDFromString failed. Error: " . Format("{:#x}", res))
   Return &CLSID
}

GetMp3StreamFromGoogle(text, lng, ByRef dataSize) {
   static hHeap := DllCall("GetProcessHeap", "Ptr")
        , flags := (HEAP_NO_SERIALIZE := 0x1) | (HEAP_ZERO_MEMORY := 0x8)
   if ( (text := Trim(text, " `t`n`r")) = "" )
      throw "Text to speach is empty"
	
	if !Ping4("translate.google.com")
		throw "Ping4(""translate.google.com"") failed with error: " . ErrorLevel
	
   chunks := [], text .= ".", pos := 1
   Loop {
      for k, v in ["\.", "!", "\?", ";", ",", ":", "\(", "\)", " ", "$"]
         RegExMatch(SubStr(text, pos, 200), "sO).+" . v . "+", m)
      until m.Len
      chunks.Push(m[0])
      pos += m.Len
   } until pos > StrLen(text)
   last := chunks.Pop()
   chunks.Push( SubStr(last, 1, -1) )

   size := offset := 0
   for k, v in chunks {
      url := CreateUrl(v, lng)
      Arr := SendMsxmlRequest(url)
      pData := NumGet(ComObjValue(Arr) + 8 + A_PtrSize)
      length := Arr.MaxIndex() + 1
      size += length
      if (A_Index = 1)
         pHeap := DllCall("HeapAlloc", "Ptr", hHeap, "UInt", flags, "Ptr", size, "Ptr")
      else
         pHeap := DllCall("HeapReAlloc", "Ptr", hHeap, "UInt", flags, "Ptr", pHeap, "Ptr", size, "Ptr")
      DllCall("RtlMoveMemory", "Ptr", pHeap + offset, "Ptr", pData, "Ptr", length)
      offset := size
   }
   pIStream := DllCall("Shlwapi\SHCreateMemStream", "Ptr", pHeap, "UInt", dataSize := offset, "Ptr")
   DllCall("HeapFree", "Ptr", hHeap, "UInt", 0, "Ptr", pHeap)
   Return pIStream
}

CreateUrl(text, lng) {
   static JS := CreateScriptObj()
   url := "https://translate.google.com/translate_tts?ie=UTF-8&tl="
         . lng . "&total=1&idx=0&client=t&prev=input&textlen="
         . StrLen(text) . "&tk=" . JS.eval("tk").(text) . "&q=" . EncodeDecodeURI(text)
   Return url
}

SendMsxmlRequest(url) {
   Whr := ComObjCreate("Msxml2.XMLHTTP.6.0")
   Whr.Open("GET", url, false)
   Whr.Send()
	status := Whr.Status
   if (status != 200)
      throw "HTTP status: " . status . "`n`n" . Whr.responseBody
   Return Whr.responseBody
}

GetBase64String(name)
{
	IconGoogle16 =
	(
		aAQAACgAAAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAAAADt5+GR
		/Pr49/78+//p0Ln/sUsA/71iAP+8YQD/vGEA/7xhAP+8YQD/vGEA/7xhAP+8YQD/
		vGEA/7thAPqxawGU/f38+/7+/v7//////Pr4/8yANf/HZwD/y3IQ/8tyEP/Lcg//
		ym8J/8txDv/LchD/y3EP/8puCf/LcQ/+ynMR+v7+/f/////////////////y3cr/
		1XYR/+GLJ//giSf/4Isq/+GPM//fiCX/4Ioo/9+IJP/hjzP/4Iss/96IJv/+/v7/
		/////////////////////+Wnbf/niCD/7ZY1/+mSMP/57eD/8bJr/+h9B//vqVz/
		+/Tu/+uYPP/rki///f7+//7////+/////v/////////37ef/4IQq/++YNP/sjiT/
		9NSx//vn0f/ytHL/+eLI//jiyv/sjiX/7pk6//z9/v/9/v///f7///3+///9/v//
		/////+m5kP/ohR7/8ZYv//CtZP/7+vn/78ab//v7+v/zuXn/75Eq//CbPf/8/P3/
		/v7///7////9/v///f3///7+///7+vv/4o0///GVL//wnD3/+Ora//SxZ//68OT/
		8aFH//GZOP/ynT///f3+//z59//89vH///////7//////////////+/Ruf/nhCD/
		9Zct//XSq////fz/+d2///KULP/0n0D/9J9B//39/v/7+PP/8cmi//PCk//9+vf/
		88WY/+ybS//7+PX/5aBj//KOI//1smj/9uzh//W3dP/2mTT/9qBC//ahQ//7+/3/
		/f7///3////ww5f/6o0y/+uVQv/yxZj//Pjy//Tl2//mhSn/+KA9//ScO//3nz7/
		+KJF//iiRP/4o0X//Pv+//38///+////+e/n/+Z6Ef/0y6T///////3+////////
		6K18//COKf/7pUX/+aNF//mjRv/5o0b/+aRH//v7/f/8/f///v////XWuf/yzqz/
		65VA//3////9/////f7///jx7v/mijb/+qFA//umSP/7pUj/+6VI//ulSf/8/P7/
		+/r7//Xhz//02L7/9+nc/+qcUf/wvYv/+e7i//v9///+////7MGf/+2JJ//9qUv/
		+6ZJ//umSf/7pkr//Pv+//v6/f/59O7/9+3k/+qZSv/58u7/8cqk//nv6P/8/f//
		/P3///r7/f/mk0v/+Jw7//2pS//8p0r//adL//v6/fn8/P/+/P////ny7v/23sr/
		/P3///3////8/v//+/v///v7///+////8tbB/+uKL//+qEn//qhL/v2oTfn69/Sb
		+/v++fr6/v/8///+/v///vv8//77+/7++/v+/vv7/v77/P7++/7+/vv///7nk0/+
		+Jk7//6oTPv5qFOXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
	)
	IconGoogle32 =
	(
		qBAAACgAAAAgAAAAQAAAAAEAIAAAAAAAgBAAAAAAAAAAAAAAAAAAAAAAAADn3tQD6OHatvv49P/8+PX8+/j0/vz59f/58ev/t2ER/7daAf+8YgL/umAA/7thAf+7YQH/
		u2EB/7thAf+7YQH/u2EB/7thAf+7YQH/u2EB/7thAf+7YQH/u2EB/7thAf+7YQH/u2EB/7thAf+7YQH+u2AA/LtgAP+sWwHEzogDCfLu6MX+/f38//////////7/////
		/fz6///////Zqn7/tVMA/8RsC//DaAb/w2kG/8NpBv/DaQb/w2kG/8NpBv/DaQb/w2kG/8NpBv/DaQb/w2kG/8NpBv/DaQb/w2kG/8NpBv/DaQb/w2kG/8NpBv/DaQb+
		wmgF/8NpBv64bA7E///+///////////////////////+/f3//v7+//v38//EciX/xGgJ/8x0Ev/KcQ//y3IQ/8tyEP/LchD/y3IQ/8tyEP/LchD/y3IQ/8tyEP/LchD/
		y3IQ/8tyEP/LchD/y3IQ/8tyEP/LchD/y3IQ/8tyEP/Lcg//ynEP/811Ef/+/fz9/////v/////+/v7////////////9/Pv//////+nIqP/DYwb/1H4f/9R8Gv/UfBr/
		1H0b/9R9G//UfRv/1H0b/9R9G//Vfh3/1X4e/9V9HP/UfRv/1H0b/9R9G//UfRv/1H0b/9V+Hf/Vfh7/1X0c/9R8Gv/UfBr+1X8d/f79+/7/////////////////////
		/v7+//7+/v/+/Pv//v79/9eSUf/Sdhb/34so/92HJf/eiCb/3ogm/96IJv/eiCb/3ogm/92DHP/dghr/3oYi/96JJ//eiCb/3ogm/96IJv/eiSf/3YQd/92CGv/dhR//
		3okn/92HJf/eiyn+/v38//////////////////////////////////38+//+////9eLR/9J1Hf/jjS//55Ew/+WQL//nkTD/5pEw/+aRMP/lkC//6qpm/+2xcv/onUj/
		5o8s/+aRMf/nkTD/5pEx/+aQLv/qqF//7bFy/+mjVf/mjiv/5pEw/+eTM//9/f3//v////7////+/////v////7////+/v7//v////38+v//////46l1/9p5G//slzn/
		6pQ0/+uUNf/rlTX/65Y4/+iMKP/w2L7///////XSq//pjSb/65Y4/+uUNf/rkzP/65pB//v28v//////7ruE/+mOKP/rljj/65c4//79/P//////////////////////
		/////////////v7//v38//7+/f/57+b/130t/+WNMP/tmDj/65Y2/+yXN//smDn/7JAo/+qydf/9/fz/++/h/+yXOP/sljT/7Jg5/+uQKv/vtXT//v79//r07f/qnET/
		7JUz/+yWN//smTr//f39//7////+/////v////7////+/////v////7//v/+/////fz7///////pvpn/2Xgd/+yYO//umDj/7Zc3/+2YOf/uljT/6pxG//j07///////
		8a9n/+ySMP/tmj7/65Iu//bXtf/+/v7/9dy//+uRLP/umTv/7Zc3/+6aPP/8/f3//f7///3+///9/v///f7///3+///9/v///f7///3+/v/9/v7//f38//z59v/bi0X/
		44cr/++bPP/umTn/75k5/++aPP/sky//8trA//7+/v/99e7///bu///48f/+9e3//fr2///////xv4f/7pIr/++bPf/umDn/75s9//39/f/+/v///v3///7+///+/v//
		/v7///7+///+/v///v7///7+///8+/r///////DSuv/Zdx//7JY6//CaO//vmTr/8Js9//CULv/tuoH//v////r18P/t3Mr/7dvJ//Dk2P//////+/n2/+6jUP/wlzX/
		75o8//CZOv/wnD7//f39//79///+/P///v3///79///+/f///v3///79///+/f///f3+//39/v/9/Pz//v///+CbYf/gfyP/8Jw///CbPP/wmzz/8Zk3/+yhTv/5+fj/
		/PTq/+uYO//qih//77yD//7+/v/34Mf/75Uy//GcPf/wmzv/8Jo7//GdP//9/f3//v7///79///+/v///v7///7+///+/v///v7///7+///+/v///v7///38/P/+/v7/
		9eTW/9p7J//qkzj/8p0+//GcPf/ynkD/75c1//Pex///////9rl3//GULP/65c7///////LBi//xlTD/8p5A//KcPv/xnD3/8p5B//39/f/9/v///fz+//39/v/9/f7/
		/f3+//39/v/+/v///v7///7+///9/f7//v7///z8+///////5q+A/959I//wmz//850+//KeQf/ylzL/776I//7+/v/506n/8aBH//37+v/8+/j/8adW//OaOf/ynT//
		850+//KcPf/zn0L//P39//79///+/f///v////39///9/Pv//f3+//3+/v/9/f7//f3+//7+///9/P3//fv6//38/P/68+3/3YU5/+iMMv/0nkD/855A//SbOv/vpVP/
		+vz9//3r2P/0voP///////jizP/ymTj/9J9B//SeP//0nj//850+//SgQ//9/f3//f7+//38/f/67uP//v/////////+/////fz8//7+///9/f7//fz9////////////
		/f7////+/v/txaT/3Xog//CZP//1oEH/9aBC//KaOP/15NL//vr2//nkzv/+/v3/9cWR//SZNP/1oUT/9Z9B//WfQf/0nkD/9aFE//z8/f/9/f3//fz8//HStP/sq2z/
		9cme//z38//+/////fz7//3+///+////+OLN/++vcP/21bX///////z6+f/gk1L/5YYt//SfQ//2okX/9Zkz//HFlP////////////3////zq1v/9p08//WgQ//2oEL/
		9qBC//WfQf/2okX/+/39//z+/v/8/P3//v////bn2f/nmk7/6o40//XQq//9////+/j0//C0eP/pii3/6YIe/+qKK//22r3//v////HXwv/ceST/7ZU+//ahRP/2nTz/
		8ahZ/+zXv//t2cL/7syo//WeP//2oEP/9qBC//agQv/2oEL/9Z9B//aiRf/8/P3//f3+//38///8+/v//v////v9/v/pqm3/53wT//C0ef/tpV7/6IId/+mHJ//qlUL/
		7a5w//PQrv/8+/v//v///+Skbv/igSj/851D//eiRP/2n0D/85s5//ObOf/0nDr/96JE//ehQ//3oUP/96FD//ehQ//2oEL/96NG//z7/f/9/P///Pv+//39///8+/z/
		/fz9//r8/f/qqWn/6YMg/+qKLP/qkz7/8cGT//nx6f/9/////v////z7/P/9/v7/9+rg/92BMf/qkDn/96FE//eiRP/4o0b/+aRG//ijRv/4okT/+KJE//iiRP/4okT/
		+KJE//ehQ//4pEj//Pz9//39///9/P///Pz+//39///7+fr//v////Tcxv/piSr/6ogo//PHnP///////P3///z7/P/8+/z//f3///v6+v//////6reM/+B8Iv/ynEL/
		+aRF//iiRP/5o0X/+aNF//mjRf/5o0X/+aNF//mjRf/5o0X/+KJE//mlSf/8/P3//P3///z8///8/f///Pz+//z7/P/9////7axt/+iHKf/piy7/7Z9S//z49f/8/Pz/
		/Pz+//z8/v/8/P7//Pz9//z8/f/79fH/4IpB/+iKMv/2oUT/+aRG//ijRf/5pEb/+aRG//mkRv/5pEb/+aRG//mjRf/4o0X/+aVJ//z7/f/9/P///fv///38///8+/3/
		/f7///js4v/pkDj/9N3H/+mcUP/pgh7/9ti9//3+/f/7+vv//fz+//38///9/f//+/r7///////wzLD/33wl//CZQv/6pUf/+aRH//qlR//6pUf/+qVH//qlR//6pUf/
		+qVH//qkRv/6pkr//Pz9//z8/v/8/P///Pz9//v49//9/fz/8cSa//C7iP//////7beC/+h+F//wtXv//v////v4+P/8+/z//P3///z8/v/8/P7//Pv8//38+//kmFj/
		5oYu//afRf/7pkj/+qRH//ulSP/7pUj/+6VI//ulSP/7pUj/+6RH//umS//8+/3//P3///v7///8/////f////3////wxJn/+/r5//7////z38z/6Ico/+uQNv/35NH/
		/f////z////7/P7//P3///z8///6+vv//f7///Tfzv/ffyv/7ZQ9//mjR//7pkj/+qVI//umSP/7pkj/+6ZI//umSP/7pUf/+6dL//z7/f/7+/3//Pz///fo3P/zz6z/
		8tK0/++/kP/13ML/9uHM//LWuv/njTX/6JpN//HAkP/20rH/9di8//z9///7+/3/+/z+//v8///6+fv//v///+iref/jgCj/85xE//ymSP/6pEj/+6VI//ulSP/7pUj/
		+6VI//ukR//7p0z//Pr9//v7/f/8/P//9+vh//TdyP/14tL/9eTV//Xi0f/rqWn/8MCR//fp2//05tn/6JVF/+d+Fv/007P//P7+//v6/P/8+////Pv+//v6/P/8/f3/
		+O3k/+CDNf/rjzr/+KJG//ynSf/7pUj//KZJ//ymSf/8pkn//KVI//yoTP/8+/3+/Pz///v6///8/////f////z////9////+fLt/+mGJf/slUD//Pz9//3////z38z/
		9NrC//3////7+v3//Pz///z8///7/P7//Pz///r5+//+////7b2X/+J/KP/xmkT//KdJ//ynSv/8p0r//adK//2nSv/9pkn//ahN/vz7/f37+/7+/Pv///v7/f/7+v3/
		+vn6//v9/f/tuYf/6I41//HIoP/7/Pv/+/n7//3////9////+/r9//z8///8+/7/+/z///v8///7+/7/+/v+//v7/P/7+Pb/45BL/+mJM//3n0X//qhL//ymSf/9p0v/
		/adK//2mSf79qE79/Pv9//z8///7+v///Pz///v7/v/7/P//+/v+//ju5v/59fT//P////z7/v/8+/7/+/r8//v6/P/8/P///Pv+//z8///8/P///Pz///z8///8/P//
		+vn7//3////y0rn/4X0l/++WQP/7pUj//ahL//2nSv/+qEv//adK//6pTv/79fLG+/v9+vv7/v/7+/7++/z///v7///7/P///P////z9///7+v3/+/z///v8///7+/7/
		+/z///v8///7/P//+/z///v8///7/P//+/z///v7/v/7+/7/+/r8//3+///noWf/5oUu//ScRP/9qEv//ahL/v6oS//9qUz896lTwPv28Av6+fjD+vv+//r7/vz7+/7+
		+/v+/vv7/v76+/3++vv+/vv7/v77+/7++/v+/vv7/v77+/7++/v+/vv7/v77+/7++/v+/vv7/v77+/7++/v+/vv7/v75+Pr+/P/+/vPTvP7ieCX+75A//vufRv7/pEn8
		/qJI/vylT8z2pE4IgAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAE=
	)
	IconSwap =
	(
		aAQAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAUAAAAQAAAAGQAAABsAAAAS
		AAAACAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHx8fFt
		+Pj4tfj4+LXPz89/AAAAJgAAABMAAAAFAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAADy8vIuyLqzyGI3IP9iNyD/+Pj4tTs7O0MAAAAiAAAADAAAAAIAAAAA
		AAAAAAAAAAAAAAACAAAABAAAAAUAAAAEAAAAAvb29mv4+Pi1fkcq/7GRgNrCwsKI
		AAAANAAAABcAAAAFAAAAAAAAAAAAAAACAAAACQAAABIAAAAYAAAAEgAAAAsAAAAI
		5ubmcr6YhNqUVDH/2MO4yG9vb2UAAAAsAAAAEgAAAAAAAAACAAAACd/f33b4+Pi1
		ysrKggAAADAAAAAgAAAAFsXFxWPNqZPWpmE3/8igh9qzs7OTAAAARAAAACQAAAAC
		AAAACd/f33b4+Pi1sms5//j4+LW5ubmOx8fHhPj4+LX4+Pi1ypt64LJrOf+yazn/
		+Pj4tfj4+LXPz89/AAAABOjo6HH4+Pi1uHE5/7hxOf+4cTn/+Pj4tfj4+LW4cTn/
		uHE5/7hxOf+4cTn/uHE5/7hxOf+4cTn/+Pj4tfPz82z4+Pi1vXg5/714Of+9eDn/
		vXg5/714Of/4+Pi1+Pj4tb14Of+9eDn/vXg5/714Of+9eDn/+Pj4td/f33b4+Pi1
		wn85/8J/Of/Cfzn/wn85/8J/Of/Cfzn/wn85//j4+LX4+Pi1wn85/8J/Of/Cfzn/
		+Pj4td/f33YAAAAJ9vb2a/j4+LX4+Pi1xoc5/8aHOf/Xrnrg+Pj4tfj4+LXm5uZy
		8fHxbfj4+LXGhzn/+Pj4tejo6HEAAAAJAAAAAgAAAAAAAAAA8/PzbN26iNrKjjn/
		4MGU1qenp3UAAAAqAAAAEAAAAAP29vZr+Pj4tfPz82wAAAAEAAAAAgAAAAAAAAAA
		AAAAAPLy8i7q2brIzpc4/9+/iNrHx8eEAAAALQAAABYAAAAFAAAAAQAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8/PzbOTJhtrVqDX/+Pj4tdTU1HwAAAAZ
		AAAACAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOnp6RH4+Pi1
		2rUz/9q1M//u4rnIw8PDOQAAAAUAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAA9vb2a/j4+LX4+Pi17+/vbgAAAAcAAAADAAAAAQAAAAAAAAAA
		AAAAAAAAAAAAAAAA/gEAAP4AAAD+AAAA4AAAAMAAAACAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAADAAQAAwB8AAMAfAADgHwAA8B8AAA==
	)
	IconPlayPause =
	(
		UAoAACgAAAAZAAAAMgAAAAEAIAAAAAAAxAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAEAAAABAAAAAQAAAAAAAAAA
		AAAAAAAAAAAAAAABAAAAAQAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB
		AAAAAQAAAAIAAAACAAAAAgAAAAIAAAABAAAAAQAAAAEAAAABAAAAAQAAAAIAAAACAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAIAAAAHAAAADwAAABAAAAAKAAAAAwAAAAIAAAABAAAAAQAAAAIAAAAE
		AAAAAwAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKmpqQPJyckTAAAAFgAAABcAAAAX
		AAAAFwAAABUAAAAHAAAAA+zs7Cnn5+cqAAAACQAAAAgAAAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAPv7+0D+/PqS9uXTnfHx8W66uro8AAAAFwAAABcAAAAXAAAAF+vr61nsxJ2t7MSdreXl5VcAAAANAAAAAwAAAAEAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wL+/PqS0nQY7s1mAf/Wgi/g9d/Kn9/f31k9PT0dAAAAFwAAABf9/f2P
		zmgE/M5qCPr9/f2LAAAAEQAAAAQAAAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8K+e3hmdBpBP/QaQT/
		0GkE/9FtC/rjpWfD/vz6ks3NzUgAAAAX////kdBpBP/QaQT/////kQAAABEAAAAEAAAAAgAAAAEAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAA////Cfvx55fTbAf/02wH/9NsB//TbAf/02wH/9h9Iury1bam5OTkXv///5HTbAf/02wH/////5EAAAAR
		AAAABAAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wn78eeX13AL/9dwC//XcAv/13AL/9dwC//XcAv/
		13EN/uakZMf///+R13AL/9dwC/////+RAAAADQAAAAMAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8J
		+/Hnl9t0D//bdA//23QP/9t0D//bdA//23QP/9t0D//bdhL8/vz6ktt0D//bdA//////kQAAAAcAAAACAAAAAQAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////Cfzy6JfgeRP/4HkT/+B5E//geRP/4HkT/+B5E//gehX+7Kxsxv///5HgeRP/
		4HkT/////5EAAAADAAAAAgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wn88uiX5X4Y/+V+GP/lfhj/
		5X4Y/+V+GP/ojjXp+Ny/pP///1T///+R5X4Y/+V+GP////+RAAAAAgAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAD///8K/PDkmemCHP/pghz/6YIc/+qFIvryt3zB//37kv///zgAAAAA////kemCHP/pghz/////kQAAAAEAAAAB
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////Av/9+5LvjzHy7och//GeS9/86dWe////Tv///wMAAAAA
		AAAAAP///47uiCT87oon+v///4oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///9E
		/vjylf3n0p////9m////KwAAAAAAAAAAAAAAAAAAAAD///9S+9WvrPvVr6z///9OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wX///8TAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///yT///8k
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////gP///4D///+A////gP8Hh4D+AAOA/gADgP4AA4D8AAOA+AABgPgAAYD4AAGA
		+AADgPgAA4D4AAOA+AADgPgCB4D4Bh+A/B4fgP5/P4D///+A////gP///4D///+A////gA==
	)
	IconStop =
	(
		aAQAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAANmrlAC4WysAuFsrAL5gLQDBYy4AwWMuAMtqMADLajAA
		y2owANFvMgDRbzIA13Q0ANd0NADtupkAAAAAAAAAAAC0WCoA3HA7AOB6RQDjgU4A
		5YxXAOiVXwDqnGYA7aVuAPCtdgD0t34A976FAPnEiQD5xIkA13Q0AAAAAAAAAAAA
		tFgqAN1sNgDSYSUA1GYoANhtLQDXdDQA4H05AOSEPgDpjkYA7ZdMAPCdUAD0pVYA
		+cSJANd0NAAAAAAAAAAAALRYKgDdbDYA0F0iANJhJQDYbS0A13Q0AOB9OQDkhD4A
		5olCAOqQRwDtl0wA8J1QAPe+hQDRbzIAAAAAAAAAAACyVikA3Ww2ANBdIgDSYSUA
		2G0tANhtLQDddjQA4H05AOSEPgDmiUIA6Y5GAO2XTADztHwA0W8yAAAAAAAAAAAA
		slYpAN1yQQDOWiAA0mElANJhJQDYbS0A13Q0AN12NADgfTkA5IQ+AOaJQgDmiUIA
		8K12AMtqMAAAAAAAAAAAALJWKQDjiV0AzlogANBdIgDSYSUA2G0tANhtLQDXdDQA
		3XY0AOB9OQDgfTkA5IQ+AO2lbgDLajAAAAAAAAAAAACvVCkA5ZRsANd3RQDUZigA
		0F0iANJhJQDVaCkA2G0tAN12NADddjQA4H05AN54NgDqnGYAyGcwAAAAAAAAAAAA
		r1QpAOWZcgDYeUcA2HlHAN1yQQDWbjYA2G0tANVoKQDVaCkA2G0tANhtLQDXdDQA
		6JVfAMFjLgAAAAAAAAAAAK9UKQDlnXgA13hIANd4SADYeUcA2HlHANh5RwDYeUcA
		4HpFANx7QQDbeT4A3HtBAOiVYwDBYy4AAAAAAAAAAACqUScA5qF+ANZ3SADYeUcA
		2HlHANh5RwDYeUcA2HlHANx7QQDYeUcA3H1JANh5RwDolWMAwWMuAAAAAAAAAAAA
		qE8mAOajggDagVUA2oFVANqBVQDagVUA3H1JANqBVQDcfUkA3H1JANh5RwDjgU4A
		44ldALhbKwAAAAAAAAAAAKZNJgDlnXgA5qOCAOahfgDlmXIA5ZlyAOWUbADolWMA
		44ldAOKCUgDjfEoA44FOAOKCUgC4WysAAAAAAAAAAADRpZEApk0mAKhPJgCvVCkA
		r1QpAK9UKQCvVCkAslYpALJWKQC0WCoAtFgqALRYKgC0WCoA2auUAAAAAAAAAAAA
		AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
		AAAAAAAAAAAAAAAA//8AAIABAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAA
		gAEAAIABAACAAQAAgAEAAIABAACAAQAA//8AAA==
	)
	IconTranslate =
	(
		aAQAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABILAAASCwAAAAAAAAAAAAD///8A
		////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A
		////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A
		////AP///wD///8A////AP///wD///8A////AP///wD///8A////ALJnFgCpXhAA
		olcKAJxRBQCXTAJIl0wCSJxRBQCiVwoAqV4QALJnFgD///8A////AP///wD///8A
		////AP///wCyZxYAqV4QAKJXCgCdUgZcnFEFzJxRBcydUgZcolcKAKleEACyZxYA
		////AP///wD///8A////AP///wD///8AsmcWAKleEACjWAtcolcKzP+8Hv//uxv/
		olcKzKNYC1ypXhAAsmcWAP///wD///8A////AP///wD///8A////ALJnFgCqXxFc
		qV4QzP/DMf//sgD//7IA//++I/+pXhDMql8RXLJnFgD///8A////AP///wD///8A
		////AP///wCzaBdcsmcWzP3JSf/9vSb//bYU//y1Ev/9uh7//cAv/7JnFsyzaBdc
		////AP///wD///8A////AP///wD///8Aum8cmbtwHcy7cB3Mu3AdzPK3OP/ytTX/
		u3AdzLtwHcy7cB3Mum8cmf///wD///8A////AP///wD///8A////ALtwHQC9ch4A
		wHUgAMR5JMznslD/57BN/8R5JMzAdSAAvXIeALtwHQD///8A////AP///wD///8A
		////AP///wC7cB0AwnciAM2CKwDNgivM67pr/+a1Zf/NgivMzYIrAMJ3IgC7cB0A
		////AP///wD///8A////AP///wD///8Ayn8oANaLMQDWizEA1osxzPXIfP/1xnr/
		1osxzNaLMQDWizEAyn8oAP///wD///8A////AP///wD///8A////AN6TNwDekzcA
		3pM3AN6TN8z60YX/+tCE/96TN8zekzcA3pM3AN6TNwD///8A////AP///wD///8A
		////AP///wDkmTwA5Jk8AOSZPADkmTzM/9+T///fk//kmTzM5Jk8AOSZPADkmTwA
		////AP///wD///8A////AP///wD///8A6J0+AOidPgDonT4A6Z4/memeP8zpnj/M
		6Z4/meidPgDonT4A6J0+AP///wD///8A////AP///wD///8A////AP///wD///8A
		////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A
		////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A
		////AP///wD///8A//8AAP//AAD+fwAA/D8AAPgfAADwDwAA4AcAAOAHAAD8PwAA
		/D8AAPw/AAD8PwAA/D8AAPw/AAD//wAA//8AAA==
	)
	Return Icon%name%
}

CreateLangArray()
{
	Languages =
	(LTrim C
		Азербайджанский|az
		Албанский|sq
		Английский|en
		Арабский|ar
		Армянский|hy
		Африкаанс|af
		Баскский|eu
		Белорусский|be
		Бенгальский|bn
		Бирманский|my
		Болгарский|bg
		Боснийский|bs
		Ваалийский|cy
		Венгерский|hu
		Вьетнамский|vi
		Галисийский|gl
		Греческий|el
		Грузинский|ka
		Гуджарати|gu
		Датский|da
		Зулу|zu
		Иврит|iw
		Игбо|ig
		Идиш|yi
		Индонезийский|id
		Ирландский|ga
		Исландский|is
		Испанский|es
		Итальянский|it
		Йоруба|yo
		Казахский|kk
		Каннада|kn
		Каталанский|ca
		Китайский|zh
		Китайский (Аомынь)|zh-cn
		Китайский (Тайвань)|zh-tw
		Корейский|ko
		Латынь|la
		Латышский|lv
		Литовский|lt
		Македонский|mk
		Малагасийский|mg
		Малайский|ms
		Малайялам|ml
		Мальтийский|mt
		Маори|mi
		Маратхи|mr
		Монгольский|mn
		Немецкий|de
		Непали|ne
		Нидерландский|nl
		Норвежский|no
		Панджаби|pa
		Персидский|fa
		Польский|pl
		Португальский|pt
		Румынский|ro
		Русский|ru
		Себуанский|ceb
		Сербский|sr
		Сесото|st
		Сингальский|si
		Словацкий|sk
		Словенский|sl
		Сомали|so
		Суахили|sw
		Суданский|su
		Тагальский|tl
		Таджикский|tg
		Тайский|th
		Тамильский|ta
		Телугу|te
		Турецкий|tr
		Узбекский|uz
		Украинский|uk
		Урду|ur
		Финский|fi
		Французский|fr
		Хауса|ha
		Хинди|hi
		Хмонг|hmn
		Хорватский|hr
		Чева|ny
		Чешский|cs
		Шведский|sv
		Эсперанто|eo
		Эстонский|et
		Яванский|jw
		Японский|ja
	)
	LangArray := {}
	Loop, parse, Languages, `n, `r
	{
		RegExMatch(A_LoopField, "(.+)\|(.+)", m)
		LangArray[m1] := m2
	}
	Return LangArray
}

http://i.imgur.com/QuMllzh.jpg

По нажатию Ctrl+C+C и/или Ctrl+Ins+Ins (по выбору через трей-меню) появляется окно (resizable) с исходным текстом из буфера обмена и с его переводом. По умолчанию, если в исходном тексте присутствует кириллица, переводит с русского на английский, если нет, то язык исходного текста определяется автоматически и переводится на русский. В окне можно сменить языки источника и перевода. В том же окне можно осуществить новый перевод, изменив исходный текст вручную и нажав кнопку "Перевод" или "Enter" на клавиатуре.

Текст в любом из полей Edit можно озвучить, нажав кнопку "Play-Pause". Сначала ищется выделенный текст, при его отсутствии озвучивается весь. После загрузки mp3 файла (или нескольких, если текст большой) активируется кнопка "Stop" и начинается озвучивание. После проигрывания кнопка Stop деактивируется. Озвучка есть не для всех языков. В таком случае кнопка Stop активируется на короткое время и сразу деактивируется без озвучки.

Окно закрывается по Esc (если активно) или по нажатию на кнопку OK.

Основной вариант последнего перевода можно вставить в активное окно по горячей клавише Ctrl+Alt+V.

Возможности:

  • Настройки скрипта через трей-меню.

  • Открытие пустого окна по двойному клику по иконке в трее для ввода текста вручную.

  • Скрипт запоминает положение окна на экране, если разрешено много окон, запоминает положение первого появившегося.

  • «Интеллектуальный» ресайзинг окна: тянем за верх — изменяется размер верхнего поля Edit, за низ — нижнего.

  • Возможность запомнить и сохранить постоянный размер окна и полей Edit, независимо от размера текста.

  • Возможность менять размер шрифта в полях Edit по отдельности. Для этого кликаем по нужному полю, нажимаем Ctrl и вращаем колесо мыши (так же, как это делается в браузерах).

  • Автоматическое переключение раскладки при фокусе на верхнем поле Edit в зависимости от языка-источника. Также переключение раскладки на русскую при фокусе на DropDownList для выбора языка с клавиатуры по первой букве.

  • Смена местами языков источника и перевода по кнопке.

  • Вставка последнего перевода по горячей клавише Ctrl + Alt + V.

Тема для обсуждения

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

2 (изменено: teadrinker, 2019-10-20 02:37:48)

Re: AHK: Онлайн переводчик

Исправлены устаревшие параметры в Http-запросе.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder