; 纠错插入修改
insertchar(str,char,ByRef pos){
	If (!pos)
		Return str . char
	Else
		Return SubStr(str,1,pos-1) char SubStr(str,pos), pos+=1
}
delchar(str,ByRef pos, del:=0){
	If (del){
		If (pos>0)
			Return SubStr(str,1,pos-1) SubStr(str,pos+1)
		Else
			Return str
	} Else If (pos)
		Return SubStr(str,1,Max(0,pos-2)) SubStr(str,pos), pos:=Max(pos-1,1)
	Else
		Return SubStr(str,1,-1)
}
insertcaret(str,pos){
	global func_key, srf_all_Input
	res:=pos=1?"|":"",index:=0
	Loop, Parse, str
	{
		t:=SubStr(srf_all_Input,index+1,1), t:=t="\"?" ":t
		If !(A_LoopField~="i)[a-z]")&&(t!=A_LoopField){
			res .= A_LoopField
			Continue
		}
		index++, res .= A_LoopField (index=pos-1?"|":"")
	}
	Return res
}
; 上屏合一
select_for_num(num){
	local Match, tarr, ThisHotkey
	If InStr(srf_all_Input,func_key){
		If (srf_func_table[modeMatch.Value[1], "Name"]="get_hotstring")||(srf_all_Input~="^" func_key "[a-z]+$"){
			srf_HotStringSelect(Function_for_select, num)
		} Else If !(A_ThisHotkey~="\d")||(srf_func_table[modeMatch.Value[1], "Name"]="get_function")||!(modeMatch.Value[1]=""||srf_Default_Func[srf_func_table[modeMatch.Value[1], "Name"],2]~="\d"){
			srf_RunSelect(Function_for_select, num)
		} Else {
			If (num=".")&&(InStr(srf_all_Input, ".")||srf_all_Input=func_key)
				Return
			If GetKeyState("Shift", "P")
				tarr:=["!","@","#","$","%","^","&","*","("], tarr[0]:=")", srf_all_Input:=insertchar(srf_all_Input,tarr[num],insertpos)
			Else
				srf_all_Input:=insertchar(srf_all_Input,num,insertpos)
			Gosub srf_tooltip
		}
	} Else If (num=1&&srf_symbol[srf_all_Input,2-(EnSymbol||Englishmode)]) {
		RegExMatch(srf_symbol[srf_all_Input,2-(EnSymbol||Englishmode)],"i)\{[a-z]+\}",Match)
		SendInput(StrReplace(srf_symbol[srf_all_Input,2-(EnSymbol||Englishmode)],Match), SendDelaymode)
		If (Match)
			SendInput, %Match%
		Gosub srf_value_off
	} Else If GetKeyState("Shift", "P"){
		ThisHotkey:=LTrim(A_ThisHotkey,"~")
		If (ThisHotkey~="^[14690]$"){
			srf_select(1,IsPinyin), tarr:={0:")",1:"!",4:"$",6:"^",9:"("}
			RegExMatch(srf_symbol[tarr[ThisHotkey],(srf_mode&&!(EnSymbol||Englishmode)&&!GetKeyState("CapsLock", "T"))+1],"i)\{[a-z]+\}",Match)
			SendInput(StrReplace(srf_symbol[tarr[ThisHotkey],(srf_mode&&!(EnSymbol||Englishmode)&&!GetKeyState("CapsLock", "T"))+1],Match), SendDelaymode)
			If (Match)
				SendInput, %Match%
		} Else If (ThisHotkey~="^\d$"){
			tarr:={0:")",1:"!",4:"$",6:"^",9:"("}
		} Else
			srf_select(num,IsPinyin)
	} Else
		srf_select(num,IsPinyin)
}
; 输入上屏
srf_select(list_num:=1,mode:=0,key:="",ret:=0){
	global
	local selectvalue, _SQL, Result, index, yhnum, tt, Match, srf_all_Input2, bianma, TableName, weight
	list_num:=list_num?list_num:10
	If (key){
		selectvalue:=[]
		RegExMatch(jichu_for_select_Array[1,1] "'","iO)([a-z]+'){" list_num "}", Match)
		selectvalue[1]:=Trim(Match.Value[0],"'"), selectvalue[0]:="pinyin"
		If (selectvalue[1]){
			selectvalue[2]:=SubStr(jichu_for_select_Array[1,2],1,list_num)
			SendInput(SubStr(jichu_for_select_Array[1,valueindex],1,list_num), SendDelaymode), hasCaretPos:=0
			Function_for_select:=[], hotstring_for_select:=[], jichu_for_select_Array:=[], save_field_array:=[]
			Goto dwcz
		} Else
			list_num:=1
	}
	If (list_num>ListNum)||(list_num=0)
		Return
	selectvalue:=jichu_for_select_Array[list_num+ListNum*waitnum], tt:=StrSplit(selectvalue[0],"|")
	If Trim(selectvalue[2])!=""
		SendInput(selectvalue[valueindex], tt[3]?tt[3]:SendDelaymode), hasCaretPos:=0
	Else If (list_num=1){
		SendInput(srf_all_Input, SendDelaymode), hasCaretPos:=0
		Return
	} Else
		Return
	If ((Wordfrequency)&&selectvalue[1]&&(Learning*(Learnfg+1)<2)&&!mode){
		TableName:=(shurulei="pinyin"?"pinyin":Inputscheme)
		If !(fixedword&&(selectvalue[2]~="^.$")){
			If (decfre&&TableName="pinyin"&&weight&&selectvalue[2]~="..+?")
				DB.Exec(_SQL:=RegExReplace(SQL_buffer[selectvalue[-1]], "SELECT .+(WHERE .+?)(ORDER .+)?$", "UPDATE 'main'.'pinyin' SET weight = max(0,weight-5) $1;"))
				; DB.Exec(_SQL:=RegExReplace(SQL_buffer[selectvalue[-1]], "SELECT .+(WHERE .+?)(ORDER .+)?$", "UPDATE 'main'.'pinyin' SET weight = max(0,weight-5) $1AND weight < " weight ";"))
			If (tt[2]>1), bianma:=StrReplace(selectvalue[1], "'", "''"){
				weight:=Tofirst?Round(selectvalue[4]+1):Round(selectvalue[3]+1+(selectvalue[4]-selectvalue[3])/(tt[2]<5?Max(tt[2]-1,1):(2*tt[2]-6)/(tt[2]-4)))
				DB.Exec(_SQL:="UPDATE 'main'.'" TableName "' SET weight = " weight " WHERE " (TableName="pinyin"?"jp='" RegExReplace(bianma,"([a-z])[a-z]*","$1") "' AND":"") " key = '" bianma "' AND value = '" selectvalue[2] "';")
			} Else If (tt[2]=1), weight:=selectvalue[4]+1
				DB.Exec(_SQL:="UPDATE 'main'.'" TableName "' SET weight = weight+1 WHERE " (TableName="pinyin"?"jp='" RegExReplace(bianma,"([a-z])[a-z]*","$1") "' AND":"") " key = '" bianma "' AND value = '" selectvalue[2] "';")
			If (DB.ErrorCode)
				DebugOutput((A_ThisLabel?"标签:" A_ThisLabel "|":A_ThisFunc?"函数:" A_ThisFunc "|":"") "消息: " DB.ErrorMsg "|SQL: " DB.SQL, DebugLevel)
		}
	}
	dwcz:
	srf_last_input[1, 2] .= selectvalue[2], srf_last_input[1, 1] .= (srf_last_input[1, 1]?"'":"") selectvalue[1]
	, srf_last_input[1, 0] .= (srf_last_input[1, 0]?"'":"") selectvalue[-1], Learnfg+=Learning
	If (selectvalue[1]="")||(tt[1]="customs"){
		If (selectvalue[1]="")
			Learnfg:=0, srf_last_input[1, 1]:=RTrim(srf_last_input[1, 1],"'")
		Gosub srf_value_off
		Return
	} Else If (Inputscheme~="sp$|pinyin"){
		If (SaveCloud)&&(selectvalue[0]="<Cloud>|-1")&&(StrLen(selectvalue[2])<9)
			DB.Exec("INSERT INTO 'main'.'pinyin' VALUES (""" RegExReplace(selectvalue[1],"([a-z])[a-z]*","$1") """,""" selectvalue[1] """,'" selectvalue[2] "'," (SQL_buffer[selectvalue[1]]?"ifnull((SELECT max(weight)+1 FROM 'pinyin' " RegExReplace(SQL_buffer[selectvalue[1]], "^.+?(WHERE jp=.+)(ORDER BY|UNION ALL).+", "$1") "),5000));":"5000);"))
		If (index:=RegExMatch(srf_all_Input_tooltip,RegExReplace(RegExReplace(RegExReplace(selectvalue[1], "i)([a-z]h?)([aeginouv]+)", "$1($2)?"), "([csz])h?", "$1h?"),"([aoei]n)g?","$1g?"))){
			StrReplace(selectvalue[1] "'", "'", "", yhnum)
			index:=InStr(srf_all_Input_tooltip "'", "'", , index, yhnum)
			StrReplace(SubStr(srf_all_Input_tooltip "'",1,index), "'", "", yhnum)
			index:=InStr(LTrim(srf_all_Input_raw_for_trim,"'"), "'", , 1, yhnum)
			srf_all_Input:=RegExReplace(srf_all_Input, "i)^" StrReplace(SubStr(LTrim(srf_all_Input_raw_for_trim,"'"),1,index),"'","'?"))
			If (tfzm=""&&selectvalue[-2]!="")
				srf_all_Input:=RegExReplace(srf_all_Input, "i)" selectvalue[-2] " ?$")
			srf_all_Input:=LTrim(srf_all_Input,"\'")
			If (RTrim(srf_all_Input,"\' ")){
				jichu_for_select:=srf_all_Input_tooltip:=ToolTipText:=tfzm:=""
				save_field_array.RemoveAt(1)
				hasCaretPos:=waitnum:=0, Function_for_select:=[], hotstring_for_select:=[], jichu_for_select_Array:=[]
				Gosub srf_tooltip
				If (ToolTipStyle=2)&&(jichu_for_select_Array[1,0]="pinyin"){
					waitspace:=1
					SetTimer, waitspace, 200
				}
				Return
			}
		}
	} Else If (mode){
		If (index:=RegExMatch(srf_all_Input_tooltip,RegExReplace(RegExReplace(RegExReplace(selectvalue[1], "i)([a-z]h?)([aeginouv]+)", "$1($2)?"), "([csz])h?", "$1h?"),"([aoei]n)g?","$1g?"))){
			StrReplace(selectvalue[1] "'", "'", "", yhnum)
			index:=InStr(srf_all_Input_tooltip "'", "'", , index, yhnum)
			StrReplace(SubStr(srf_all_Input_tooltip "'",1,index), "'", "", yhnum)
			If (mode=1)
				RegExMatch(srf_all_Input, "O)^(" lspy_key ")(.+)", Match)
			index:=InStr(LTrim(srf_all_Input_raw_for_trim,"'"), "'", , 1, yhnum)
			srf_all_Input:=RegExReplace(Match.Value[2], "i)^" StrReplace(SubStr(LTrim(srf_all_Input_raw_for_trim,"'"),1,index),"'","'?"))
			srf_all_Input:=LTrim(srf_all_Input,"\'")
			If (RTrim(srf_all_Input,"\' ")){
				jichu_for_select:=srf_all_Input_tooltip:=ToolTipText:="", srf_all_Input:=Match.Value[1] srf_all_Input
				hasCaretPos:=waitnum:=0, Function_for_select:=[], hotstring_for_select:=[], jichu_for_select_Array:=[]
				save_field_array.RemoveAt(1)
				Gosub srf_tooltip
				Return
			}
		}
	} Else {
		If InStr(srf_all_Input,"``"){
			If (srf_all_Input:=RegExReplace(srf_all_Input,"^``?[a-z]+``?")){
				srf_all_Input:="``" srf_all_Input
				Gosub srf_tooltip
				Return
			}
			Gosub srf_value_off
		}
		If (selectvalue[-2]!="")
			srf_all_Input:=RegExReplace(srf_all_Input, "i)" selectvalue[-2] " ?$")
		If (srf_all_Input~="^" selectvalue[1])&&(srf_all_Input:=RegExReplace(srf_all_Input, "^" selectvalue[1])){
			Gosub srf_tooltip
			Return
		}
	}
	If ret
		Return
	Gosub srf_value_off
	If Imagine&&(Inputscheme~="pinyin|sp$"){
		DB.GetTable("SELECT NULL,substr(value," (StrSplit(tvar:=RegExReplace(srf_last_input[2, 1], "([a-z])[a-z]*", "$1"),"'").Length()+1) ") FROM 'pinyin' WHERE jp>=""" tvar "'a"" AND jp<""" tvar "'{"" AND value like """ srf_last_input[2, 2] "%"" ORDER BY weight DESC LIMIT 30",Result)
		If (Result.RowCount){
			jichu_for_select_Array:=Result.Rows, srf_inputing:=1, jichu_for_select_Array[1,0]:="lianxiang"
			Gosub srf_tooltip_fanye
			SetTimer, removelianxiang, -1000
		}
	}
	Return
}
removelianxiang:
	If (srf_all_Input||InStr(StrReplace(fanyefg,","), A_ThisHotkey))
		Return
	jichu_for_select_Array:=[], history_field_array:=[]
	srf_inputing:=Learnfg:=0, ToolTipText:=srf_all_Input:=srf_for_select:="", srf_for_select_obj:="", hasCaretPos:=waitnum:=IsPinyin:=0
	If (ToolTipStyle=1)
		ToolTip(1)
	Else
		; GdipText("")	
		DrawHXGUI("", "")
