; 输入法上屏
srf_select(list_num,mode:=0,key:=""){
	global
	local selectvalue, _SQL, Result, index, yhnum, tt, Match, srf_all_Input2
	list_num:=list_num?list_num:10
	If (key){
		selectvalue:=[]
		SendInput(SubStr(jichu_for_select_Array[1,valueindex],1,list_num), SendDelaymode), hasCaretPos:=0
		RegExMatch(jichu_for_select_Array[1,1] "'","iO)([a-z]+'){" list_num "}", Match)
		selectvalue[2]:=SubStr(jichu_for_select_Array[1,2],1,list_num)
		selectvalue[1]:=Trim(Match.Value[0],"'"), selectvalue[0]:="pinyin"
		Function_for_select:=[], hotstring_for_select:=[], jichu_for_select_Array:=[], save_field_array:=[]
		Goto dwcz
	}
	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&&!mode&&selectvalue[1]){
		If (Inputscheme~="sp$|pinyin"){
			If (tt[2]>1)
				DB.Exec(_SQL:="UPDATE 'pinyin' SET weight = " (selectvalue[3]+1+(selectvalue[4]-selectvalue[3])//(tt-1)) " WHERE jp='" RegExReplace(StrReplace(selectvalue[1], "'", "''"),"([a-z])[a-z]*","$1") "' AND key = '" StrReplace(selectvalue[1], "'", "''") "' AND value = '" selectvalue[2] "';")
			Else If (tt[2]=1)
				DB.Exec(_SQL:="UPDATE 'pinyin' SET weight = weight+1 WHERE jp='" RegExReplace(StrReplace(selectvalue[1], "'", "''"),"([a-z])[a-z]*","$1") "' AND key = '" StrReplace(selectvalue[1], "'", "''") "' AND value = '" selectvalue[2] "';")
		} Else {
			If (tt[2]>1)
				DB.Exec(_SQL:="UPDATE '" Inputscheme "' SET weight = " (selectvalue[3]+1+(selectvalue[4]-selectvalue[3])//(tt-1)) " WHERE key = '" StrReplace(selectvalue[1], "'", "''") "' AND value = '" selectvalue[2] "';")
			Else If (tt[2]=1)
				DB.Exec(_SQL:="UPDATE '" Inputscheme "' SET weight = weight+1 WHERE key = '" StrReplace(selectvalue[1], "'", "''") "' AND value = '" selectvalue[2] "';")
		}
	}
	dwcz:
	srf_last_input[1, 2] .= selectvalue[2], srf_last_input[1, 1] .= (srf_last_input[1, 1]?"'":"") selectvalue[1]
	If (Inputscheme~="sp$|pinyin"){
		If (selectvalue[1]=""){
			Gosub srf_value_off
			Return
		}
		If (SaveCloud)&&(selectvalue[0]="<Cloud>|-1")
			Learnfg++
		; If Learning&&(Learnfg||(InStr(srf_all_Input,"\")||fzm||list_num+ListNum*waitnum>1)) ; &&!InStr(selectvalue[1], "'")
		If (Learning)
			learn_words[1] .= (learn_words[1]?"'":"") selectvalue[1], learn_words[2] .= selectvalue[2], Learnfg+=1 ; Learnfg+=(1+(InStr(srf_all_Input,"\")?1:0))
		If (index:=RegExMatch(srf_all_Input_tooltip,RegExReplace(RegExReplace(RegExReplace(selectvalue[1], "([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(srf_all_Input2:=LTrim(pyfenci(srf_all_Input, Inputscheme, False, DB),"'"), "'", , 1, yhnum)
			srf_all_Input:=RegExReplace(srf_all_Input, "^" StrReplace(SubStr(srf_all_Input2,1,index),"'","'?"))
			If (fzm!="")
				srf_all_Input:=RegExReplace(srf_all_Input, fzm "$")
			srf_all_Input:=LTrim(srf_all_Input,"\'")
			If (RTrim(srf_all_Input,"\'")){
				jichu_for_select:=srf_all_Input_tooltip:=ToolTipText:=""
				save_field_array.RemoveAt(1)
				hasCaretPos:=waitnum:=0, Function_for_select:=[], hotstring_for_select:=[], jichu_for_select_Array:=[]
				Gosub srf_tooltip
				If (key)
					KeyWait, %key%, Up
				Return
			}
		}
	} Else If (mode){
		If selectvalue[1]&&(index:=RegExMatch(srf_all_Input_tooltip,RegExReplace(RegExReplace(RegExReplace(selectvalue[1], "([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)^(Z)(.+)", Match)
			index:=InStr(srf_all_Input2:=LTrim(pyfenci(Match.Value[2], "pinyin", False, DB),"'"), "'", , 1, yhnum)
			srf_all_Input:=RegExReplace(Match.Value[2], "^" StrReplace(SubStr(srf_all_Input2,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
			}
		}
	}
	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
			Gosub srf_tooltip_fanye
			SetTimer, removelianxiang, -1000
		}
	}
	Return
	removelianxiang:
		If !(A_ThisHotkey~="i)[\d;',\.]|Space|Shift|Enter")
			Return
		jichu_for_select_Array:=[], history_field_array:=[]
		srf_inputing:=Learnfg:=0, ToolTipText:=srf_all_Input:=srf_for_select:="", hasCaretPos:=waitnum:=IsPinyin:=0
		If (ToolTipStyle=1)
			ToolTip(1)
		Else
			GdipText("")		
	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|<Cloud>|)$")
		Return
	KeyWait, % Mod(list_num, 10), T0.3
	If (A_TickCount-presstime>290)||(tt[1]="customs"){
		Suspend, On
		Gui +OwnDialogs
		If (tt[1]="customs")
			InputBox, pos, 输入调整后的位置, % "词条固定在第" selectvalue[3] "位`n输入整数调整至指定位置", , 2*A_ScreenDPI, 1.25*A_ScreenDPI
		Else If (tt[1]="pinyin"&&fzm)
			InputBox, pos, 在自定义短语中新建词条, % "词条在" tt[1] " 第" tt[2] "位`n输入整数固定在指定位置", , 2*A_ScreenDPI, 1.25*A_ScreenDPI
		Else
			InputBox, pos, 输入调整后的位置, % "词条在" tt[1] " 第" tt[2] "位`n输入整数调整至指定位置", , 2*A_ScreenDPI, 1.25*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[2],"'","''") "'")
				srf_all_Input_history:=""
				Gosub srf_tooltip
				Return
			} Else If fzm&&(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),"'") fzm
				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
				}
				Return
			}
			pos:=pos?pos:1
		} Else
			Return
	}
	If (pos=tt[2])
		Return
	Else {
		If (pos=1){
			DB.Exec("UPDATE '" tt[1] "' SET weight=" selectvalue[4]+1 " WHERE " (tt[1]="pinyin"?"jp=""" RegExReplace(selectvalue[1],"([a-z])[a-z]*","$1") """ AND ":"") "key=""" selectvalue[1] """ AND value=""" selectvalue[2] """")
		} Else If (pos>=2){
			_SQL:=SQL_buffer[selectvalue[-1]], 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 '" 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 '" tt[1] "' SET weight=" Result.Rows[2,1]+1 " WHERE " (tt[1]="pinyin"?"jp=""" RegExReplace(selectvalue[1],"([a-z])[a-z]*","$1") """ AND ":"") "key=""" selectvalue[1] """ AND value=""" selectvalue[2] """")
			} Else If (Result.RowCount=1){
				DB.Exec("UPDATE '" tt[1] "' SET weight=weight+1 WHERE ROWID IN (" RegExReplace(_SQL,"i)^SELECT (.+) FROM","SELECT ROWID FROM") " LIMIT " (pos-1) ")")
				DB.Exec("UPDATE '" tt[1] "' SET weight=" Result.Rows[1,1]+1 " WHERE " (tt[1]="pinyin"?"jp=""" RegExReplace(selectvalue[1],"([a-z])[a-z]*","$1") """ AND ":"") "key=""" 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 '" 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 '" tt[1] "' SET weight=1 WHERE " (tt[1]="pinyin"?"jp=""" RegExReplace(selectvalue[1],"([a-z])[a-z]*","$1") """ AND ":"") "key=""" 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
	}
}

; 输入法快捷键删词
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 'pinyin' WHERE jp=""" RegExReplace(selectvalue[1],"([a-z])[a-z]*","$1") """ AND key=""" selectvalue[1] """ AND value='" StrReplace(selectvalue[2],"'","''") "';"
	Else If (tt[1]="customs")
		_SQL:="DELETE FROM 'customs' WHERE key=""" selectvalue[-1] """ AND value='" StrReplace(selectvalue[2],"'","''") "';"
	Else
		_SQL:="DELETE FROM '" 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
		OutputDebug, % A_ThisFunc "|消息:`t" DB.ErrorMsg "`n代码:`t" DB.ErrorCode "|" DB.SQL
}
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) "'")
	}
	DB.Exec("UPDATE 'extend'.'customs' SET comment='" (Format("{:03}", alterpos) bz "' WHERE key='" key "' AND value='" StrReplace(value,"'","''") "'"))
}
; 输入法快捷键造词
srf_create(){
	global Inputscheme, DB, CopyOfData
	Gui +OwnDialogs
	InputBox, citiao, 创建词条，格式：词库名|编码=词条=位置, % "在当前输入方案的词库中创建词条可省略词库名`npinyin、wubi98、wubi86词库能自动生成编码可省略编码`n(拼音编码含'分隔符)`n在首选位置生成词条可省略位置", , 3.2*A_ScreenDPI, 5*A_ScreenDPI/3, , , , , %Clipboard%
	If (ErrorLevel)
		Return
	citiao:=Trim(citiao, "|=")
	RegExMatch(citiao,"^.+\|",cikuname), citiao:=StrReplace(citiao,cikuname), cikuname:=Trim(cikuname, "|")?Trim(cikuname, "|"):(Inputscheme~="pinyin|sp$"?"pinyin":Inputscheme), cikuname:=(cikuname~="(短语|dy|zdy)$"?"customs":(cikuname~="拼音|py"?"pinyin":cikuname))
	RegExMatch(citiao,"^[a-z']+[= ]",key), citiao:=StrReplace(citiao,key), key:=Trim(key, "= ")
	RegExMatch(citiao,"[= \t]\d+(\{.*\})?$",pos), value:=StrReplace(citiao,pos), pos:=Trim(pos, "= ")?Trim(pos, "= "):1
	If (value="")||(cikuname~="i)^(symbol|hotstrings|functions)$")
		Return
	If (key="")&&(cikuname~="^(pinyin|wubi86|wubi98)$")
		key:=StrSplit(IMEConverter(cikuname,value),"=","'")[1]
	If (key="")
		InputBox, key, 生成编码失败，请输入编码, , , 2*A_ScreenDPI, A_ScreenDPI
	If (key="")
		Return
	Else {
		If (cikuname="customs"){
			DB.Exec("DELETE FROM " (cikuname="customs"?"'extend'.":"") "'" cikuname "' WHERE " (cikuname="pinyin"?"jp=""" RegExReplace(key, "([a-z])[a-z]*", "$1") """ AND ":"") "key=""" 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
				SetTimer, ToolTipOff, -5000
			}
		} Else {
			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 weight FROM '" cikuname "' WHERE " (cikuname="pinyin"?"jp=""" RegExReplace(key, "([a-z])[a-z]*", "$1") """ AND ":"") "key=""" key """ ORDER BY weight DESC LIMIT 1",Result)
				weight:=(Result.Rows[1,1]?Result.Rows[1,1]+1:1)
			} Else If (pos>=2){
				DB.GetTable("SELECT weight FROM '" cikuname "' WHERE " (cikuname="pinyin"?"jp=""" RegExReplace(key, "([a-z])[a-z]*", "$1") """ AND ":"") "key=""" 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 '" 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=""" key """ ORDER BY weight DESC LIMIT " (pos-1) ")")
					weight:=Result.Rows[2,1]+1
				} Else If (Result.RowCount=1){
					DB.Exec("UPDATE '" 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=""" 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=""" key """",Result)
					If (Result.Rows[1,1]!="")&&(Result.Rows[1,1]<2)
						DB.Exec("UPDATE '" cikuname "' SET weight=weight+" (2-Result.Rows[1,1]) " WHERE " (cikuname="pinyin"?"jp=""" RegExReplace(key, "([a-z])[a-z]*", "$1") """ AND ":"") "key=""" key """")
					weight:=1
				}
			}
			If (oldpos="")
				_SQL:="INSERT INTO '" cikuname "' VALUES (" (cikuname="pinyin"?"""" RegExReplace(key, "([a-z])[a-z]*", "$1") """,":"") """" key """,'" StrReplace(value,"'","''") "','" weight "');"
			Else
				_SQL:="UPDATE '" 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
				SetTimer, ToolTipOff, -5000
			} Else
				MsgBox, 16, 数据库错误, % "消息:`t" DB.ErrorMsg "`n代码:`t" DB.ErrorCode
		}
	}
}
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
	hotstring:=StrReplace(hotarr[index, 1], "``n", "`n")
	Gosub srf_value_off
	SendInput(StrReplace(hotstring, "``t", "`t"), 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
	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 "{Label}":
			If IsLabel(function[index, 1])
				Gosub % function[index, 1]
		Case "{Func}":
			tarr:=StrSplit(Trim(function[index, 1],"/"), "/"), funcobj:=Func(tarr[1]), tarr.RemoveAt(1)
			If (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], %A_variate%:=function[index, 1, A_Index, 3]
			}
		Default:
			If (function[index, 0]~="i)\{Ev(erything)?\}")
				exePath:=exeQuery(function[index, 1], DllFolder "\Everything.dll")
			Else
				exePath:=StrDeref(function[index, 1])
			Try	Run, % exePath
			Catch errinfo {
				ToolTip % exePath "`n" errinfo.Extra, A_CaretX + 10 , A_CaretY + 20
				SetTimer, ToolTipOff, -2000
			}
	}
}
; 内置函数
srf_FuncSelect(srf_Input){
	global
	local srf_Func_Params:=[], Match, funcobj, result, key, value
	ToolTipText:=srf_Input, Function_for_select:=[]
	srf_Func_Params:=StrSplit(Trim(ToolTipText,func_key),func_key)
	If (srf_Input~="^" func_key "\d+"){
		funcobj:=srf_func_table[srf_Custom_Func["num"]?srf_Custom_Func["num"]:"num"]
	} Else If (srf_Input~="^" func_key "[a-z]+$"){
		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 {
			; If (funcobj){
			; 	Function_for_select[1, 0]:="{Label}", Function_for_select[1, 1]:=funcobj
			; 	Function_for_select[1, 3]:=srf_Default_Label[funcobj,2], srf_for_select:="1." Function_for_select[1, 3]
			; 	; srf_for_select:=Trim(srf_for_select, "`n")
			; } 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]
	Else If IsObject(result){
		If (result[1,0]="{Off}")
			Return -1
		Function_for_select:=result
		Return 1
	} Else
		Function_for_select[1, 0]:="{Value}", srf_for_select:="(Space)" (Function_for_select[1, 3]:=Function_for_select[1, 1]:=result)
	Return 0
}
FuncCall(funcobj,params*){
	Return funcobj.Call(params*)
}
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){
	global Imagine, Singleword, SQL_buffer
	If (input="")
		Return []
	; Input:=StrReplace(Input, "'", "''")
	If (cikuname="hotstrings")
		_SQL:="SELECT value,comment,value 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
		_SQL:="SELECT key,value,weight,1 FROM '" cikuname "' WHERE key='" Input "' AND value <> '' " (Singleword?"AND length(value)=1":"") " UNION ALL SELECT key,value,weight,2 FROM '" cikuname "' WHERE key>""" Input """ " ("AND key<""" SubStr(Input, 1, -1) Chr(Ord(SubStr(Input, 0))+1) """") " AND value <> '' " (Singleword?"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 (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]
					} Else
						index++, Result.Rows[A_Index, 0]:=cikuname "|" index, Result.Rows[A_Index, 4]:=Result.Rows[1, 3]
			}
		}
		Result.Rows[0]:=input
		Return Result.Rows
	}
	Return []
}
; 精确取词
get_word(DB, input, cikuname, num:=0){
	global mhyRegExstr, Singleword, SQL_buffer
	If (input="")
		Return []
	If (cikuname="pinyin")
		_SQL:="SELECT key,value,weight FROM 'pinyin' WHERE jp=""" RegExReplace(Input,"([a-z])[a-z]*","$1") """ AND key=""" 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 key,value,comment FROM 'extend'.'customs' where key = '" Input "' AND comment>'/' AND comment<':' ORDER BY key,comment;"
	Else
		_SQL:="SELECT key,value,weight FROM '" cikuname "' where key = '" Input "' AND value <> '' " (Singleword?"AND length(value)=1":"") " ORDER BY key,weight DESC" (num?" LIMIT" num:"") ";"
	If DB.GetTable(_SQL, Result){
		If (Result.RowCount){
			If (cikuname="customs"){
				Loop % Result.RowCount
				{
					Result.Rows[A_Index, -1]:=Result.Rows[A_Index, 1], 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
				}
			} 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:=""){
	global ClipSaved
	If !(InStr(mode, "{"))||(mode~="\{\d+\}")
		SendInput % "{Text}" str
	Else If InStr(mode, "{Input}")
		SendInput % str
	Else If InStr(mode, "{Fast}"){
		OnClipboardChange("ClipChanged", 0)
		If (ClipSaved="")&&Clipboard
			ClipSaved:=ClipboardAll
		Clipboard:=str
		RegExMatch(mode, "i)\{Delay,(\d+)?(,\d+)?\}", KeyDelay)
		SendInput, {RCtrl Down}v{RCtrl Up}
		Sleep (KeyDelay1?KeyDelay1:10)
		OnClipboardChange("ClipChanged", 1)
	} Else If RegExMatch(mode, "i)\{Delay,(\d+)?(,\d+)?\}", KeyDelay){
		SetKeyDelay, %KeyDelay1%, % Trim(KeyDelay2, ",")
		SendEvent % (InStr(mode, "{Text}")?"{Text}":"") str
		SetKeyDelay, 10, 0
	} Else {
		SendEvent % (InStr(mode, "{Text}")?"{Text}":"") str
	}
	Return
}

soso_select(arr*){
	static sosourl:={baidu:"http://www.baidu.com/s?wd=",bing:"https://cn.bing.com/search?q=",weibo:"https://s.weibo.com/weibo/",google:"http://www.google.com/search?q="}
	ClipSaved:=ClipboardAll
	Clipboard:=""
	SendInput, {RCtrl Down}c{RCtrl Up}
	ClipWait, 0.5
	If (arr.Length()=0){
		For Key, Value in sosourl
			Run, % Value Clipboard
	} Else
		Loop % arr.Length()
			Run, % sosourl[arr[A_Index]] Clipboard
	Clipboard:=ClipSaved
}
soso_list(){
	Return [{0:"{Func}",1:"soso_select/baidu",3:"百度搜索"},{0:"{Func}",1:"soso_select/bing",3:"bing搜索"}
		,{0:"{Func}",1:"soso_select/weibo",3:"微博搜索"},{0:"{Func}",1:"soso_select/google",3:"谷歌搜索"}]
}
label_list(){
	Return [{0:"{Label}",1:"option",3:"选项"},{0:"{Label}",1:"cikuManager",3:"词库"},{0:"{Label}",1:"srfupdate",3:"更新"}
		,{0:"{Label}",1:"srfreload",3:"重启"},{0:"{Label}",1:"srfsuspend",3:"禁用"},{0:"{Label}",1:"EXIT",3:"退出"}]
}
mode_list(){
	global
	local m_list
	m_list:=[{0:"{Mode}",1:[["Settings","Traditional",(Traditional?0:1)],["","valueindex",(Traditional?2:5)]],3:(Traditional?"关闭繁体模式":"繁体模式")}
			,{0:"{Mode}",1:[["Settings","Imagine",(Imagine?0:1)]],3:(Imagine?"关闭联想":"开启联想")}
			,{0:"{Mode}",1:[["Settings","SendFromClip",(SendFromClip?0:1)],["","SendDelaymode",(SendFromClip?"":"{Fast}") (SendDelay>1?"{Delay," SendDelay*10 ",0}":"")]],3:(SendFromClip?"默认上屏":"剪切板上屏")}
			,{0:"{Mode}",1:[["GuiStyle","Textdirection",(Textdirection="Vertical"?"Horizontal":"Vertical")]],3:(Textdirection="Vertical"?"候选框横版":"候选框竖版")}]
	If (shurulei="pinyin"){
		m_list.Push({0:"{Mode}",1:[["Settings","fuzhuma",(fuzhuma?0:1)]],3:(fuzhuma?"关闭辅助码":"开启辅助码")})
		m_list.Push({0:"{Mode}",1:[["Settings","Learning",(Learning?0:1)]],3:(Learning?"关闭自学习":"开启自学习")})
		m_list.Push({0:"{Mode}",1:[["Settings","Singleword",(Singleword?0:1)]],3:(Singleword?"长句模式":"字词模式")})
		m_list.Push({0:"{Mode}",1:[["Settings","CloudInput",(CloudInput?0:1)]],3:(CloudInput?"关闭云输入":"开启云输入")})
		m_list.Push({0:"{Mode}",1:[["Settings","Wordfrequency",(Wordfrequency?0:1)]],3:(Wordfrequency?"关闭动态调频":"开启动态调频")})
	} Else {
		m_list.Push({0:"{Mode}",1:[["Settings","Singleword",(Singleword?0:1)]],3:(Singleword?"字词模式":"字模式")})
		m_list.Push({0:"{Mode}",1:[["Settings","pinyinhunsu",(pinyinhunsu?0:1)]],3:(pinyinhunsu?"关闭Z拼音模式":"开启Z拼音模式")})
		m_list.Push({0:"{Mode}",1:[["Settings","ShowCode",(ShowCode&1?2&ShowCode:1|ShowCode)]],3:(ShowCode&1?"关闭编码反查":"开启编码反查")})
		m_list.Push({0:"{Mode}",1:[["Settings","ShowCode",(ShowCode&2?1&ShowCode:2|ShowCode)]],3:(ShowCode&2?"关闭字根反查":"开启字根反查")})
		m_list.Push({0:"{Mode}",1:[["Settings","wumaqc",(wumaqc?0:1)]],3:(wumaqc?"关闭误码清除":"开启误码清除")})
		m_list.Push({0:"{Mode}",1:[["Settings","simasp",(simasp?0:1)]],3:(simasp?"关闭四码上屏":"开启四码上屏")})
		m_list.Push({0:"{Mode}",1:[["Settings","wumasp",(wumasp?0:1)]],3:(wumasp?"关闭五码上屏":"开启五码上屏")})
	}
	Return m_list
}
Inputscheme_list(){
	global DB, pinyince, Inputscheme
	result:=[]
	For Key, Value in pinyince
		result.Push({0:"{Mode}",1:[["Settings","Inputscheme",Value],["","shurulei","pinyin"]],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 ('symbol','customs','functions','hotstrings','pinyin','hebing','sqlite_sequence') ORDER BY name DESC",TableInfo)
	Loop % TableInfo.RowCount
		result.InsertAt(1,{0:"{Mode}",1:[["Settings","Inputscheme",TableInfo.Rows[A_Index,1]],["Settings","Wordfrequency",0],["","shurulei",(TableInfo.Rows[A_Index,1]="sanpin"?"sanpin":"xingma")]],3:TableInfo.Rows[A_Index,1]})
	Return result
}
Last_input(){
	global srf_last_input
	Return srf_last_input[2, 2]
}
; 简体转繁体
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]
}
; 执行脚本
ExecScript(Script, Name:="", Params:="") {
	Pipe:=[], Name:=Name?Name:"YZ_AHK_" . A_TickCount, AhkPath:=A_ScriptDir "\Lib\AutoHotkey.exe"
	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, %A_ScriptDir%\Lib, , 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()
	WinWait, % "ahk_pid" pid, , 3
	Return pid
}
; 下载
UrlDownloadToFile(URL, FilePath){
	If RegExMatch(LTrim(FilePath, "\"), "(.*\\)?([^\\]+)$", FilePath){
		If (FilePath1&&!FileExist(FilePath1)){
			FileCreateDir, %FilePath1%
			If ErrorLevel
				Return 0
		}
		ComObjError(0)
		WebRequest:=ComObjCreate("WinHttp.WinHttpRequest.5.1")
		WebRequest.Open("GET", URL, true)
		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()
		ADO.Write(WebRequest.ResponseBody()), 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,True, 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 ""
}
; 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
}
; 下载到变量
Requests(url, Method="GET", postData="", headers="", Encoding=""){
	hObject:=ComObjCreate("WinHttp.WinHttpRequest.5.1")
	hObject.SetTimeouts(30000, 30000, 30000, 30000) 
	hObject.Open(Method, url, (Method="POST" ? True : False))  
	
	If IsObject(headers){
		for k, v in headers
			If v
				hObject.SetRequestHeader(k, v)
	}
	If postData{
		try
			hObject.Send(postData)
		try
			hObject.WaitForResponse(-1)
	} Else {
		try
			hObject.Send()
	}

	If (Encoding && hObject.ResponseBody)
	{
		oADO:=ComObjCreate("adodb.stream")
		oADO.Type:=1, oADO.Mode:=3
		oADO.Open(),oADO.Write(hObject.ResponseBody)
		oADO.Position:=0, oADO.Type:=2
		oADO.Charset:=Encoding
		return oADO.ReadText(), oADO.Close()
	}
	try 
		return hObject.ResponseText
}
ScriptControl(Language:="JScript"){
	sc:=ComObjCreate("ScriptControl"), sc.Language:=Language
	; execute the JScript
	; sc.ExecuteStatement(script)

	; extract a variate from the JScript
	; obj := sc.Eval("obj")
	Return sc
}
; 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(){
	Static init
    If (A_CaretX=""){
		Caretx:=Carety:=CaretH:=CaretW:=0
		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}
}

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

RunPlugins(){
	global srf_Plugins
	Script=
	(
#NoEnv
#NoTrayIcon
#Persistent
#SingleInstance Force
ListLines, Off
SendMode, Input
SetBatchLines,-1
OnExit, Exit
If !(A_Args[1]~="^\d+$")||!(A_Args[2]~="\{.+\}")
	ExitApp
Else
	ObjRegisterActive(YzPlugins, A_Args[2])
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 %A_ScriptDir%\Lib\YzPlugins.ahk
	)
	Return ExecScript(Script,"YzPlugins",DllCall("GetCurrentProcessId") " " (srf_Plugins["YzPlugins",2]:=CreateGUID()))
}
/****************************************************************************************************************************
 * 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*)
		}
	}
}