Return
; 输入法快捷键调位置
srf_SetFirst(list_num){
	global
	local selectvalue, _SQL, index, tt, presstime:=A_TickCount, tarr, pos:=1, tpos, yhnum, tstr, maxweight, Match, Result
	list_num:=list_num?list_num:10
	selectvalue:=jichu_for_select_Array[index:=list_num+ListNum*waitnum]
	If (list_num>ListNum)||((tt:=StrSplit(selectvalue[0],"|"))[2]<1)||(selectvalue[2]="")||(tt[1]~="^(hotstrings|functions|English|symbol|<Cloud>|)$")
		Return
	KeyWait, % Mod(list_num, 10), T0.3
	If (A_TickCount-presstime>290)||(tt[1]="customs"){
		Suspend, On
		Gui +OwnDialogs
		OnMessage(0x18, "SetWindowsAlwaysOnTop")
		If (tt[1]="customs")
			InputBox, pos, 输入调整后的位置, % "词条固定在第" selectvalue[3] "位`n输入整数调整至指定位置", , 2*A_ScreenDPI, 1.4*A_ScreenDPI
		Else If (tt[1]="pinyin"&&selectvalue[-2])
			InputBox, pos, 在自定义短语中新建词条, % "词条在" tt[1] " 第" tt[2] "位`n输入整数固定在指定位置", , 2*A_ScreenDPI, 1.4*A_ScreenDPI
		Else
			InputBox, pos, 输入调整后的位置, % "词条在" tt[1] " 第" tt[2] "位`n输入整数调整至指定位置", , 2*A_ScreenDPI, 1.4*A_ScreenDPI
		Suspend, Off
		If (ErrorLevel)
			Return
		If (pos~="^\d{1,3}$")&&(selectvalue[-1]){
			If (tt[1]="customs"){
				DB.GetTable("SELECT key FROM 'extend'.'customs' WHERE key='" selectvalue[-1] "' AND comment LIKE '" Format("{:03}", pos) "%' LIMIT 1",Result)
				If (Result.Rows[1,1]){
					If (pos>selectvalue[3])
						DB.Exec("UPDATE 'extend'.'customs' SET comment=substr('00'||(substr(comment,1,3)-1),-3)||substr(comment,4) WHERE key='" selectvalue[-1] "' AND comment>='" Format("{:03}", selectvalue[3]) "' AND comment<'" Format("{:03}", pos+1) "'")
					Else If (pos<selectvalue[3])
						DB.Exec("UPDATE 'extend'.'customs' SET comment=substr('00'||(substr(comment,1,3)+1),-3)||substr(comment,4) WHERE key='" selectvalue[-1] "' AND comment<'" Format("{:03}", selectvalue[3]+1) "' AND comment>='" Format("{:03}", pos) "'")
				}
				; DB.Exec("UPDATE 'extend'.'customs' SET comment='" (Format("{:03}", pos) StrSplit(selectvalue[0], "|")[3]) "' WHERE key='" selectvalue[-1] "' AND value='" StrReplace(selectvalue[1],"'","''") "'")
				DB.Exec("UPDATE 'extend'.'customs' SET comment='" (Format("{:03}", pos) RegExReplace(selectvalue[4],"^\d+")) "' WHERE key='" selectvalue[-1] "' AND value='" StrReplace(selectvalue[1],"'","''") "'")
				srf_all_Input_history:=""
				Gosub srf_tooltip
				Return
			} Else If selectvalue[-2]&&(tt[1]="pinyin"){
				tpos:=RegExMatch(srf_all_Input_tooltip, selectvalue[-1])
				StrReplace(SubStr(srf_all_Input_tooltip,1,tpos-1),"'", , yhnum)
				tpos:=InStr(srf_all_Input_raw_for_trim, "'", , 1, yhnum+1)
				tstr:=StrReplace(SubStr(srf_all_Input_raw_for_trim,tpos+1,InStr(srf_all_Input_raw_for_trim, "'", , 1, yhnum+1+StrSplit(selectvalue[-1], "'").Length())-tpos-1),"'") selectvalue[-2]
				If DB.GetTable("SELECT comment FROM 'extend'.'customs' WHERE key='" tstr "' AND value='" StrReplace(selectvalue[2],"'","''") "' LIMIT 1",Result){
					If (Result.Rows[1,1]){
						RegExMatch(Result.Rows[1,1], "O)(\d+)(\{.*\})?",Match)
						DB.GetTable("SELECT key FROM 'extend'.'customs' WHERE key='" tstr "' AND comment LIKE '" Format("{:03}", pos) "%' LIMIT 1",Result)
						If (Result.Rows[1,1]){
							If (pos>Match.Value[1])
								DB.Exec("UPDATE 'extend'.'customs' SET comment=substr('00'||(substr(comment,1,3)-1),-3)||substr(comment,4) WHERE key='" tstr "' AND comment>='" Format("{:03}", Match.Value[1]) "' AND comment<'" Format("{:03}", pos+1) "'")
							Else If (pos<Match.Value[1])
								DB.Exec("UPDATE 'extend'.'customs' SET comment=substr('00'||(substr(comment,1,3)+1),-3)||substr(comment,4) WHERE key='" tstr "' AND comment<'" Format("{:03}", Match.Value[1]+1) "' AND comment>='" Format("{:03}", pos) "'")
						}
						DB.Exec("UPDATE 'extend'.'customs' SET comment='" (Format("{:03}", pos) Match.Value[2]) "' WHERE key='" tstr "' AND value='" StrReplace(selectvalue[2],"'","''") "'")
					} Else {
						DB.GetTable("SELECT key FROM 'extend'.'customs' WHERE key='" tstr "' AND comment LIKE '" Format("{:03}", pos) "%' LIMIT 1",Result)
						If (Result.Rows[1,1])
							DB.Exec("UPDATE 'extend'.'customs' SET comment=substr('00'||(substr(comment,1,3)+1),-3)||substr(comment,4) WHERE key='" tstr "' AND comment>=""" Format("{:03}", pos) """")
						DB.Exec("INSERT INTO 'extend'.'customs' VALUES('" tstr "','" selectvalue[2] "','" Format("{:03}", pos) "')")
					}
					srf_all_Input_history:=""
					Gosub srf_tooltip
				}
				If (DB.ErrorCode)
					DebugOutput((A_ThisLabel?"标签:" A_ThisLabel "|":A_ThisFunc?"函数:" A_ThisFunc "|":"") "消息: " DB.ErrorMsg "|SQL: " DB.SQL, DebugLevel)
				Return
			}
			pos:=pos?pos:1
		} Else
			Return
	}
	If (pos=tt[2])
		Return
	Else {
		If (pos=1){
			DB.Exec("UPDATE 'main'.'" tt[1] "' SET weight=" selectvalue[4]+1 " WHERE " (tt[1]="pinyin"?"jp=""" RegExReplace(selectvalue[1],"([a-z])[a-z]*","$1") """ AND ":"") "key='" StrReplace(selectvalue[1],"'","''") "' AND value=""" selectvalue[2] """")
		} Else If (pos>=2){
			_SQL:=RegExReplace(SQL_buffer[selectvalue[-1]], "i)ORDER BY.+", "ORDER BY weight DESC"), pos+=(pos>tt[2]?1:0)
			DB.GetTable(RegExReplace(_SQL,"i)^SELECT (.+) FROM","SELECT weight FROM") " LIMIT " (pos-2) ",2",Result)
			If (Result.RowCount=2){
				If (Result.Rows[1,1]-Result.Rows[2,1]<2)
					DB.Exec("UPDATE 'main'.'" tt[1] "' SET weight=weight+" (2+Result.Rows[2,1]-Result.Rows[1,1]) " WHERE ROWID IN (" RegExReplace(_SQL,"i)^SELECT (.+) FROM","SELECT ROWID FROM") " LIMIT " (pos-1) ")")
				DB.Exec("UPDATE 'main'.'" tt[1] "' SET weight=" Result.Rows[2,1]+1 " WHERE " (tt[1]="pinyin"?"jp=""" RegExReplace(selectvalue[1],"([a-z])[a-z]*","$1") """ AND ":"") "key='" StrReplace(selectvalue[1],"'","''") "' AND value=""" selectvalue[2] """")
			} Else If (Result.RowCount=1){
				DB.Exec("UPDATE 'main'.'" tt[1] "' SET weight=weight+1 WHERE ROWID IN (" RegExReplace(_SQL,"i)^SELECT (.+) FROM","SELECT ROWID FROM") " LIMIT " (pos-1) ")")
				DB.Exec("UPDATE 'main'.'" tt[1] "' SET weight=" Result.Rows[1,1] " WHERE " (tt[1]="pinyin"?"jp=""" RegExReplace(selectvalue[1],"([a-z])[a-z]*","$1") """ AND ":"") "key='" StrReplace(selectvalue[1],"'","''") "' AND value=""" selectvalue[2] """")
			} Else {
				DB.GetTable(RegExReplace(_SQL,"i)^SELECT (.+) FROM","SELECT min(weight) FROM"),Result)
				If (Result.Rows[1,1]!="")&&(Result.Rows[1,1]<2)
					DB.Exec("UPDATE 'main'.'" tt[1] "' SET weight=weight+" (2-Result.Rows[1,1]) " WHERE ROWID IN (" RegExReplace(_SQL,"i)^SELECT (.+) FROM","SELECT ROWID FROM") " LIMIT " (pos-1) ")")
				DB.Exec("UPDATE 'main'.'" tt[1] "' SET weight=1 WHERE " (tt[1]="pinyin"?"jp=""" RegExReplace(selectvalue[1],"([a-z])[a-z]*","$1") """ AND ":"") "key='" StrReplace(selectvalue[1],"'","''") "' AND value=""" selectvalue[2] """")
			}
		}
		srf_all_Input_history:="", history_field_array.Delete(selectvalue[-1]), save_field_array.RemoveAt(1), jichu_for_select_Array:=[]
		Gosub srf_tooltip
		If (DB.ErrorCode)
			DebugOutput((A_ThisLabel?"标签:" A_ThisLabel "|":A_ThisFunc?"函数:" A_ThisFunc "|":"") "消息: " DB.ErrorMsg "|SQL: " DB.SQL, DebugLevel)
	}
}

; 输入法快捷键删词
srf_delete(list_num){
	global
	local selectvalue, tt, _SQL
	list_num:=list_num?list_num:10
	selectvalue:=jichu_for_select_Array[list_num+ListNum*waitnum]
	If (list_num>ListNum)||((tt:=StrSplit(selectvalue[0],"|"))[2]<0&&tt[1]!="customs")||(selectvalue[2]="")
		Return
	If (tt[1]="pinyin")
		_SQL:="DELETE FROM 'main'.'pinyin' WHERE jp=""" RegExReplace(selectvalue[1],"([a-z])[a-z]*","$1") """ AND key='" StrReplace(selectvalue[1],"'","''") "' AND value='" StrReplace(selectvalue[2],"'","''") "';"
	Else If (tt[1]="customs")
		_SQL:="DELETE FROM 'extend'.'customs' WHERE key='" selectvalue[-1] "' AND value='" StrReplace(selectvalue[2],"'","''") "';"
	Else
		_SQL:="DELETE FROM 'main'.'" tt[1] "' WHERE key='" selectvalue[1] "' AND value='" StrReplace(selectvalue[2],"'","''") "';"
	If DB.Exec(_SQL){
		jichu_for_select_Array.RemoveAt(list_num+ListNum*waitnum)
		If (ListNum*waitnum+1>jichu_for_select_Array.Length())&&(waitnum>0)
			waitnum-=1
		Gosub srf_tooltip_fanye
	} Else
		DebugOutput((A_ThisLabel?"标签:" A_ThisLabel "|":A_ThisFunc?"函数:" A_ThisFunc "|":"") "消息: " DB.ErrorMsg "|SQL: " DB.SQL, DebugLevel)
}
customs_alterpos(DB,key,value,pos,alterpos,bz:=""){
	DB.GetTable("SELECT key FROM 'extend'.'customs' WHERE key='" key "' AND comment LIKE """ Format("{:03}", alterpos) "%"" LIMIT 1",Result)
	If (Result.Rows[1,1]){
		If (alterpos>pos)
			DB.Exec("UPDATE 'extend'.'customs' SET comment=substr('00'||(substr(comment,1,3)-1),-3)||substr(comment,4) WHERE key='" key "' AND comment>='" Format("{:03}", pos) "' AND comment<'" Format("{:03}", alterpos+1) "'")
		Else If (alterpos<pos)
			DB.Exec("UPDATE 'extend'.'customs' SET comment=substr('00'||(substr(comment,1,3)+1),-3)||substr(comment,4) WHERE key='" key "' AND comment<'" Format("{:03}", pos+1) "' AND comment>='" Format("{:03}", alterpos) "'")
	}
	If !DB.Exec("UPDATE 'extend'.'customs' SET comment='" (Format("{:03}", alterpos) bz "' WHERE key='" key "' AND value='" StrReplace(value,"'","''") "'"))
		DebugOutput((A_ThisLabel?"标签:" A_ThisLabel "|":A_ThisFunc?"函数:" A_ThisFunc "|":"") "消息: " DB.ErrorMsg "|SQL: " DB.SQL, DebugLevel)
}
; 输入法快捷键造词
srf_create(key:=""){
	global YzPID, Inputscheme, GUIFont
	static dy:=0, tkey:="", buffer, lxzc:=0
	If WinExist("快捷造词 Enter确定 Esc退出 ahk_pid" YzPID){
		WinActivate, 快捷造词 Enter确定 Esc退出 ahk_pid%YzPID%
		Return
	}
	dy:=key?1:dy, tkey:=key
	Gosub srf_value_off
	Gui, create:+AlwaysOnTop -MinimizeBox
	Gui, create:Margin, 15, 15
	Gui, create:Font, s12, %GUIFont%
	Gui, create:Add, Text, , 词条：
	Gui, create:Add, Edit, x+0 yp w400 -Multi r1 ggetkey, %Clipboard%
	Gui, create:Add, Text, xm, 编码：
	Gui, create:Add, Edit, x+0 yp w400 -Multi r1 gsetkey, %key%
	Gui, create:Add, Text, xm, 位置：
	Gui, create:Add, Edit, x+0 yp w60 Limit2 Number
	Gui, create:Add, UpDown, Range0-99, 1
	Gui, create:Add, Checkbox, x+30 yp gzdydy Center Checked%dy%, 自定义短语`n(固定位置)
	Gui, create:Add, DropDownList, % "x+20 yp w80 AltSubmit Hidden" !dy, 文本||按键|函数
	Gui, create:Add, Checkbox, x+20 yp Checked%lxzc%, 继续造词
	Gui, create:Show, , 快捷造词 Enter确定 Esc退出
	Gosub getkey
	Hotkey, IfWinActive, 快捷造词 Enter确定 Esc退出 ahk_pid%YzPID%
	Hotkey, Enter, createButton确定
	Hotkey, NumpadEnter, createButton确定
	Hotkey, If
	Return
	zdydy:
		GuiControlGet, dy, , Button1
		If (dy)
			GuiControl, Show, ComboBox1
		Else {
			GuiControl, Hide, ComboBox1
			Gosub getkey
		}
	Return
	getkey:
		Gui, create:Default
		GuiControlGet, buffer, , Edit1
		If (A_GuiControl=buffer)
			SetTimer, getkey_, -300
		Else
			Gosub getkey_
	Return
	getkey_:
		Critical, Off
		Gui, create:Default
		GuiControlGet, dy, , Button1
		If (tkey=""&&!dy){
			cikuname:=Inputscheme~="pinyin|sp$"?"pinyin":Inputscheme~="^(wubi|五笔)86$"?"wubi86":Inputscheme~="^(wubi|五笔)98$"?"wubi98":""
			If (cikuname){
				GuiControl, -g, Edit2
				GuiControl, , Edit2, % StrReplace(RegExReplace(StrSplit(IMEConverter(cikuname,buffer),"=","'")[1],"[^a-z']"),"''","'")
				GuiControl, +gsetkey, Edit2
			}
		}
	Return
	setkey:
		tkey:=A_GuiControl
		Gosub getkey_
	Return
	createButton确定:
	Gui, create:Default
	Gui create:+OwnDialogs
	GuiControlGet, value, , Edit1
	GuiControlGet, key, , Edit2
	GuiControlGet, pos, , Edit3
	GuiControlGet, dy, , Button1
	GuiControlGet, ty, , ComboBox1
	GuiControlGet, lxzc, , Button2
	cikuname:=(dy?"customs":(Inputscheme~="pinyin|sp$"?"pinyin":Inputscheme))
	value:=Trim(value," "), key:=Trim(dy||cikuname!="pinyin"?StrReplace(key,"'"):key)
	If (value=""){
		GuiControl, Focus, Edit1
		ToolTip 未输入词条！
		SetTimer, ToolTipOff, -1000
		Return
	} Else If (key=""){
		GuiControl, Focus, Edit2
		ToolTip 未输入编码！
		SetTimer, ToolTipOff, -1000
		Return
	} Else If (pos=""){
		GuiControl, Focus, Edit3
		ToolTip 未指定位置！
		SetTimer, ToolTipOff, -1000
		Return
	}
	pos:=(dy?pos (ty=2?"{}":ty=3?"{Func}":""):pos)
	srf_create_(cikuname,key,value,pos)
	If (lxzc){
		GuiControl, , Edit1
		GuiControl, , Edit2
		GuiControl, Focus, Edit1
	} Else
		Gosub createGuiClose
	Return
	createGuiEscape:
	createGuiClose:
	Gui, create:Destroy
	Return
}
srf_create_(cikuname,key,value,pos){
	global Inputscheme, DB
	If (key=""||value=""||cikuname=""||pos="")
		Return
	Else {
		If (cikuname="customs"){
			DB.Exec("DELETE FROM " (cikuname="customs"?"'extend'.":"'main'.") "'" cikuname "' WHERE " (cikuname="pinyin"?"jp=""" RegExReplace(key, "([a-z])[a-z]*", "$1") """ AND ":"") "key='" StrReplace(key,"'","''") "' AND value='" StrReplace(value,"'","''") "'")
			RegExMatch(pos,"\{.*\}", Match), pos:=StrReplace(pos, Match)
			DB.GetTable("SELECT key FROM 'extend'.'customs' WHERE key='" key "' AND comment LIKE '" Format("{:03}", pos) "%' LIMIT 1",Result)
			If (Result.Rows[1,1])
				DB.Exec("UPDATE 'extend'.'customs' SET comment=substr('00'||(substr(comment,1,3)+1),-3)||substr(comment,4) WHERE key='" key "' AND comment>='" Format("{:03}", pos) "'")
			If DB.Exec("INSERT INTO 'extend'.'customs' VALUES ('" key "','" StrReplace(value,"'","''") "','" Format("{:03}", pos) Match "');"){
				ToolTip % "新建词条成功`n编码：" key "`n词条：" value "`n词库：自定义短语"
				SetTimer, ToolTipOff, -5000
			} Else
				DebugOutput((A_ThisLabel?"标签:" A_ThisLabel "|":A_ThisFunc?"函数:" A_ThisFunc "|":"") "消息: " DB.ErrorMsg "|SQL: " DB.SQL, DebugLevel)
		} Else {
			pos:=Max(pos,1)
			DB.GetTable("SELECT (SELECT COUNT(*) FROM pinyin WHERE " (cikuname="pinyin"?"jp = TEMP.jp AND ":"") "key = TEMP.key AND weight > TEMP.weight) + (SELECT COUNT(*) FROM pinyin WHERE " (cikuname="pinyin"?"jp = TEMP.jp AND ":"") "key = TEMP.key AND weight = TEMP.weight AND ROWID <= TEMP.ROWID) FROM pinyin TEMP WHERE " (cikuname="pinyin"?"jp = '" RegExReplace(StrReplace(key,"'","''"),"([a-z])[a-z]*","$1") "' AND ":"") "key = '" StrReplace(key,"'","''") "' AND value = '" value "'",Result), oldpos:=Result.Rows[1,1]
			If (oldpos!="")
				pos+=(pos>oldpos?1:0)
			Else If (pos=oldpos)
				Return
			If (pos=1){
				DB.GetTable("SELECT max(weight)+1 FROM '" cikuname "' WHERE " (cikuname="pinyin"?"jp=""" RegExReplace(key, "([a-z])[a-z]*", "$1") """ AND ":"") "key='" StrReplace(key,"'","''") "'",Result)
				weight:=(Result.Rows[1,1]?Result.Rows[1,1]:5000)
			} Else If (pos>=2){
				DB.GetTable("SELECT weight FROM '" cikuname "' WHERE " (cikuname="pinyin"?"jp=""" RegExReplace(key, "([a-z])[a-z]*", "$1") """ AND ":"") "key='" StrReplace(key,"'","''") "' ORDER BY weight DESC LIMIT " (pos-2) ",2",Result)
				If (Result.RowCount=2){
					If (Result.Rows[1,1]-Result.Rows[2,1]<2)
						DB.Exec("UPDATE 'main'.'" cikuname "' SET weight=weight+" (2+Result.Rows[2,1]-Result.Rows[1,1]) " WHERE ROWID IN (SELECT ROWID FROM '" cikuname "' WHERE " (cikuname="pinyin"?"jp=""" RegExReplace(key, "([a-z])[a-z]*", "$1") """ AND ":"") "key='" StrReplace(key,"'","''") "' ORDER BY weight DESC LIMIT " (pos-1) ")")
					weight:=Result.Rows[2,1]+1
				} Else If (Result.RowCount=1){
					DB.Exec("UPDATE 'main'.'" cikuname "' SET weight=weight+1 WHERE ROWID IN (SELECT ROWID FROM '" cikuname "' WHERE " (cikuname="pinyin"?"jp=""" RegExReplace(key, "([a-z])[a-z]*", "$1") """ AND ":"") "key='" StrReplace(key,"'","''") "' ORDER BY weight DESC LIMIT " (pos-1) ")")
					weight:=Result.Rows[1,1]
				} Else {
					DB.GetTable("SELECT min(weight) FROM '" cikuname "' WHERE " (cikuname="pinyin"?"jp=""" RegExReplace(key, "([a-z])[a-z]*", "$1") """ AND ":"") "key='" StrReplace(key,"'","''") "'",Result)
					If (Result.Rows[1,1]="")
						weight:=5000
					Else
						weight:=Max(Result.Rows[1,1]-1,1)
				}
			}
			If (oldpos="")
				_SQL:="INSERT INTO 'main'.'" cikuname "' VALUES (" (cikuname="pinyin"?"""" RegExReplace(key, "([a-z])[a-z]*", "$1") """,":"") """" key """,'" StrReplace(value,"'","''") "','" weight "');"
			Else
				_SQL:="UPDATE 'main'.'" cikuname "' SET weight = '" weight "' WHERE " (cikuname="pinyin"?"jp = '" RegExReplace(StrReplace(key,"'","''"), "([a-z])[a-z]*", "$1") "' AND ":"") "key = '" StrReplace(key,"'","''") "' AND value = '" StrReplace(value,"'","''") "';"
			If DB.Exec(_SQL){
				ToolTip % "新建词条成功`n编码：" key "`n词条：" value "`n词库：" cikuname
				SetTimer, ToolTipOff, -5000
			} Else
				DebugOutput((A_ThisLabel?"标签:" A_ThisLabel "|":A_ThisFunc?"函数:" A_ThisFunc "|":"") "消息: " DB.ErrorMsg "|SQL: " DB.SQL, DebugLevel)
		}
	}
}

SetWindowsAlwaysOnTop(l,w,msg,Hwnd){
	WinSet, AlwaysOnTop, On, ahk_id%Hwnd%
	ControlGetText, txt, Button2
	If (txt="Cancel"){
		ControlSetText Button1, 确定
		ControlSetText Button2, 取消
	}
	OnMessage(msg, "")
}

restoreinput(str, fzm:=""){
	global srf_all_Input_tooltip, srf_all_Input_raw_for_trim
	tpos:=RegExMatch(srf_all_Input_tooltip, str)
	StrReplace(SubStr(srf_all_Input_tooltip,1,tpos-1),"'", , yhnum)
	tpos:=InStr(srf_all_Input_raw_for_trim, "'", , 1, yhnum+1)
	tstr:=StrReplace(SubStr(srf_all_Input_raw_for_trim,tpos+1,InStr(srf_all_Input_raw_for_trim, "'", , 1, yhnum+1+StrSplit(str, "'").Length())-tpos-1),"'")
	Return (tstr?tstr fzm:"")
}
; 魔法字符串上屏
srf_HotStringSelect(hotarr, index:=1){
	global ListNum, waitnum
	If (hotarr[index:=index?index+ListNum*waitnum:10+ListNum*waitnum, 1]="")
		Return
	Gosub srf_value_off
	SendInput(StrDeref(hotarr[index, 1]), hotarr[index, 0])
}
; 超级命令执行
srf_RunSelect(function, index:=1){
	; global SendDelaymode, srf_func_table, srf_label_table, DllFolder, ListNum, waitnum
	global
	local tarr, result, exePath, A_variate, errinfo, funcobj, OutDir, Value, tvar, key, Params
	If (function[index:=index?index+ListNum*waitnum:10+ListNum*waitnum, 1] . function[index, 3]="")
		Return
	Gosub srf_value_off
	Switch function[index, 0]
	{
		Case "{Script}":
			ExecScript(function[index, 1], function[index, 2])
		Case "{Value}":
			If function[index, 1]
				SendInput(function[index, 1], SendDelaymode)
		Case "{Fast}":
			SendInput(function[index, 1], "{Fast}")
		Case "{Label}":
			If IsLabel(function[index, 1])
				Gosub % function[index, 1]
			Else If IsFunc(tvar:=function[index, 1])&&(Func(tvar).MinParams=0)
				%tvar%()
		Case "{Func}":
			tarr:=StrSplit(Trim(function[index, 1],"/"), "/"), funcobj:=Func(tarr[1]), tarr.RemoveAt(1)
			If !IsObject(result:=FuncCall(funcobj,tarr*))
				SendInput(result, SendDelaymode)
		Case "{Mode}":
			Loop % function[index, 1].Length(){
				If (function[index, 1, A_Index, 1])
					YzIni[function[index, 1, A_Index, 1], function[index, 1, A_Index, 2]]:=function[index, 1, A_Index, 3]
				A_variate:=function[index, 1, A_Index, 2]
				If  (A_variate="shurulei"&&function[index, 1, A_Index, 3]!=shurulei&&InStr(function[index, 1, A_Index, 3] "|" shurulei, "pinyin")){
					tvar:=""
					For Value,Key In ["decfre","fixedword","Imagine","Learning","Tofirst","Wordfrequency"] {
						tvar .= %key%
						YzIni["Settings",key]:=%key%:=(SubStr(YzIni["Settings","Settingsbak"], A_Index, 1)?1:0)
					}
					YzIni["Settings","Settingsbak"]:=tvar Inputscheme
				}
				%A_variate%:=function[index, 1, A_Index, 3]
			}
		Case "{Plugin}":
			PluginCall(function[index, 1])
		Default:
			If (function[index, 0]~="i)\{Ev(erything)?\}")
				exePath:=exeQuery(function[index, 1], DllFolder "\Everything.dll")
			Else
				exePath:=StrDeref(function[index, 1])
			Params:=""
			Loop % srf_Func_Params.Length()-1
				Params .= A_Space srf_Func_Params[A_Index+1]
			SplitPath, exePath, , OutDir
			Try	Run, % exePath Params, %OutDir%
			Catch errinfo {
				ToolTip % exePath "`n" errinfo.Extra, A_CaretX + 10 , A_CaretY + 20
				SetTimer, ToolTipOff, -2000
			}
	}
}
; 内置函数
srf_FuncSelect(srf_Input){
	global
	local Match, funcobj, result, key, value, sel
	ToolTipText:=insertcaret(srf_Input,insertpos), srf_Func_Params:=[]
	If (srf_Input~="i)^" func_key "[^a-z]+"){
		If (srf_Input~="i)[^a-z][a-z]$"){
			sel:=Ord(SubStr(srf_Input,0))-96
			If (sel<=Function_for_select.Length()){
				select_for_num(sel)
				Return -2
			}
		}
		funcobj:=Func("mathmode"), Function_for_select:=[], srf_Func_Params:=[SubStr(srf_Input,2)]
	} Else If (srf_Input~="^" func_key "[a-z]+$"), Function_for_select:=[], srf_Func_Params:=StrSplit(Trim(srf_Input,func_key),func_key)
	{
		If (srf_Func_Params[1])
			Function_for_select:=get_symbol(DB,srf_Func_Params[1])
			If (Function_for_select[1,1]="")
				Function_for_select[1,3]:=Function_for_select[1,1]:=Trim(srf_input, func_key)
		Return 1
	} Else {
		If (funcobj:=srf_func_table[srf_Func_Params[1]]).Name
			srf_Func_Params.RemoveAt(1)
		Else {
			Function_for_select[1,0]:="{Value}", Function_for_select[1,3]:=Function_for_select[1,1]:=Trim(srf_input, func_key)
			Return 1
		}
	}
	If (srf_Func_Params.Length()>=funcobj.MinParams)
		result:=FuncCall(funcobj,srf_Func_Params*)
	If (result="")&&(srf_Func_Params.Length()=0){
		Function_for_select[1, 0]:="{Value}", Function_for_select[1,3]:=Function_for_select[1,1]:=Trim(srf_input, func_key)
		, srf_for_select:="1." Function_for_select[1,3], srf_for_select_obj:=[], srf_for_select_obj[1]:=Function_for_select[1,3]
		Return 1
	} Else If IsObject(result){
		If (result[1,0]="{Off}")
			Return -1
		Function_for_select:=result
		Return 1
	} Else {
		If (result="")
			result:=srf_Input
		Function_for_select[1, 0]:="{Value}", srf_for_select:="1." (Function_for_select[1, 3]:=Function_for_select[1, 1]:=result)
		, srf_for_select_obj:=[], srf_for_select_obj[1]:=Function_for_select[1,3]
	}
	Return 0
}
FuncCall(funcobj,params*){
	Return funcobj.Call(params*)
}
mathmode(str){
	result:=[]
	If (str~="^\d+(\.(\d+)?)?$"){
		arr:=StrSplit(str,"/")
		t:=n2c(arr*)
		Loop % t.Length()
			result.Push(t[A_Index])
		arr[2]:="r"
		result.Push({0:"{Value}",1:(t:=n2c(arr*)),3:t})
		arr[2]:="dr"
		result.Push({0:"{Value}",1:(t:=n2c(arr*)),3:t})
	}
	If RegExMatch(str,"O)^(\d{4}|\d\d|\d)\.(1[012]|0?[1-9])\.(3[01]|[12]\d|0?[0-9])$",mm){
		If (StrLen(mm.Value[1])<3){
			t:="yy年" (StrLen(mm.Value[2])=2?"M":"") "M月" (StrLen(mm.Value[3])=2?"d":"") "d日"
			arr:=date(Format("20{:02}{:02}{:02}",mm.Value[1],mm.Value[2],mm.Value[3]),0,t)
			If arr&&!IsObject(arr){
				result.Push({0:"{Value}",1:arr,3:arr})
				arr:=date(Format("20{:02}{:02}{:02}",mm.Value[1],mm.Value[2],mm.Value[3]),1,t), result.Push({0:"{Value}",1:arr,3:arr})
			}
		} Else {
			t:="yyyy年" (StrLen(mm.Value[2])=2?"M":"") "M月" (StrLen(mm.Value[3])=2?"d":"") "d日"
			arr:=date(mm.Value[1] Format("{:02}{:02}",mm.Value[2],mm.Value[3]),0,t)
			If arr&&!IsObject(arr){
				result.Push({0:"{Value}",1:arr,3:arr})
				arr:=date(mm.Value[1] Format("{:02}{:02}",mm.Value[2],mm.Value[3]),1,t), result.Push({0:"{Value}",1:arr,3:arr})
				arr:=lunar(mm.Value[1] Format("{:02}{:02}",mm.Value[2],mm.Value[3]),"农历YYYY年Md"), result.Push({0:"{Value}",1:arr,3:arr})
				arr:=lunar(mm.Value[1] Format("{:02}{:02}",mm.Value[2],mm.Value[3]),"YY年Md"), result.Push({0:"{Value}",1:arr,3:arr})
			}
		}
	} Else If RegExMatch(str,"O)^(1[0-2]|0?[1-9])\.(3[01]|[12]\d|0?[0-9])$",mm){
		t:=(StrLen(mm.Value[1])=2?"M":"") "M月" (StrLen(mm.Value[2])=2?"d":"") "d日"
		arr:=date(A_YYYY Format("{:02}{:02}",mm.Value[1],mm.Value[2]),0,t)
		If arr&&!IsObject(arr){
			result.Push({0:"{Value}",1:arr,3:arr})
			arr:=date(A_YYYY Format("{:02}{:02}",mm.Value[1],mm.Value[2]),1,t), result.Push({0:"{Value}",1:arr,3:arr})
		}
		If (mm.Value[2]<13){
			t:="yy年" (StrLen(mm.Value[2])=2?"M":"") "M月"
			arr:=date(Format("20{:02}{:02}",mm.Value[1],mm.Value[2]),0,t), result.Push({0:"{Value}",1:arr,3:arr})
			arr:=date(Format("20{:02}{:02}",mm.Value[1],mm.Value[2]),1,t), result.Push({0:"{Value}",1:arr,3:arr})
		}
	} Else If RegExMatch(str,"O)^(\d{4}|\d\d|\d)\.(1[012]|0?[1-9])$",mm){
		If (StrLen(mm.Value[1])<3){
			t:="yy年" (StrLen(mm.Value[2])=2?"M":"") "M月"
			arr:=date(Format("20{:02}{:02}",mm.Value[1],mm.Value[2]),0,t)
			If arr&&!IsObject(arr){
				result.Push({0:"{Value}",1:arr,3:arr})
				arr:=date(Format("20{:02}{:02}",mm.Value[1],mm.Value[2]),1,t), result.Push({0:"{Value}",1:arr,3:arr})
			}
		} Else {
			t:="yyyy年" (StrLen(mm.Value[2])=2?"M":"") "M月"
			arr:=date(mm.Value[1] Format("{:02}",mm.Value[2]),0,t)
			If arr&&!IsObject(arr){
				result.Push({0:"{Value}",1:arr,3:arr})
				arr:=date(mm.Value[1] Format("{:02}",mm.Value[2]),1,t), result.Push({0:"{Value}",1:arr,3:arr})
				arr:=lunar(mm.Value[1] Format("{:02}",mm.Value[2]),"农历YYYY年M"), result.Push({0:"{Value}",1:arr,3:arr})
				arr:=lunar(mm.Value[1] Format("{:02}",mm.Value[2]),"YY年M"), result.Push({0:"{Value}",1:arr,3:arr})
			}
		}
	} Else {
		If RegExMatch(str,"O)^(\d{4})/(\d\d?)(/\d\d?)?$",mm)
			t:=mm.Value[1] Format("{:02}",mm.Value[2]) (mm.Value[3]?Format("{:02}",SubStr(mm.Value[3],2)):"")
		If t&&!Mod(StrLen(t),2){
			If t is time
			{
				arr:=FormatTime(t,"yyyy年" (StrLen(t)>4?"M月":"") (StrLen(t)>6?"d日":""),0), result.Push({0:"{Value}",1:arr,3:arr}), arr:=FormatTime(t,"yyyy年" (StrLen(t)>4?"M月":"") (StrLen(t)>6?"d日":""),1), result.Push({0:"{Value}",1:arr,3:arr})
				If StrLen(t)>6
					arr:=lunar(t,"农历YYYY年Md"), result.Push({0:"{Value}",1:arr,3:arr}),arr:=lunar(t,"YY年Md"), result.Push({0:"{Value}",1:arr,3:arr})
			} Else If !InStr(str,"/"){
				t:=SubStr(A_Now,1,8) t
				If t is time
					arr:=FormatTime(t,"H时" (StrLen(t)>11?"m分":"") (StrLen(t)>13?"s秒":""),0), result.Push({0:"{Value}",1:arr,3:arr}), arr:=FormatTime(t,"H时" (StrLen(t)>11?"m分":"") (StrLen(t)>13?"s秒":""),1), result.Push({0:"{Value}",1:arr,3:arr})
			}
		}
	}
	If RegExMatch(str,"O)^(2[0-3]|1\d|0?[1-9]):([1-5]\d|0?[1-9])(:([1-5]\d|0?[1-9]))?$",mm){
		t:="H时m分" (mm.Value[4]?"s秒":"")
		arr:=time(SubStr(A_Now,1,8) Format("{:02}{:02}{:02}",mm.Value[1],mm.Value[2],mm.Value[4]),0,t), result.Push({0:"{Value}",1:arr,3:arr})
		arr:=time(SubStr(A_Now,1,8) Format("{:02}{:02}{:02}",mm.Value[1],mm.Value[2],mm.Value[4]),1,t), result.Push({0:"{Value}",1:arr,3:arr})
		If (mm.Value[4]=""){
			arr:=time(SubStr(A_Now,1,10) Format("{:02}{:02}",mm.Value[1],mm.Value[2]),0,"m分s秒"), result.Push({0:"{Value}",1:arr,3:arr})
			arr:=time(SubStr(A_Now,1,10) Format("{:02}{:02}",mm.Value[1],mm.Value[2]),1,"m分s秒"), result.Push({0:"{Value}",1:arr,3:arr})
		}
	} Else If RegExMatch(str,"O)^([1-5]\d|0?[1-9]):([1-5]\d|0?[1-9])$",mm){
		arr:=time(SubStr(A_Now,1,10) Format("{:02}{:02}",mm.Value[1],mm.Value[2]),0,"m分s秒"), result.Push({0:"{Value}",1:arr,3:arr})
		arr:=time(SubStr(A_Now,1,10) Format("{:02}{:02}",mm.Value[1],mm.Value[2]),1,"m分s秒"), result.Push({0:"{Value}",1:arr,3:arr})
	}
	If (str~="[\+\-\*/!\^\(\)%&\|<>~]"){
		If (SubStr(str,0)="=")
			str:=SubStr(str,1,-1)
		arr:=RegExReplace(str,"(\d+)!","jiecheng($1)")
		RegExMatch(arr,"O)(\([^\(\)]+\)|\d+(\.\d+)?)\^(\([^\(\)]+\)|\d+(\.\d+)?)",mm)
		arr:=RegExReplace(arr,"(\([^\(\)]+\)|\d+(\.\d+)?)\^(\([^\(\)]+\)|\d+(\.\d+)?)","Math.pow($1,$3)")
		Try arr:=JScript("function eval2(str){var num=eval(str);return num.toString()};function jiecheng(num){var result=1;if (num%1!=0){return};for(var i=1;i<=num;i++){result*=i;}return result;}").("eval2(" arr ").toString()")
		Catch
			arr:=""
		If (arr!="")&&!InStr(arr,"#"){
			;If RegExMatch(arr,"\.\d*9{4,}\d$")
				;arr:=RegExReplace(arr,"(\.\d*?)9{4,}\d$","$1"), arr+=1/(10**StrLen(Strsplit(arr,".")[2]))
			;arr:=RTrim(RegExReplace(arr,"(0{4,}\d|0*)$"),".")
			;, result.Push({0:"{Value}",1:arr,3:arr}), arr:=str "=" arr, result.Push({0:"{Value}",1:arr,3:arr})
		;}
        If RegExMatch(arr,"(?<=\.)9{4,}\d$") 
            arr:=RegExReplace(arr,"(?<=\.)9{4,}\d$"), arr+=1/(10**StrLen(Strsplit(arr,".")[2])) 
        arr:=RTrim(RegExReplace(arr,"(?<=\.)(0{4,}\d|0*)$"),".")
        , result.Push({0:"{Value}",1:arr,3:arr}), arr:=str "=" arr, result.Push({0:"{Value}",1:arr,3:arr}) 
        }
	}
	If result.Length()=0
		result:=""
	Return result
}
get_hotstring(str){
	global DB
	Return get_word_lianxiang(DB,str,"hotstrings",0)
}
get_function(str){
	global DB
	Return get_word_lianxiang(DB,str,"functions",0)
}
; 模糊取词
get_word_lianxiang(DB, input, cikuname, num:=200, xz:=1){
	Critical
	global Imagine, Singleword, SQL_buffer, srf_all_Input
	If (input="")
		Return []
	If (cikuname="English"){
		If (Ord(input)<91)
			_SQL:="SELECT '',upper(substr(key,1,1))||substr(key,2),weight,1 FROM 'extend'.'English' WHERE key='" Input "' UNION ALL SELECT '',upper(substr(key,1,1))||substr(key,2),weight,2 FROM 'extend'.'English' WHERE key>'" Input "' AND key<'" SubStr(Input, 1, -1) Chr(Ord(SubStr(Input, 0))+1) "' " (xz?"AND length(key)<5+" StrLen(Input):"") " ORDER by 4,weight DESC " (num?" limit " num:"")
		Else
			_SQL:="SELECT '',key,weight,1 FROM 'extend'.'English' WHERE key='" Input "' UNION ALL SELECT '',key,weight,2 FROM 'extend'.'English' WHERE key>'" Input "' AND key<'" SubStr(Input, 1, -1) Chr(Ord(SubStr(Input, 0))+1) "' AND length(key)<5+" StrLen(Input) " ORDER by 4,weight DESC " (num?" limit " num:"")
	} Else If (cikuname="hotstrings"), Input:=Format("{:L}", Input)
		_SQL:="SELECT value,comment,replace(replace(value,x'0a','``n'),x'09','``t') FROM 'extend'.'hotstrings' WHERE key>='" Input "' AND key<""" SubStr(Input, 1, -1) Chr(Ord(SubStr(Input, 0))+1) """ AND value <> '' ORDER by key " (num?" limit 1":"")
	Else If (cikuname="functions")
		_SQL:="SELECT value,comment,comment FROM 'extend'.'functions' WHERE key>='" Input "' AND key<'" SubStr(Input, 1, -1) Chr(Ord(SubStr(Input, 0))+1) "' AND value <> '' ORDER by key " (num?" limit 1":"")
	Else 
		word:=Singleword||InStr(srf_all_Input,"``"), _SQL:="SELECT key,value,weight,1 FROM '" cikuname "' WHERE key='" Input "' AND value <> '' " (word?"AND length(value)=1":"") " UNION ALL SELECT key,value,weight,length(key) FROM '" cikuname "' WHERE key>'" Input "' " ("AND key<'" SubStr(Input, 1, -1) Chr(Ord(SubStr(Input, 0))+1) "'") " AND length(key)<" StrLen(Input)+3 " AND value <> '' " (word?"AND length(value)=1":"") " ORDER by 4,weight DESC " (num?"limit " num:"")
	If DB.GetTable(_SQL, Result){
		If (Result.RowCount){
			If (cikuname="hotstrings"){
				Loop % Result.RowCount {
					If RegExMatch(Result.Rows[A_Index, 2], "\{.*\}", Match){
						Result.Rows[A_Index, 2]:=StrReplace(Result.Rows[A_Index, 2],Match)
						If InStr(Match,"{bz}")
							Result.Rows[A_Index, 3]:=Result.Rows[A_Index, 2], Result.Rows[A_Index, 0]:=StrReplace(Match,"{bz}")
						Else
							Result.Rows[A_Index, 0]:=Match
					}
					If (!InStr(Match,"{bz}")&&StrLen(Result.Rows[A_Index, 3])>10)
						Result.Rows[A_Index, 3]:=SubStr(Result.Rows[A_Index, 3],1,10) "……"
				}
			} Else If (cikuname="functions"){
				Loop % Result.RowCount
					If RegExMatch(Result.Rows[A_Index, 2], "\{.*\}", Match){
						If ((Result.Rows[A_Index, 3]:=StrReplace(Result.Rows[A_Index, 2],Match))="")
							Result.Rows[A_Index, 3]:=SubStr(StrReplace(Result.Rows[A_Index, 1],"`n","``n"),1,10) (StrLen(Result.Rows[A_Index, 1])>10?"……":"")
						Result.Rows[A_Index, 0]:=Match
					}
			} Else {
				index:=0, fg:=0, SQL_buffer[input]:=_SQL
				Loop % Result.RowCount
					If (Result.Rows[A_Index, 4]=2){
						If fg=0
							fg:=A_Index, index:=0
						index++, Result.Rows[A_Index, 0]:=cikuname "|" index, Result.Rows[A_Index, 4]:=Result.Rows[fg, 3], Result.Rows[A_Index, -1]:=input
					} Else
						index++, Result.Rows[A_Index, 0]:=cikuname "|" index, Result.Rows[A_Index, 4]:=Result.Rows[1, 3], Result.Rows[A_Index, -1]:=input
			}
		}
		Result.Rows[0]:=input
		Return Result.Rows
	}
	Return []
}
; 精确取词
get_word(DB, input, cikuname, num:=0){
	Critical
	global mhyRegExstr, Singleword, SQL_buffer, valueindex, srf_all_Input
	If (input="")
		Return []
	If (cikuname="pinyin")
		_SQL:="SELECT key,value,weight FROM 'pinyin' WHERE jp=""" RegExReplace(Input,"([a-z])[a-z]*","$1") """ AND key='" StrReplace(Input,"'","''") "' ORDER BY weight DESC"
	Else If (cikuname~="^(hotstrings|functions)$")
		_SQL:="SELECT value,comment FROM 'extend'.'" cikuname "' where key='" Input "' AND value <> '' ORDER by key ASC limit 1"
	Else If (cikuname="customs")
		_SQL:="SELECT value,value,comment,comment FROM 'extend'.'customs' where key='" Input "' AND comment>'/' AND comment<':' ORDER BY key,comment"
	Else
		word:=Singleword||InStr(srf_all_Input,"``"), _SQL:="SELECT key,value,weight FROM '" cikuname "' where key='" Input "' AND value <> '' " (word?"AND length(value)=1":"") " ORDER BY key,weight DESC" (num?" LIMIT" num:"")
	; If (cikuname="customs")
	; 	MsgBox %input%
	If DB.GetTable(_SQL, Result){
		If (Result.RowCount){
			If (cikuname="customs"){
				Loop % Result.RowCount
				{
					Result.Rows[A_Index, -1]:=Input ;, Result.Rows[A_Index, 1]:=""
					RegExMatch(Result.Rows[A_Index, 3], "^(\d+)(\{.*\})?",match)
					Result.Rows[A_Index, 0]:=cikuname "|" A_Index "|" match2, Result.Rows[A_Index, 3]:=match1
				}
				If (valueindex>2)
					Loop % Result.RowCount
						Result.Rows[A_Index, valueindex]:=Result.Rows[A_Index, 2]
			} Else {
				Loop % Result.RowCount
					Result.Rows[A_Index, -1]:=input, Result.Rows[A_Index, 0]:=cikuname "|" A_Index, Result.Rows[A_Index, 4]:=Result.Rows[1, 3]
				SQL_buffer[input]:=_SQL
			}
		}
		Result.Rows[0]:=input
		Return Result.Rows
	}
	; Else
		; MsgBox % "消息:`t" DB.ErrorMsg "`n代码:`t" DB.ErrorCode
	Return []
}

; 字符上屏
SendInput(str, mode:=""){
	Critical
	global ClipSaved
	If !(InStr(mode, "{"))||(mode~="\{\d+\}")
		SendInput % "{Text}" str
	Else If InStr(mode, "{Input}")
		SendInput % str
	Else If RegExMatch(mode, "i)\{Fast(,(\d+))?\}", KeyDelay){
		OnClipboardChange("ClipChanged", 0)
		If (ClipSaved="")&&Clipboard
			ClipSaved:=ClipboardAll
		If ((t:=TickCount(1, 1))>15){
			Clipboard:=str
			SendInput, {RCtrl Down}v{RCtrl Up}
			TickCount(0, 1)
		} Else
			Clipboard.=str
		OnClipboardChange("ClipChanged", 1)
	} Else If RegExMatch(mode, "i)\{Delay,(\d+)?(,\d+)?\}", KeyDelay){
		SetKeyDelay, %KeyDelay1%, % Trim(KeyDelay2, ",")
		SendEvent % (InStr(mode, "{Text}")?"{Text}":"") str
		SetKeyDelay, 0, 0
	} Else {
		SendEvent % (InStr(mode, "{Text}")?"{Text}":"") str
	}
	Return
}
TickCount(s:=0,n:=1){
	static freq:=0, CounterBefore:=""
	If !freq
		CounterBefore:=[], DllCall("QueryPerformanceFrequency", "Int64*", freq), DllCall("QueryPerformanceCounter", "Int64*", t), CounterBefore[n]:=t
	If (s){
		DllCall("QueryPerformanceCounter", "Int64*", t)
		Return Format("{:.2f}", (t - CounterBefore[n])/freq*1000)
	} Else
		DllCall("QueryPerformanceCounter", "Int64*", t), CounterBefore[n]:=t
}
soso_select(source,search:=""){
	static sosourl:={baidu:"http://www.baidu.com/s?ie=utf-8&wd=",bing:"https://cn.bing.com/search?q=",weibo:"https://s.weibo.com/weibo/",google:"http://www.google.com/search?q="}
	If (search=""){
		OnClipboardChange("ClipChanged", 0)
		ClipSaved:=ClipboardAll
		Clipboard:=""
		SendInput, {RCtrl Down}c{RCtrl Up}
		ClipWait, 0.5
		If (Clipboard&&DllCall("IsClipboardFormatAvailable","UInt",1))
			search:=Clipboard
		Clipboard:=ClipSaved
		OnClipboardChange("ClipChanged", 1)
		If (search=""){
			OnMessage(0x18, "SetWindowsAlwaysOnTop")
			InputBox, search, 输入搜索关键字, , , , 100, , , , , % Last_input()
			OnMessage(0x18,"")
			If (ErrorLevel)
				Return
		}
	}
	search:=StrReplace(StrReplace(StrReplace(StrReplace(search,"\","\\"),"'","\'"), "`n", "\n"), "`r", "\r")
	Run, % sosourl[source] JScript("").("encodeURIComponent('" search "')")
}
soso_list(str:=""){
	str:="(.*)" RegExReplace(str, "(.)", "$1(.*)")
	m_list:=[{0:"{Func}",1:"soso_select/baidu",3:"百度搜索",4:"baidusousuo"},{0:"{Func}",1:"soso_select/bing",3:"bing搜索",4:"bingsousuo"}
		,{0:"{Func}",1:"fanyi_select/google",3:"谷歌翻译",4:"gugefanyi"},{0:"{Func}",1:"fanyi_select/youdao",3:"有道翻译",4:"youdaofanyi"}
		,{0:"{Func}",1:"soso_select/weibo",3:"微博搜索",4:"weibosousuo"},{0:"{Func}",1:"soso_select/google",3:"谷歌搜索",4:"gugesousuo"}]
	Loop % len:=m_list.Length()
		If !(m_list[len+1-A_Index,4]~=str)
			m_list.RemoveAt(len+1-A_Index)
	Return m_list
}
fanyi_select(apitype:="youdao",KeyWord:=""){
	static apitype_
	If (KeyWord=""){
		OnClipboardChange("ClipChanged", 0)
		KeyWord:=Clipboard
		ClipSaved:=ClipboardAll
		Clipboard:=""
		SendInput, {RCtrl Down}c{RCtrl Up}
		ClipWait, 0.5
		If (Clipboard&&DllCall("IsClipboardFormatAvailable","UInt",1))
			KeyWord:=Clipboard
		Clipboard:=ClipSaved
		ClipSaved:=""
		OnClipboardChange("ClipChanged", 1)
	}
	Gui, fanyi:-DPIScale
	Gui, fanyi:Color, White, White
	Gui, fanyi:Margin, 0, 0
	Gui, fanyi:Font, s15
	w:=A_ScreenWidth//2, h:=A_ScreenHeight*0.375
	Gui, fanyi:Add, Edit, w%w% h%h% ggettrans_
	Gui, fanyi:Add, Tab, % "gfanyitab AltSubmit Choose" (apitype="google"?1:2), 谷歌翻译|有道翻译
	Gui, fanyi:Tab, 1
	Gui, fanyi:Add, Edit, w%w% h%h% ReadOnly
	Gui, fanyi:Tab, 2
	Gui, fanyi:Add, Edit, w%w% h%h% ReadOnly
	Gui, fanyi:Font
	Gui, fanyi:Show, , 中英互译 Esc关闭窗口 Tab切换
	WinSet, Redraw,, 中英互译 Esc关闭窗口 Tab切换
	Hotkey, IfWinActive, 中英互译 Esc关闭窗口 Tab切换
	Hotkey, Tab, switchfanyitab
	Hotkey, If
	apitype_:=apitype
	GuiControl, fanyi:, Edit1, %KeyWord%
	SetTimer gettrans, -10
	Return
	switchfanyitab:
		Gui, fanyi:Default
		GuiControlGet, apitype,, SysTabControl321
		GuiControl, Choose, SysTabControl321, % "|" 3-apitype
	Return
	fanyitab:
		GuiControlGet, apitype,, SysTabControl321
		apitype_:=apitype=1?"google":"youdao"
		Gosub gettrans
	Return
	gettrans:
		Critical, Off
		Gui, fanyi:Default
		GuiControlGet, KeyWord,, Edit1
		GuiControl, , % (apitype_="google"?"Edit2":"Edit3"), % TranslateApi(apitype_,KeyWord,"auto","auto")
	Return
	gettrans_:
		SetTimer, gettrans, -400
	Return
	fanyiGuiEscape:
	fanyiGuiClose:
		Gui, fanyi:Destroy
	Return
}
label_list(str:=""){
	str:="(.*)" RegExReplace(str, "(.)", "$1(.*)")
	m_list:=[{0:"{Label}",1:"option",3:"选项",4:"xuanxiang"},{0:"{Label}",1:"currentciku",3:"词库",4:"ciku"},{0:"{Label}",1:"cikuManager",3:"短语词库",4:"duanyuciku"}
		,{0:"{Label}",1:"srfreload",3:"重启",4:"chongqi"},{0:"{Label}",1:"srfupdate",3:"更新",4:"gengxin"},{0:"{Label}",1:"srfsuspend",3:"禁用",4:"jinyong"},{0:"{Label}",1:"EXIT",3:"退出",4:"tuichu"}]
	Loop % len:=m_list.Length()
		If !(m_list[len+1-A_Index,4]~=str)
			m_list.RemoveAt(len+1-A_Index)
	Return m_list
}
mode_list(str:=""){
	global
	local m_list, len
	str:="(.*)" RegExReplace(str, "(.)", "$1(.*)")
	m_list:=[{0:"{Mode}",1:[["Settings","Traditional",(Traditional?0:1)],["","valueindex",(Traditional?2:5)]],3:(Traditional?"关闭繁体模式":"繁体模式"),4:"fanti"}
			,{0:"{Mode}",1:[["Settings","Imagine",(Imagine?0:1)]],3:(Imagine?"关闭联想":"开启联想"),4:"liangxing"}
			,{0:"{Mode}",1:[["","Englishmode",(Englishmode?0:1)]],3:(Englishmode?"关闭英文输入":"英文输入"),4:"yingwen"}
			,{0:"{Mode}",1:[["Settings","EnSymbol",(EnSymbol?0:1)]],3:(EnSymbol?"中文标点":"英文标点"),4:"biaodian"}
			,{0:"{Mode}",1:[["","SendFromClip",(SendFromClip?0:1)],["","SendDelaymode",(SendFromClip?(SendDelay?"{Delay," SendDelay*10 ",0}":""):"{Fast}")]],3:(SendFromClip?"默认上屏":"剪贴板上屏"),4:"jiantieban"}
			,{0:"{Mode}",1:[["GuiStyle","Textdirection",(Textdirection="Vertical"?"Horizontal":"Vertical")]],3:(Textdirection="Vertical"?"候选框横版":"候选框竖版"),4:"houxuankuang"}]
	If (shurulei="pinyin"){
		m_list.Push({0:"{Mode}",1:[["Settings","fuzhuma",(fuzhuma?0:1)]],3:(fuzhuma?"关闭辅助码":"开启辅助码"),4:"fuzhuma"})
		m_list.Push({0:"{Mode}",1:[["Settings","Learning",(Learning?0:1)]],3:(Learning?"关闭自学习":"开启自学习"),4:"zixuexi"})
		m_list.Push({0:"{Mode}",1:[["Settings","Singleword",(Singleword?0:1)]],3:(Singleword?"长句模式":"字词模式"),4:"zicichangju"})
		m_list.Push({0:"{Mode}",1:[["Settings","CloudInput",(CloudInput?0:1)]],3:(CloudInput?"关闭云输入":"开启云输入"),4:"yunshuru"})
		m_list.Push({0:"{Mode}",1:[["Settings","chaojijp",(chaojijp?0:1)]],3:(chaojijp?"关闭超级简拼":"开启超级简拼"),4:"chaojijianpin"})
		m_list.Push({0:"{Mode}",1:[["Settings","Wordfrequency",(Wordfrequency?0:1)]],3:(Wordfrequency?"关闭动态调频":"开启动态调频"),4:"dongtaitiaopin"})
		If (Wordfrequency)
			m_list.Push({0:"{Mode}",1:[["Settings","fixedword",(fixedword?0:1)]],3:(fixedword?"关闭字频固定":"字频固定"),4:"zipingudin"})
	} Else {
		m_list.Push({0:"{Mode}",1:[["Settings","Singleword",(Singleword?0:1)]],3:(Singleword?"字词模式":"字模式"),4:"zici"})
		m_list.Push({0:"{Mode}",1:[["Settings","lspy",(lspy?0:1)]],3:(lspy?"关闭Z拼音模式":"开启Z拼音模式"),4:"zpinyin"})
		If (lspy)
			m_list.Push({0:"{Mode}",1:[["Settings","ShowCode",(ShowCode?0:1)]],3:(ShowCode?"关闭编码反查":"开启编码反查"),4:"bianmafancha"})
		m_list.Push({0:"{Mode}",1:[["Settings","zigen",(zigen?0:1)]],3:(zigen?"关闭字根反查":"开启字根反查"),4:"zigenfancha"})
		m_list.Push({0:"{Mode}",1:[["Settings","wumaqc",(wumaqc?0:1)]],3:(wumaqc?"关闭误码清除":"开启误码清除"),4:"wumaqingchu"})
		m_list.Push({0:"{Mode}",1:[["Settings","simasp",(simasp?0:1)]],3:(simasp?"关闭四码上屏":"开启四码上屏"),4:"simashangping"})
		m_list.Push({0:"{Mode}",1:[["Settings","wumasp",(wumasp?0:1)]],3:(wumasp?"关闭五码上屏":"开启五码上屏"),4:"wumashangping"})
	}
	Loop % len:=m_list.Length()
		If !(m_list[len+1-A_Index,4]~=str)
			m_list.RemoveAt(len+1-A_Index)
	Return m_list
}
Inputscheme_list(str:=""){
	global DB, pinyince, Inputscheme, MethodTable
	result:=[], str:="(.*)" RegExReplace(str, "(.)", "$1(.*)")
	For Key, Value in pinyince
		If (Value~=str)
			result.Push({0:"{Mode}",1:[["","shurulei","pinyin"],["Settings","Inputscheme",Value]],3:(Inputscheme=Value?"<" Key ">":Key)})
	DB.GetTable("SELECT name FROM sqlite_master WHERE type='table' AND NOT instr(tbl_name,'@') AND tbl_name NOT IN ('English','symbol','customs','functions','hotstrings','pinyin','hebing','sqlite_sequence') ORDER BY name DESC",TableInfo)
	Loop % TableInfo.RowCount
		If (TableInfo.Rows[A_Index,1]~=str)
			result.InsertAt(1,{0:"{Mode}",1:[["","shurulei",MethodTable[TableInfo.Rows[A_Index,1]]?MethodTable[TableInfo.Rows[A_Index,1]]:"xingma"],["Settings","Inputscheme",TableInfo.Rows[A_Index,1]]],3:(Inputscheme=TableInfo.Rows[A_Index,1]?"<" TableInfo.Rows[A_Index,1] ">":TableInfo.Rows[A_Index,1])})
	Return result
}
editgetsel(){
	ControlGetFocus, ctl, A
	ControlGet focusedHWND, Hwnd, , %ctl%, A
	If DllCall("SendMessage", "Ptr", focusedHWND, "Uint", 0xB0, "UintP", start, "UintP", end){
		VarSetCapacity(buf, (A_IsUnicode?2:1)*end, 0)
		ControlGetText, buf, , ahk_id%focusedHWND%
		Return Trim(SubStr(buf, start+1, end-start)," `r`n`t"), buf:=""
	}
	Return Chr(1)
}
selectmenu(){
	Critical, Off
	static init:=0
		, Paramslist:={百度搜索:"baidu",谷歌搜索:"google",bing搜索:"bing",微博搜索:"weibo",谷歌翻译:"google",有道翻译:"youdao",二维码生成:"qrcode",Base64编码:"StrToBase64",Base64解码:"Base64toStr"}
	global srf_mode, YzPID, Gbuffer:=""
	If (!init){
		Menu, soso_select, Add, 百度搜索(&B), selectmenu_
		Menu, soso_select, Add, bing搜索(&N), selectmenu_
		Menu, soso_select, Add, 微博搜索(&W), selectmenu_
		Menu, soso_select, Add, 谷歌搜索(&G), selectmenu_
		Menu, fanyi_select, Add, 谷歌翻译(&G), selectmenu_
		Menu, fanyi_select, Add, 有道翻译(&Y), selectmenu_
		Menu, Encoding, Add, 二维码生成(&Q), Func_
		Menu, Encoding, Add, Base64编码(&E), Func_
		Menu, Encoding, Add, Base64解码(&D), Func_
		Menu, selectmenu, Add, 搜索(&S), :soso_select
		Menu, selectmenu, Add, 翻译(&F), :fanyi_select
	}
	If ((Gbuffer:=editgetsel())=Chr(1)){
		OnClipboardChange("ClipChanged", 0)
		ClipSaved:=ClipboardAll
		Gbuffer:=Clipboard:=""
		Sleep 100
		SendInput, {RCtrl Down}c{RCtrl Up}
		ClipWait, 0.5
		If (Clipboard&&DllCall("IsClipboardFormatAvailable","UInt",1))
			Gbuffer:=Clipboard
		Clipboard:=ClipSaved
		OnClipboardChange("ClipChanged", 1)
	}
	If Trim(Gbuffer," `t`r`n"){
		t:=srf_mode, srf_mode:=0
		Gosub srf_value_off
		Menu, selectmenu, Delete
		arr:=[]
		If (Gbuffer~="\d+")
			arr:=mathmode(Gbuffer)
		If (arr=""||arr.Length()=0){
			Menu, selectmenu, Add, 搜索(&S), :soso_select
			Menu, selectmenu, Add, 翻译(&F), :fanyi_select
			Menu, selectmenu, Add, 编码(&C), :Encoding
			Menu, selectmenu, Show
		} Else {
			Try Menu, mathmode, Delete
			Loop % arr.Length()
				Menu, mathmode, Add, % arr[A_Index,1] " (&" Chr(A_Index+64) ")", mathmode_
			Menu, selectmenu, Add, 数值(&M), :mathmode
			Menu, selectmenu, Add, 编码(&C), :Encoding
			Menu, selectmenu, Show
		}
		srf_mode:=t
	}
	Return
	mathmode_:
		SendInput(RegExReplace(A_ThisMenuItem,"i) ?\(&[a-z]\)$"), "{Fast}")
	Return
	selectmenu_:
		%A_ThisMenu%(Paramslist[RegExReplace(A_ThisMenuItem,"i) ?\(&[a-z]\)$")],Gbuffer), Gbuffer:=""
	Return
	Plugin_:
		PluginCall(Paramslist[RegExReplace(A_ThisMenuItem,"i) ?\(&[a-z]\)$")] "(" Gbuffer ")"), Gbuffer:=""
	Return
	Func_:
		tFunc:=Paramslist[RegExReplace(A_ThisMenuItem,"i) ?\(&[a-z]\)$")], SendInput(t:=%tFunc%(Gbuffer), "{Fast}")
		OnClipboardChange("ClipChanged", 0), Clipboard:=t, OnClipboardChange("ClipChanged", 1), Gbuffer:=""
	Return
}
Last_input(){
	global srf_last_input
	Return srf_last_input[2, 2]
}
FileGetSize(file){
	FileGetSize, size, %file%
	Return size
}
Clipboardhistory(s:=0){
	global DB
	If (s="+"){
		If (Clipboard="")
			Return
		If (!DB.Exec("INSERT INTO 'temp'.'Clipboardhistory' VALUES('" t:=StrReplace(Clipboard, "'", "''") "');"))
			DB.Exec("CREATE TABLE IF NOT EXISTS 'temp'.'Clipboardhistory' ('value' TEXT);"), DB.Exec("INSERT INTO 'temp'.'Clipboardhistory' VALUES('" t "');")
	} Else If (s=0){
		DB.GetTable("SELECT DISTINCT value FROM 'temp'.'Clipboardhistory' ORDER BY ROWID DESC", result)
		Loop % result.RowCount {
			result.Rows[A_Index,0]:="{Fast}"
			If StrLen(LTrim(result.Rows[A_Index,1]," `r`n`t"))>50
				result.Rows[A_Index,3]:=SubStr(LTrim(result.Rows[A_Index,1]," `r`n`t"),1,50) "……"
			Else
				result.Rows[A_Index,3]:=LTrim(result.Rows[A_Index,1]," `r`n`t")
			result.Rows[A_Index,3]:=StrReplace(StrReplace(StrReplace(result.Rows[A_Index,3],"`t","``t"),"`n","``n"),"`r","``r")
		}
		Return IsObject(result.Rows)?result.Rows:[{0:"{Value}",3:"无剪贴板记录"}]
	} Else If (s="c"){
		DB.Exec("DELETE FROM 'temp'.'Clipboardhistory'")
		Return [{0:"{Off}"}]
	} Else If (s~="^\d+$"){
		DB.GetTable("SELECT DISTINCT value FROM 'temp'.'Clipboardhistory' ORDER BY ROWID DESC LIMIT " (s-1) ",1", result)
		If (result.Rows[1,1])
			SendInput(result.Rows[1,1], "{Fast}")
	} Else If (s~="^-\d+"){
		DB.Exec("DELETE FROM 'temp'.'Clipboardhistory' WHERE value=(SELECT DISTINCT value FROM 'temp'.'Clipboardhistory' ORDER BY ROWID DESC LIMIT " (s-1) ",1)")
		Return [{0:"{Off}"}]
	} Else
		Return [{0:"{Func}",1:"Clipboardhistory/c",3:"清空剪贴板纪录"}]
}
qrcode(string:=""){		; 二维码生成
	static str
	If (string=""){
		ClipSaved:=ClipboardAll
		Clipboard:=""
		SendInput, {RCtrl Down}c{RCtrl Up}
		ClipWait, 0.5
		str:=Clipboard, Clipboard:=ClipSaved
	} Else
		str:=string
	SetTimer, makeqrcode, -10
	Return
	makeqrcode:
	If (str=""){
		InputBox, str, 输入文本, , , , 100
		If (ErrorLevel)
			Return
	}
	picHeight:=Max(300,Min(A_ScreenHeight-200,StrLen(str)+100))
	Gui, qrcode:Destroy
	Gui, qrcode:-DPIScale
	Gui, qrcode:Margin , 0, 0
	If (A_PtrSize=4)
		DllCall("Lib\Dll_x86\quricol32.dll\GeneratePNG","str", sFile:=A_Temp "\" A_NowUTC ".png", "str", str, "int", 5, "int", 5, "int", 0)
	Else
		DllCall("Lib\Dll_x64\quricol64.dll\GeneratePNG","str", sFile:=A_Temp "\" A_NowUTC ".png", "str", str, "int", 5, "int", 5, "int", 0)
	Gui, qrcode:Add,Picture, h%picHeight% w-1 gSaveAs, % sFile
	Gui, qrcode:Show, ,点击保存图片 Esc关闭
	str:=""
	Return
	SaveAs:
		Fileselectfile,nf,s16,,另存为,PNG图片(*.png)
		If !StrLen(nf)
			Return
		nf := RegExMatch(nf,"i)\.png") ? nf : nf ".png"
		FileMove,%sFile%,%nf%,1
		Gui, qrcode:Destroy
	Return
	qrcodeGuiEscape:
	qrcodeGuiClose:
		Gui, qrcode:Destroy
		FileDelete, %sFile%
	Return
}
; 简体转繁体
simp2trad(str){
	static STPhrases, phrases_index
	global Traditional, YzIni, valueindex
	If !IsObject(phrases_index){
		STPhrases:={}, STPhrases:={}, phrases_index:={}
		If FileExist("Lib\@s2t.txt"){
			FileRead, Mabiao, Lib\@s2t.txt
			Loop, Parse, Mabiao, `n, `r
				If (A_LoopField!="")
					STPhrases[(tarr:=StrSplit(A_LoopField, "="))[1]]:=tarr[2]
		} Else {
			Traditional:=YzIni["Settings","Traditional"]:=0, valueindex:=2, phrases_index:=""
			MsgBox, 16, 错误, Lib目录下缺少简繁体转换字符集@s2t.txt，转换失败！
			Return
		}
		For key,value in STPhrases
			phrases_index[SubStr(key, 1, 1)] .= "," key
	}
	result:="",word:="",wordnum:=0
	If (StrLen(str)=1)
		Return StrReplace(STPhrases[str]?STPhrases[str]:str, " ", Chr(2))

	Loop, Parse, str
	{
		If (A_LoopField<=Chr(0xff)){
			If wordnum {
				If STPhrases[word]
					result .= STPhrases[word]
				Else
					Loop, Parse, word
						result .= STPhrases[A_LoopField]?SubStr(STPhrases[A_LoopField],1,1):A_LoopField
				word:="", wordnum:=0, result .= A_LoopField
			} Else
				result .= A_LoopField
			Continue
		}
		If !wordnum {
			wordnum+=1
			word .= A_LoopField
		} Else If InStr(phrases_index[SubStr(word, 1, 1)], word A_LoopField) {
			word .= A_LoopField, wordnum+=1
		} Else If (wordnum=1) {
			result .= STPhrases[word]?SubStr(STPhrases[word],1,1):word, word:=A_LoopField, wordnum:=1
		} Else {
			If STPhrases[word]
					result .= STPhrases[word]
			Else
				Loop, Parse, word
					result .= STPhrases[A_LoopField]?SubStr(STPhrases[A_LoopField],1,1):A_LoopField
			word:=A_LoopField, wordnum:=1
		}
	}
	If wordnum
		If STPhrases[word]
			result .= STPhrases[word]
		Else
			Loop, Parse, word
				result .= STPhrases[A_LoopField]?SubStr(STPhrases[A_LoopField],1,1):A_LoopField
	Return StrReplace(result, " ", Chr(2))
}
; 云输入
BDCloudInput(input){
	global srf_Plugins, CloudInput, yzPID, CloudStart:=A_TickCount
	static init:=0
	If (!init)
		Gui, globalvar:Add, Text, Hwndinit
	GuiControl,globalvar:, %init%, % input
	DetectHiddenWindows, on
	If (srf_Plugins["CloudInput",1]=""){
		Try {
			Run, % "Lib\CloudInput.exe " yzPID, , , tPID
			WinWait, % "ahk_pid" tPID, , 5
			srf_Plugins["CloudInput",1]:=tPID
		} Catch
			CloudInput:=0
	} Else {
		Process, Exist, % srf_Plugins["CloudInput",1]
		If (!ErrorLevel){
			Run, % "Lib\CloudInput.exe " yzPID, , , tPID
			WinWait, % "ahk_pid" tPID, , 5
			srf_Plugins["CloudInput",1]:=tPID
		}
	}
	If (ErrorLevel=srf_Plugins["CloudInput",1])||(ErrorLevel=0)
		PostMessage, 10000, %YzPID%, %init%, , % "ahk_class AutoHotkey ahk_pid" srf_Plugins["CloudInput",1]
}
; 加载配置
LoadIni(){
	global
	local Key, Value, Section, element, delini:=[]
	For Section, element In srf_default_value
		For Key, Value In element
			If ((%Key%:=YzIni[Section, Key])="")
				%Key%:=YzIni[Section, Key]:=Value

	; 删除无效配置
	;For Section,element In YzIni
		;If !srf_default_value.HasKey(Section){
			;If (Section!="Hidden")
				;delini[Section]:=""
		;} Else
			;For Key, Value In element
				;If !srf_default_value[Section].HasKey(Key)
					;delini[Section,Key]:=""
	;For Section,element In delini
		;If (element="")
			;YzIni.DeleteSection(Section)
		;Else If (Section!="Version")
			;For Key In element
				;YzIni.RemoveKey(Section, Key)
	;delini:=""
}
; 执行脚本
ExecScript(Script, Name:="", Params:="", workingdir:="") {
	Pipe:=[], Name:=Name?Name:"YZ_AHK_" . A_TickCount, AhkPath:=A_ScriptDir "\Lib\AutoHotkey.exe", workingdir:=workingdir?workingdir:A_ScriptDir
	If (!FileExist(AhkPath)) {
		If FileExist(A_AhkPath)&&(A_AhkVersion>"1.1.30"){
			FileCopy, % StrReplace(A_AhkPath,"AutoHotkey.exe","AutoHotkeyU32.exe"), %AhkPath%
		} Else {
			MsgBox, 20, 错误, 主目录下缺少AutoHotkey.exe或版本太低，是否下载？
			IfMsgBox, Yes
			{
				If !UrlDownloadToFile("https://autohotkey.oss-cn-qingdao.aliyuncs.com/AutoAHKScript/Scripts/yz/Lib/AutoHotkey.exe", "Lib\AutoHotkey.exe"){
					MsgBox, 16, 错误, 下载AutoHotkey.exe失败！`n请手动下载后放在主目录下。
					Return
				}
			} Else
				Return
		}
	}
	Loop 2 {
		Pipe[A_Index]:=DllCall("CreateNamedPipe"
			, "Str", "\\.\pipe\" Name
			, "UInt", 2, "UInt", 0
			, "UInt", 255, "UInt", 0
			, "UInt", 0, "UPtr", 0
			, "UPtr", 0, "UPtr")
	}
	Call = "%AhkPath%" /CP65001 "\\.\pipe\%Name%"
	; Shell:=ComObjCreate("WScript.Shell")
	; Exec:=Shell.Run(Call " " Params)
	Run, % Call " " Params, %workingdir%, , pid
	DllCall("ConnectNamedPipe", "UPtr", Pipe[1], "UPtr", 0)
	DllCall("CloseHandle", "UPtr", Pipe[1])
	DllCall("ConnectNamedPipe", "UPtr", Pipe[2], "UPtr", 0)
	FileOpen(Pipe[2], "h", "UTF-8").Write(Script)
	DllCall("CloseHandle", "UPtr", Pipe[2])
	; Return Exec.StdOut.ReadAll()
	Return pid
}
; 下载
UrlDownloadToFile(URL, FilePath){
	ComObjError(1)
	If RegExMatch(LTrim(FilePath, "\"), "(.*\\)?([^\\]+)$", FilePath){
		If (FilePath1&&!FileExist(FilePath1)){
			FileCreateDir, %FilePath1%
			If ErrorLevel
				Return 0
		}
		WebRequest:=ComObjCreate("WinHttp.WinHttpRequest.5.1")
		WebRequest.Open("GET", URL, 1)
		Try {
			WebRequest.Send()
			WebRequest.WaitForResponse(-1)
		} Catch
			Return 0
		If !WebRequest.ResponseBody()
			Return 0
		ADO:=ComObjCreate("adodb.stream"), ADO.Type:=1, ADO.Mode:=3, ADO.Open()
		Try ADO.Write(WebRequest.ResponseBody())
		Try ADO.SaveToFile(FilePath,2)
		ADO.Close(), WebRequest:=ADO:=""
		Return 1
	} Else
		Return 0
}
; 执行命令行并返回结果
StdoutToVar(sCmd, sEncoding:="CP936", sDir:="", ByRef nExitCode:=0) {
	DllCall( "CreatePipe",           PtrP,hStdOutRd, PtrP,hStdOutWr, Ptr,0, UInt,0 )
	DllCall( "SetHandleInformation", Ptr,hStdOutWr, UInt,1, UInt,1                 )

	VarSetCapacity( pi, (A_PtrSize == 4) ? 16 : 24,  0 )
	siSz := VarSetCapacity( si, (A_PtrSize == 4) ? 68 : 104, 0 )
	NumPut( siSz,      si,  0,                          "UInt" )
	NumPut( 0x100,     si,  (A_PtrSize == 4) ? 44 : 60, "UInt" )
	NumPut( hStdInRd,  si,  (A_PtrSize == 4) ? 56 : 80, "Ptr"  )
	NumPut( hStdOutWr, si,  (A_PtrSize == 4) ? 60 : 88, "Ptr"  )
	NumPut( hStdOutWr, si,  (A_PtrSize == 4) ? 64 : 96, "Ptr"  )

	If ( !DllCall( "CreateProcess", Ptr,0, Ptr,&sCmd, Ptr,0, Ptr,0, Int,1, UInt,0x08000000
		, Ptr,0, Ptr,sDir?&sDir:0, Ptr,&si, Ptr,&pi ) )
		return ""
		, DllCall( "CloseHandle", Ptr,hStdOutWr )
		, DllCall( "CloseHandle", Ptr,hStdOutRd )

	DllCall( "CloseHandle", Ptr,hStdOutWr ) ; The write pipe must be closed before Reading the stdout.
	VarSetCapacity(sTemp, 4095)
	while ( DllCall( "ReadFile", Ptr,hStdOutRd, Ptr,&sTemp, UInt,4095, PtrP,nSize, Ptr,0 ) )
	sOutput .= StrGet(&sTemp, nSize, sEncoding)

	DllCall( "GetExitCodeProcess", Ptr,NumGet(pi,0), UIntP,nExitCode )
	DllCall( "CloseHandle",        Ptr,NumGet(pi,0)                  )
	DllCall( "CloseHandle",        Ptr,NumGet(pi,A_PtrSize)          )
	DllCall( "CloseHandle",        Ptr,hStdOutRd                     )
	return sOutput
}
CreateGUID(){
    VarSetCapacity(pguid, 16, 0)
    If !(DllCall("ole32.dll\CoCreateGuid", "Ptr", &pguid)) {
        size := VarSetCapacity(sguid, (38 << !!A_IsUnicode) + 1, 0)
        If (DllCall("ole32.dll\StringFromGUID2", "Ptr", &pguid, "Ptr", &sguid, "Int", size))
            Return StrGet(&sguid)
    }
    Return ""
}
Base64toStr(sString){
	DllCall("crypt32\CryptStringToBinary", "str", sString, "Uint", 0, "Uint", 1, "ptr", 0, "Uint*", nSize, "ptr", 0, "ptr", 0)
	VarSetCapacity(sbin, nSize)
	DllCall("crypt32\CryptStringToBinary", "str", sString, "Uint", 0, "Uint", 1, "ptr", &sbin, "Uint*", nSize, "ptr", 0, "ptr", 0)
	Return StrGet(&sbin, "utf-8")
}
StrToBase64(sString, Flags:=0x40000001){
	sStrlen:=StrPutVar(sString, sbin, "utf-8")
	Return BinToBase64(&sbin, sStrlen, Flags)
}
StrPutVar(sVar, ByRef sbin, encoding){
	VarSetCapacity(sbin, StrPut(sVar, encoding)* ((encoding="utf-16"||encoding="cp1200")  ? 2 : 1))
    Return (StrPut(sVar, &sbin, encoding) -1)* ((encoding="utf-16"||encoding="cp1200")  ? 2 : 1)
}
BinToBase64(binpointer, bytes, Flags:=0x40000001){
	DllCall("crypt32\CryptBinaryToString", "Ptr", binpointer, "Uint", bytes, "Uint", Flags, "Ptr", 0, "Uint*", nSize)
	VarSetCapacity(sString, nSize*2)
	DllCall("crypt32\CryptBinaryToString", "Ptr", binpointer, "Uint", bytes, "Uint", Flags, "str", sString, "Uint*", nSize)
	Return StrGet(&sString, (A_IsUnicode ? "utf-16" : "cp0"))
}
Base64toBin(sString, ByRef sbin){
	DllCall("crypt32\CryptStringToBinary", "str", sString, "Uint", 0, "Uint", 1, "ptr", 0, "Uint*", Bytes, "ptr", 0, "ptr", 0)
	VarSetCapacity(sbin, Bytes)
	DllCall("crypt32\CryptStringToBinary", "str", sString, "Uint", 0, "Uint", 1, "ptr", &sbin, "Uint*", Bytes, "ptr", 0, "ptr", 0)
	Return Bytes
}
; BASE64转Bitmap
Gdip_BitmapFromBase64(ByRef Base64){
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	; calculate the length of the buffer needed
	If !(DllCall("crypt32\CryptStringToBinary", Ptr, &Base64, "UInt", 0, "UInt", 0x01, Ptr, 0, "UIntP", DecLen, Ptr, 0, Ptr, 0))
		return -1
	VarSetCapacity(Dec, DecLen, 0)
	; decode the Base64 encoded string
	If !(DllCall("crypt32\CryptStringToBinary", Ptr, &Base64, "UInt", 0, "UInt", 0x01, Ptr, &Dec, "UIntP", DecLen, Ptr, 0, Ptr, 0))
		return -2
	; create a memory stream
	If !(pStream := DllCall("shlwapi\SHCreateMemStream", Ptr, &Dec, "UInt", DecLen, "UPtr"))
		return -3
	DllCall("gdiplus\GdipCreateBitmapFromStreamICM", Ptr, pStream, "PtrP", pBitmap)
	ObjRelease(pStream)
	return pBitmap
}
; 复制对象
CopyObj(obj){
	If !IsObject(obj){
		retObj:=obj
	} Else {
		retObj := {}
		For k, v In obj
			retObj[k] := CopyObj(v)
	}
	Return retObj
}
; 下载到变量
SendRequest(url, Method="GET", postData=""){ 
	WebRequest:=ComObjCreate("WinHttp.WinHttpRequest.5.1"), WebRequest.SetTimeouts(100, 100, 100, 100)
	WebRequest.Open(Method, url, (Method="POST" ? 1 : 0))
	WebRequest.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
	WebRequest.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0")
    if postData
    {
        WebRequest.Send(postData)
        WebRequest.WaitForResponse(-1)
        Return WebRequest.ResponseText
    }   
	Return
}
JScript(Script:=""){
	static doc
	ComObjError(1)
	Try {
		doc:=ComObjCreate("htmlfile"), doc.write("<meta http-equiv='X-UA-Compatible' content='IE=9'><body><script>" Script "</script></body>")
		Return ObjBindMethod(doc.parentWindow, "eval")
	} Catch {
		sc:=ComObjCreate("ScriptControl"), sc.Language:="JScript", sc.ExecuteStatement(Script)
		Return ObjBindMethod(sc, "Eval")
	}
}
; symbol函数
Get_symbol(DB,str){
	_SQL:="SELECT value FROM 'extend'.'symbol' WHERE key='" str "' ORDER BY key"
	If DB.GetTable(_SQL, Result){
		If (Result.RowCount){
			Loop % Result.RowCount
				Result.Rows[A_Index, 0]:="symbol|-1"
			Return Result.Rows
		} Else {
			DB.GetTable(_SQL:="SELECT value FROM 'extend'.'symbol' WHERE key>='" str "' AND key<'" SubStr(str, 1, -1) Chr(Ord(SubStr(str, 0))+1) "' ORDER BY key", Result)
			If (Result.RowCount){
				Loop % Result.RowCount
					Result.Rows[A_Index, 0]:="symbol|-1"
				Return Result.Rows
			}
		}
	}
	Return []
}

; 获取光标坐标
GetCaretPos(Byacc:=1){
	Static init
    If (A_CaretX=""){
		Caretx:=Carety:=CaretH:=CaretW:=0
		If (Byacc){
			If (!init)
				init:=DllCall("LoadLibrary","Str","oleacc","Ptr")
			VarSetCapacity(IID,16), idObject:=OBJID_CARET:=0xFFFFFFF8
			, NumPut(idObject==0xFFFFFFF0?0x0000000000020400:0x11CF3C3D618736E0, IID, "Int64")
			, NumPut(idObject==0xFFFFFFF0?0x46000000000000C0:0x719B3800AA000C81, IID, 8, "Int64")
			If (DllCall("oleacc\AccessibleObjectFromWindow", "Ptr",Hwnd:=WinExist("A"), "UInt",idObject, "Ptr",&IID, "Ptr*",pacc)=0){
				Acc:=ComObject(9,pacc,1), ObjAddRef(pacc)
				Try Acc.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0), ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), ChildId:=0)
				, CaretX:=NumGet(x,0,"int"), CaretY:=NumGet(y,0,"int"), CaretH:=NumGet(h,0,"int")
			}
		}
		If (Caretx=0&&Carety=0){
			MouseGetPos, x, y
			Return {x:x,y:y,h:30,t:"Mouse",Hwnd:Hwnd}
		} Else
        	Return {x:Caretx,y:Carety,h:Max(Careth,30),t:"Acc",Hwnd:Hwnd}
    } Else
        Return {x:A_CaretX,y:A_CaretY,h:30,t:"Caret",Hwnd:Hwnd}
}

DebugOutput(info,type){
	static buffer:=""
	Switch type
	{
		Case 1:
			FormatTime, Now, , [yyyy-MM-dd HH:mm:ss]
			FileAppend, % Now "`n" info "`n", debug.log, UTF-8
		Case 2:
			OutputDebug % info
		Case 3:
			MsgBox, 16, 错误, % StrReplace(info, "|", "`n")
		Case 4:
			buffer .= info "    "
			SetTimer, writeintolog, -1000
		Default:
			Return
	}
	Return
	writeintolog:
		FormatTime, Now, , [yyyy-MM-dd HH:mm:ss]
		FileAppend, % Now "`n" buffer "`n", debug.log, UTF-8
		; OutputDebug % buffer
		buffer:=""
	Return
}

StrDeref(str){
	Try {
		Transform, var, Deref, %str%
		Return var
	} Catch
		Return str
}

PluginCall(str){
	global srf_Plugins
	If !RegExMatch(str, "O)^(.+\|)?([^\(\)]+?)(\((.*)\))?$", Match)
		Return
	ComObjError(1)
	Plugin:=(Plugin:=Trim(Match.Value[1], "|"))?Plugin:"YzPlugins", FuncName:=Match.Value[2], Params:=StrReplace(Match.Value[4], "``,", Chr(3))
	Params:=StrSplit(Params, ",")
	Loop % Params.Length()
		Params[A_Index]:=StrDeref(StrReplace(Params[A_Index], Chr(3), ","))
	Try Return ComObjActive(srf_Plugins[Plugin, 2])[FuncName](Params*)
	Catch {
		If !FileExist(PluginPath:="Lib\YzPlugins\" Plugin ".ahk")&&!FileExist(PluginPath:="Lib\YzPlugins\" Plugin "\" Plugin ".ahk"){
			MsgBox, 16, 错误, 插件不存在或已禁用！
			Return
		}
		WinWait, % "ahk_pid" RunPlugins(A_ScriptDir "\" PluginPath), , 2
		Try Return ComObjActive(srf_Plugins[Plugin, 2])[FuncName](Params*)
		Catch
			MsgBox, 16, 错误, 插件启动失败！
	}
}

RunPlugins(PluginPath){
	global srf_Plugins
	SplitPath, PluginPath, , PluginDir, , Plugin
	Script=
	(
#NoEnv
#NoTrayIcon
#Persistent
#SingleInstance Force
ListLines, Off
SendMode, Input
SetBatchLines,-1
OnExit, Exit
If !(A_Args[1]~="^\d+$")||!(A_Args[2]~="\{.+\}")
	ExitApp
Else If IsObject(YzPlugins)
	ObjRegisterActive(YzPlugins, A_Args[2])
Else
	ExitApp
SetTimer, scriptexit, 5000
Return

ObjRegisterActive(Object, CLSID, Flags:=0){
    static cookieJar := {}
    If (!CLSID) {
        If (cookie := cookieJar.Remove(Object)) != ""
            DllCall("oleaut32\RevokeActiveObject", "uInt", cookie, "Ptr", 0)
        Return
    }
    If cookieJar[Object]
        Throw Exception("Object is already registered", -1)
    VarSetCapacity(_clsid, 16, 0)
    If (hr := DllCall("ole32\CLSIDFromString", "wstr", CLSID, "Ptr", &_clsid)) < 0
        Throw Exception("Invalid CLSID", -1, CLSID)
    hr := DllCall("oleaut32\RegisterActiveObject"
        , "Ptr", &Object, "Ptr", &_clsid, "uInt", Flags, "uInt*", cookie
        , "uInt")
    If hr < 0
        Throw Exception(Format("Error 0x{:x}", hr), -1)
    cookieJar[Object] := cookie
}

scriptexit:
	Process, Exist, `% A_Args[1]
	If !ErrorLevel
		ExitApp
Return

Exit:
	ObjRegisterActive(YzPlugins, "")
	ExitApp
Return

#Include %PluginPath%
	)
	Return srf_Plugins[Plugin,1]:=ExecScript(Script,Plugin,DllCall("GetCurrentProcessId") " " (srf_Plugins[Plugin,2]:=CreateGUID()),PluginDir)
}

TranslateApi(ApiType,KeyWord,to:="auto",from:="auto",proxy:=""){
	static ik:="'" RegExReplace(SendRequest("http://translate.google.cn/"), ".+tkk:'(\d+\.\d+)'.+", "$1") "'"
	; en, zh-CN, auto ik:="'" RegExReplace(SendRequest("http://translate.google.cn/"), ".+tkk:'(\d+\.\d+)'.+", "$1") "'"
	; ik='439034.2746551257'
	; static js:=""
	; if (js=""){
		; Script:=RegExReplace(SendRequest("http://translate.google.cn/translate/releases/twsfe_20161212_RC00/r/js/desktop_module_main.js")
		; 	, ".+(var gk=.+)var kk=.+", "$1") "ik='" RegExReplace(SendRequest("http://translate.google.cn/"), ".+tkk:'(\d+\.\d+)'.+", "$1") "';"
		Script=
		(LTrim
			var gk=function(a){return function(){return a}},hk=function(a,b){for(var c=0;c<b.length-2;c+=3){var d=b.charAt(c+2),
			d="a"<=d?d.charCodeAt(0)-87:Number(d),d="+"==b.charAt(c+1)?a>>>d:a<<d;a="+"==b.charAt(c)?a+d&4294967295:a^d}return a},
			ik=null,jk=function(a){var b;if(null!==ik)b=ik;else{b=gk(String.fromCharCode(84));var c=gk(String.fromCharCode(75));b=[b(),b()];
			b[1]=c();b=(ik=window[b.join(c())]||"")||""}var d=gk(String.fromCharCode(116)),c=gk(String.fromCharCode(107)),d=[d(),d()];d[1]=c();
			c="&"+d.join("")+"=";d=b.split(".");b=Number(d[0])||0;for(var e=[],f=0,g=0;g<a.length;g++){var l=a.charCodeAt(g);
			128>l?e[f++]=l:(2048>l?e[f++]=l>>6|192:(55296==(l&64512)&&g+1<a.length&&56320==(a.charCodeAt(g+1)&64512)?(l=65536+((l&1023)<<10)+(a.charCodeAt(++g)&1023),
			e[f++]=l>>18|240,e[f++]=l>>12&63|128):e[f++]=l>>12|224,e[f++]=l>>6&63|128),e[f++]=l&63|128)}a=b;for(f=0;f<e.length;f++)a+=e[f],
			a=hk(a,"+-a^+6");a=hk(a,"+-3^+b+-f");a^=Number(d[1])||0;0>a&&(a=(a&2147483647)+2147483648);a`%=1E6;return c+(a.toString()+"."+(a^b))};
			ik=%ik%;
		)
		js:=JScript(Script)
	; }
	If (KeyWord="")
		Return
	ComObjError(0)
	KeyWord:=StrReplace(StrReplace(StrReplace(StrReplace(KeyWord,"\","\\"),"'","\'"), "`n", "\n"), "`r", "\r")
	Switch ApiType
	{
		Case "youdao":
			url:="http://fanyi.youdao.com/fanyiapi.do?keyfrom=qqqqqqqq123&key=86514254&type=data&doctype=json&version=1.1"
			jsondata:=SendRequest(url, "POST", "q=" js.("encodeURIComponent('" KeyWord "')")), obj:=js.("(" jsondata ")")
			trans:=obj["translation"][0]
			if IsObject(obj["basic"]["explains"])
				Loop % obj["basic"]["explains"].length
					trans .= "`n" obj["basic"]["explains"][A_Index-1]
			if (trans=""&&StrLen(KeyWord)>200)
				Return "要翻译的文本过长！"
		Case "google":
			; to:=from:="zh-CN"
			to:=(to="auto"?(KeyWord~="[\x{4e00}-\x{9fff}]"?"en":"zh-CN"):to), from:=(from="auto"?(to="en"?"zh-CN":"en"):from)
			url:="https://translate.google.cn/translate_a/single?client=webapp&sl=" from "&tl=" to "&hl=" to "&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" js.("jk('" KeyWord "')") "&q=" js.("encodeURIComponent('" KeyWord "')")
			jsondata:=SendRequest(url, "GET")
			obj:=js.("(" jsondata ")")
			if !IsObject(obj[1]){
				Loop % obj[0].length
					trans .= obj[0][A_Index - 1][0]
				trans := Trim(trans, ",`n ")
			} else {
				MainTransText := obj[0][0][0]
				Loop % obj[1].length {
					trans .= "`n", obj := obj[1][A_Index-1][1]
					Loop % obj.length
						txt := obj[A_Index - 1], trans .= (MainTransText = txt ? "" : "`n" txt)
				}
				trans := MainTransText . "`n" . Trim(trans, ",`n ")
			}
	}
	Return trans
}
/****************************************************************************************************************************
 * Lib: JSON.ahk
 *     JSON Lib for AutoHotkey.
 * Version:
 *     v2.1.3 [updated 04/18/2016 (MM/DD/YYYY)]
 * License:
 *     WTFPL [http://wtfpl.net/]
 * Requirements:
 *     Latest version of AutoHotkey (v1.1+ or v2.0-a+)
 * Installation:
 *     Use #Include JSON.ahk or copy into a function Library folder and then
 *     use #Include <JSON>
 * Links:
 *     GitHub:     - https://github.com/cocobelgica/AutoHotkey-JSON
 *     Forum Topic - http://goo.gl/r0zI8t
 *     Email:      - cocobelgica <at> gmail <dot> com
 */


/**
 * Class: JSON
 *     The JSON object contains methods for parsing JSON and converting values
 *     to JSON. Callable - NO; Instantiable - YES; Subclassable - YES;
 *     Nestable(via #Include) - NO.
 * Methods:
 *     Load() - see relevant documentation before method definition header
 *     Dump() - see relevant documentation before method definition header
 */
class JSON
{
	/**
	 * Method: Load
	 *     Parses a JSON string into an AHK value
	 * Syntax:
	 *     value := JSON.Load( text [, reviver ] )
	 * Parameter(s):
	 *     value      [retval] - parsed value
	 *     text    [in, ByRef] - JSON formatted string
	 *     reviver   [in, opt] - function object, similar to JavaScript's
	 *                           JSON.parse() 'reviver' parameter
	 */
	class Load extends JSON.Functor
	{
		Call(self, ByRef text, reviver:="")
		{
			this.rev := IsObject(reviver) ? reviver : false
		; Object keys(and array indices) are temporarily stored in arrays so that
		; we can enumerate them in the order they appear in the document/text instead
		; of alphabetically. Skip If no reviver function is specIfied.
			this.keys := this.rev ? {} : false

			static quot := Chr(34), bashq := "\" . quot
			     , json_value := quot . "{[01234567890-tfn"
			     , json_value_or_array_closing := quot . "{[]01234567890-tfn"
			     , object_key_or_object_closing := quot . "}"

			key := ""
			is_key := false
			root := {}
			stack := [root]
			next := json_value
			pos := 0

			while ((ch := SubStr(text, ++pos, 1)) != "") {
				If InStr(" `t`r`n", ch)
					continue
				If !InStr(next, ch, 1)
					this.ParseError(next, text, pos)

				holder := stack[1]
				is_array := holder.IsArray

				If InStr(",:", ch) {
					next := (is_key := !is_array && ch == ",") ? quot : json_value

				} Else If InStr("}]", ch) {
					ObjRemoveAt(stack, 1)
					next := stack[1]==root ? "" : stack[1].IsArray ? ",]" : ",}"

				} Else {
					If InStr("{[", ch) {
					; Check If Array() is overridden and If its return value has
					; the 'IsArray' property. If so, Array() will be called normally,
					; otherwise, use a custom base object for arrays
						static json_array := Func("Array").IsBuiltIn || ![].IsArray ? {IsArray: true} : 0
					
					; sacrIfice readability for minor(actually negligible) performance gain
						(ch == "{")
							? ( is_key := true
							  , value := {}
							  , next := object_key_or_object_closing )
						; ch == "["
							: ( value := json_array ? new json_array : []
							  , next := json_value_or_array_closing )
						
						ObjInsertAt(stack, 1, value)

						If (this.keys)
							this.keys[value] := []
					
					} Else {
						If (ch == quot) {
							i := pos
							while (i := InStr(text, quot,, i+1)) {
								value := StrReplace(SubStr(text, pos+1, i-pos-1), "\\", "\u005c")

								static tail := A_AhkVersion<"2" ? 0 : -1
								If (SubStr(value, tail) != "\")
									break
							}

							If (!i)
								this.ParseError("'", text, pos)

							  value := StrReplace(value,  "\/",  "/")
							, value := StrReplace(value, bashq, quot)
							, value := StrReplace(value,  "\b", "`b")
							, value := StrReplace(value,  "\f", "`f")
							, value := StrReplace(value,  "\n", "`n")
							, value := StrReplace(value,  "\r", "`r")
							, value := StrReplace(value,  "\t", "`t")

							pos := i ; update pos
							
							i := 0
							while (i := InStr(value, "\",, i+1)) {
								If !(SubStr(value, i+1, 1) == "u")
									this.ParseError("\", text, pos - StrLen(SubStr(value, i+1)))

								uffff := Abs("0x" . SubStr(value, i+2, 4))
								If (A_IsUnicode || uffff < 0x100)
									value := SubStr(value, 1, i-1) . Chr(uffff) . SubStr(value, i+6)
							}

							If (is_key) {
								key := value, next := ":"
								continue
							}
						
						} Else {
							value := SubStr(text, pos, i := RegExMatch(text, "[\]\},\s]|$",, pos)-pos)

							static number := "number", integer :="integer"
							If value is %number%
							{
								If value is %integer%
									value += 0
							}
							Else If (value == "true" || value == "false")
								value := %value% + 0
							Else If (value == "null")
								value := ""
							Else
							; we can do more here to pinpoint the actual culprit
							; but that's just too much extra work.
								this.ParseError(next, text, pos, i)

							pos += i-1
						}

						next := holder==root ? "" : is_array ? ",]" : ",}"
					} ; If InStr("{[", ch) { ... } Else

					is_array? key := ObjPush(holder, value) : holder[key] := value

					If (this.keys && this.keys.HasKey(holder))
						this.keys[holder].Push(key)
				}
			
			} ; while ( ... )

			return this.rev ? this.Walk(root, "") : root[""]
		}

		ParseError(expect, ByRef text, pos, len:=1)
		{
			static quot := Chr(34), qurly := quot . "}"
			
			line := StrSplit(SubStr(text, 1, pos), "`n", "`r").Length()
			col := pos - InStr(text, "`n",, -(StrLen(text)-pos+1))
			msg := Format("{1}`n`nLine:`t{2}`nCol:`t{3}`nChar:`t{4}"
			,     (expect == "")     ? "Extra data"
			    : (expect == "'")    ? "Unterminated string starting at"
			    : (expect == "\")    ? "Invalid \escape"
			    : (expect == ":")    ? "Expecting ':' delimiter"
			    : (expect == quot)   ? "Expecting object key enclosed in double quotes"
			    : (expect == qurly)  ? "Expecting object key enclosed in double quotes or object closing '}'"
			    : (expect == ",}")   ? "Expecting ',' delimiter or object closing '}'"
			    : (expect == ",]")   ? "Expecting ',' delimiter or array closing ']'"
			    : InStr(expect, "]") ? "Expecting JSON value or array closing ']'"
			    :                      "Expecting JSON value(string, number, true, false, null, object or array)"
			, line, col, pos)

			static offset := A_AhkVersion<"2" ? -3 : -4
			throw Exception(msg, offset, SubStr(text, pos, len))
		}

		Walk(holder, key)
		{
			value := holder[key]
			If IsObject(value) {
				for i, k in this.keys[value] {
					; check If ObjHasKey(value, k) ??
					v := this.Walk(value, k)
					If (v != JSON.Undefined)
						value[k] := v
					Else
						ObjDelete(value, k)
				}
			}
			
			return this.rev.Call(holder, key, value)
		}
	}

	/**
	 * Method: Dump
	 *     Converts an AHK value into a JSON string
	 * Syntax:
	 *     str := JSON.Dump( value [, replacer, space ] )
	 * Parameter(s):
	 *     str        [retval] - JSON representation of an AHK value
	 *     value          [in] - any value(object, string, number)
	 *     replacer  [in, opt] - function object, similar to JavaScript's
	 *                           JSON.stringIfy() 'replacer' parameter
	 *     space     [in, opt] - similar to JavaScript's JSON.stringIfy()
	 *                           'space' parameter
	 */
	class Dump extends JSON.Functor
	{
		Call(self, value, replacer:="", space:="")
		{
			this.rep := IsObject(replacer) ? replacer : ""

			this.gap := ""
			If (space) {
				static integer := "integer"
				If space is %integer%
					Loop, % ((n := Abs(space))>10 ? 10 : n)
						this.gap .= " "
				Else
					this.gap := SubStr(space, 1, 10)

				this.indent := "`n"
			}

			return this.Str({"": value}, "")
		}

		Str(holder, key)
		{
			value := holder[key]

			If (this.rep)
				value := this.rep.Call(holder, key, ObjHasKey(holder, key) ? value : JSON.Undefined)

			If IsObject(value) {
			; Check object type, skip serialization for other object types such as
			; ComObject, Func, BoundFunc, FileObject, RegExMatchObject, Property, etc.
				static type := A_AhkVersion<"2" ? "" : Func("Type")
				If (type ? type.Call(value) == "Object" : ObjGetCapacity(value) != "") {
					If (this.gap) {
						stepback := this.indent
						this.indent .= this.gap
					}

					is_array := value.IsArray
				; Array() is not overridden, rollback to old method of
				; identIfying array-like objects. Due to the use of a for-loop
				; sparse arrays such as '[1,,3]' are detected as objects({}). 
					If (!is_array) {
						for i in value
							is_array := i == A_Index
						until !is_array
					}

					str := ""
					If (is_array) {
						Loop, % value.Length() {
							If (this.gap)
								str .= this.indent
							
							v := this.Str(value, A_Index)
							str .= (v != "") ? v . "," : "null,"
						}
					} Else {
						colon := this.gap ? ": " : ":"
						for k in value {
							v := this.Str(value, k)
							If (v != "") {
								If (this.gap)
									str .= this.indent

								str .= this.Quote(k) . colon . v . ","
							}
						}
					}

					If (str != "") {
						str := RTrim(str, ",")
						If (this.gap)
							str .= stepback
					}

					If (this.gap)
						this.indent := stepback

					return is_array ? "[" . str . "]" : "{" . str . "}"
				}
			
			} Else ; is_number ? value : "value"
				return ObjGetCapacity([value], 1)=="" ? value : this.Quote(value)
		}

		Quote(string)
		{
			static quot := Chr(34), bashq := "\" . quot

			If (string != "") {
				  string := StrReplace(string,  "\",  "\\")
				; , string := StrReplace(string,  "/",  "\/") ; optional in ECMAScript
				, string := StrReplace(string, quot, bashq)
				, string := StrReplace(string, "`b",  "\b")
				, string := StrReplace(string, "`f",  "\f")
				, string := StrReplace(string, "`n",  "\n")
				, string := StrReplace(string, "`r",  "\r")
				, string := StrReplace(string, "`t",  "\t")

				static rx_escapable := A_AhkVersion<"2" ? "O)[^\x20-\x7e]" : "[^\x20-\x7e]"
				; while RegExMatch(string, rx_escapable, m)
				; 	string := StrReplace(string, m.Value, Format("\u{1:04x}", Ord(m.Value)))
			}

			return quot . string . quot
		}
	}

	/**
	 * Property: Undefined
	 *     Proxy for 'undefined' type
	 * Syntax:
	 *     undefined := JSON.Undefined
	 * Remarks:
	 *     For use with reviver and replacer functions since AutoHotkey does not
	 *     have an 'undefined' type. Returning blank("") or 0 won't work since these
	 *     can't be distnguished from actual JSON values. This leaves us with objects.
	 *     Replacer() - the caller may return a non-serializable AHK objects such as
	 *     ComObject, Func, BoundFunc, FileObject, RegExMatchObject, and Property to
	 *     mimic the behavior of returning 'undefined' in JavaScript but for the sake
	 *     of code readability and convenience, it's better to do 'return JSON.Undefined'.
	 *     Internally, the property returns a ComObject with the variant type of VT_EMPTY.
	 */
	Undefined[]
	{
		get {
			static empty := {}, vt_empty := ComObject(0, &empty, 1)
			return vt_empty
		}
	}

	class Functor
	{
		__Call(method, ByRef arg, args*)
		{
		; When casting to Call(), use a new instance of the "function object"
		; so as to avoid directly storing the properties(used across sub-methods)
		; into the "function object" itself.
			If IsObject(method)
				return (new this).Call(method, arg, args*)
			Else If (method == "")
				return (new this).Call(arg, args*)
		}
	}
}