diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index ea1e4933..04e9a93b 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -20,9 +20,10 @@ jobs: go-version: '1.21' cache: false # Handled by golangci-lint. - - name: Validate go mod + - name: Validate go mod / generate run: | go mod tidy + go generate ./... git --no-pager diff && [[ 0 -eq $(git status --porcelain | wc -l) ]] - name: golangci-lint diff --git a/redis/command_action.gen.go b/redis/command_action.gen.go new file mode 100644 index 00000000..3597e95a --- /dev/null +++ b/redis/command_action.gen.go @@ -0,0 +1,2263 @@ +// Code generated by commandinfo_gen. DO NOT EDIT. + +package redis + +var ( + actionWatch = &commandAction{ + Action: func(state *connectionState) { + *state |= stateWatch + }, + } + actionUnwatch = &commandAction{ + Action: func(state *connectionState) { + *state &^= stateWatch + }, + } + actionMulti = &commandAction{ + Action: func(state *connectionState) { + *state |= stateMulti + }, + } + actionExec = &commandAction{ + Action: func(state *connectionState) { + *state &^= stateWatch | stateMulti + }, + } + actionDiscard = &commandAction{ + Action: func(state *connectionState) { + *state &^= stateWatch | stateMulti + }, + } + actionPsubscribe = &commandAction{ + Action: func(state *connectionState) { + *state |= stateSubscribe + }, + } + actionSubscribe = &commandAction{ + Action: func(state *connectionState) { + *state |= stateSubscribe + }, + } + actionMonitor = &commandAction{ + Action: func(state *connectionState) { + *state |= stateMonitor + }, + } + actionClientReplyOff = &commandAction{ + Action: func(state *connectionState) { + *state |= stateClientReplyOff + }, + } + actionClientReplyOn = &commandAction{ + Action: func(state *connectionState) { + *state &^= stateClientReplyOff | stateClientReplySkip + }, + } + actionClientReplySkip = &commandAction{ + Action: func(state *connectionState) { + if *state&stateClientReplyOff == 0 { + *state |= stateClientReplySkipNext + } + }, + } + actionClientReply = &commandAction{ + Next: map[string]*commandAction{ + "OFF": actionClientReplyOff, + "OFf": actionClientReplyOff, + "OfF": actionClientReplyOff, + "Off": actionClientReplyOff, + "oFF": actionClientReplyOff, + "oFf": actionClientReplyOff, + "ofF": actionClientReplyOff, + "off": actionClientReplyOff, + "ON": actionClientReplyOn, + "On": actionClientReplyOn, + "oN": actionClientReplyOn, + "on": actionClientReplyOn, + "SKIP": actionClientReplySkip, + "SKIp": actionClientReplySkip, + "SKiP": actionClientReplySkip, + "SKip": actionClientReplySkip, + "SkIP": actionClientReplySkip, + "SkIp": actionClientReplySkip, + "SkiP": actionClientReplySkip, + "Skip": actionClientReplySkip, + "sKIP": actionClientReplySkip, + "sKIp": actionClientReplySkip, + "sKiP": actionClientReplySkip, + "sKip": actionClientReplySkip, + "skIP": actionClientReplySkip, + "skIp": actionClientReplySkip, + "skiP": actionClientReplySkip, + "skip": actionClientReplySkip, + }, + } + actionClient = &commandAction{ + Next: map[string]*commandAction{ + "REPLY": actionClientReply, + "REPLy": actionClientReply, + "REPlY": actionClientReply, + "REPly": actionClientReply, + "REpLY": actionClientReply, + "REpLy": actionClientReply, + "REplY": actionClientReply, + "REply": actionClientReply, + "RePLY": actionClientReply, + "RePLy": actionClientReply, + "RePlY": actionClientReply, + "RePly": actionClientReply, + "RepLY": actionClientReply, + "RepLy": actionClientReply, + "ReplY": actionClientReply, + "Reply": actionClientReply, + "rEPLY": actionClientReply, + "rEPLy": actionClientReply, + "rEPlY": actionClientReply, + "rEPly": actionClientReply, + "rEpLY": actionClientReply, + "rEpLy": actionClientReply, + "rEplY": actionClientReply, + "rEply": actionClientReply, + "rePLY": actionClientReply, + "rePLy": actionClientReply, + "rePlY": actionClientReply, + "rePly": actionClientReply, + "repLY": actionClientReply, + "repLy": actionClientReply, + "replY": actionClientReply, + "reply": actionClientReply, + }, + } + activeConnActions = map[string]*commandAction{ + "WATCH": actionWatch, + "WATCh": actionWatch, + "WATcH": actionWatch, + "WATch": actionWatch, + "WAtCH": actionWatch, + "WAtCh": actionWatch, + "WAtcH": actionWatch, + "WAtch": actionWatch, + "WaTCH": actionWatch, + "WaTCh": actionWatch, + "WaTcH": actionWatch, + "WaTch": actionWatch, + "WatCH": actionWatch, + "WatCh": actionWatch, + "WatcH": actionWatch, + "Watch": actionWatch, + "wATCH": actionWatch, + "wATCh": actionWatch, + "wATcH": actionWatch, + "wATch": actionWatch, + "wAtCH": actionWatch, + "wAtCh": actionWatch, + "wAtcH": actionWatch, + "wAtch": actionWatch, + "waTCH": actionWatch, + "waTCh": actionWatch, + "waTcH": actionWatch, + "waTch": actionWatch, + "watCH": actionWatch, + "watCh": actionWatch, + "watcH": actionWatch, + "watch": actionWatch, + "UNWATCH": actionUnwatch, + "UNWATCh": actionUnwatch, + "UNWATcH": actionUnwatch, + "UNWATch": actionUnwatch, + "UNWAtCH": actionUnwatch, + "UNWAtCh": actionUnwatch, + "UNWAtcH": actionUnwatch, + "UNWAtch": actionUnwatch, + "UNWaTCH": actionUnwatch, + "UNWaTCh": actionUnwatch, + "UNWaTcH": actionUnwatch, + "UNWaTch": actionUnwatch, + "UNWatCH": actionUnwatch, + "UNWatCh": actionUnwatch, + "UNWatcH": actionUnwatch, + "UNWatch": actionUnwatch, + "UNwATCH": actionUnwatch, + "UNwATCh": actionUnwatch, + "UNwATcH": actionUnwatch, + "UNwATch": actionUnwatch, + "UNwAtCH": actionUnwatch, + "UNwAtCh": actionUnwatch, + "UNwAtcH": actionUnwatch, + "UNwAtch": actionUnwatch, + "UNwaTCH": actionUnwatch, + "UNwaTCh": actionUnwatch, + "UNwaTcH": actionUnwatch, + "UNwaTch": actionUnwatch, + "UNwatCH": actionUnwatch, + "UNwatCh": actionUnwatch, + "UNwatcH": actionUnwatch, + "UNwatch": actionUnwatch, + "UnWATCH": actionUnwatch, + "UnWATCh": actionUnwatch, + "UnWATcH": actionUnwatch, + "UnWATch": actionUnwatch, + "UnWAtCH": actionUnwatch, + "UnWAtCh": actionUnwatch, + "UnWAtcH": actionUnwatch, + "UnWAtch": actionUnwatch, + "UnWaTCH": actionUnwatch, + "UnWaTCh": actionUnwatch, + "UnWaTcH": actionUnwatch, + "UnWaTch": actionUnwatch, + "UnWatCH": actionUnwatch, + "UnWatCh": actionUnwatch, + "UnWatcH": actionUnwatch, + "UnWatch": actionUnwatch, + "UnwATCH": actionUnwatch, + "UnwATCh": actionUnwatch, + "UnwATcH": actionUnwatch, + "UnwATch": actionUnwatch, + "UnwAtCH": actionUnwatch, + "UnwAtCh": actionUnwatch, + "UnwAtcH": actionUnwatch, + "UnwAtch": actionUnwatch, + "UnwaTCH": actionUnwatch, + "UnwaTCh": actionUnwatch, + "UnwaTcH": actionUnwatch, + "UnwaTch": actionUnwatch, + "UnwatCH": actionUnwatch, + "UnwatCh": actionUnwatch, + "UnwatcH": actionUnwatch, + "Unwatch": actionUnwatch, + "uNWATCH": actionUnwatch, + "uNWATCh": actionUnwatch, + "uNWATcH": actionUnwatch, + "uNWATch": actionUnwatch, + "uNWAtCH": actionUnwatch, + "uNWAtCh": actionUnwatch, + "uNWAtcH": actionUnwatch, + "uNWAtch": actionUnwatch, + "uNWaTCH": actionUnwatch, + "uNWaTCh": actionUnwatch, + "uNWaTcH": actionUnwatch, + "uNWaTch": actionUnwatch, + "uNWatCH": actionUnwatch, + "uNWatCh": actionUnwatch, + "uNWatcH": actionUnwatch, + "uNWatch": actionUnwatch, + "uNwATCH": actionUnwatch, + "uNwATCh": actionUnwatch, + "uNwATcH": actionUnwatch, + "uNwATch": actionUnwatch, + "uNwAtCH": actionUnwatch, + "uNwAtCh": actionUnwatch, + "uNwAtcH": actionUnwatch, + "uNwAtch": actionUnwatch, + "uNwaTCH": actionUnwatch, + "uNwaTCh": actionUnwatch, + "uNwaTcH": actionUnwatch, + "uNwaTch": actionUnwatch, + "uNwatCH": actionUnwatch, + "uNwatCh": actionUnwatch, + "uNwatcH": actionUnwatch, + "uNwatch": actionUnwatch, + "unWATCH": actionUnwatch, + "unWATCh": actionUnwatch, + "unWATcH": actionUnwatch, + "unWATch": actionUnwatch, + "unWAtCH": actionUnwatch, + "unWAtCh": actionUnwatch, + "unWAtcH": actionUnwatch, + "unWAtch": actionUnwatch, + "unWaTCH": actionUnwatch, + "unWaTCh": actionUnwatch, + "unWaTcH": actionUnwatch, + "unWaTch": actionUnwatch, + "unWatCH": actionUnwatch, + "unWatCh": actionUnwatch, + "unWatcH": actionUnwatch, + "unWatch": actionUnwatch, + "unwATCH": actionUnwatch, + "unwATCh": actionUnwatch, + "unwATcH": actionUnwatch, + "unwATch": actionUnwatch, + "unwAtCH": actionUnwatch, + "unwAtCh": actionUnwatch, + "unwAtcH": actionUnwatch, + "unwAtch": actionUnwatch, + "unwaTCH": actionUnwatch, + "unwaTCh": actionUnwatch, + "unwaTcH": actionUnwatch, + "unwaTch": actionUnwatch, + "unwatCH": actionUnwatch, + "unwatCh": actionUnwatch, + "unwatcH": actionUnwatch, + "unwatch": actionUnwatch, + "MULTI": actionMulti, + "MULTi": actionMulti, + "MULtI": actionMulti, + "MULti": actionMulti, + "MUlTI": actionMulti, + "MUlTi": actionMulti, + "MUltI": actionMulti, + "MUlti": actionMulti, + "MuLTI": actionMulti, + "MuLTi": actionMulti, + "MuLtI": actionMulti, + "MuLti": actionMulti, + "MulTI": actionMulti, + "MulTi": actionMulti, + "MultI": actionMulti, + "Multi": actionMulti, + "mULTI": actionMulti, + "mULTi": actionMulti, + "mULtI": actionMulti, + "mULti": actionMulti, + "mUlTI": actionMulti, + "mUlTi": actionMulti, + "mUltI": actionMulti, + "mUlti": actionMulti, + "muLTI": actionMulti, + "muLTi": actionMulti, + "muLtI": actionMulti, + "muLti": actionMulti, + "mulTI": actionMulti, + "mulTi": actionMulti, + "multI": actionMulti, + "multi": actionMulti, + "EXEC": actionExec, + "EXEc": actionExec, + "EXeC": actionExec, + "EXec": actionExec, + "ExEC": actionExec, + "ExEc": actionExec, + "ExeC": actionExec, + "Exec": actionExec, + "eXEC": actionExec, + "eXEc": actionExec, + "eXeC": actionExec, + "eXec": actionExec, + "exEC": actionExec, + "exEc": actionExec, + "exeC": actionExec, + "exec": actionExec, + "DISCARD": actionDiscard, + "DISCARd": actionDiscard, + "DISCArD": actionDiscard, + "DISCArd": actionDiscard, + "DISCaRD": actionDiscard, + "DISCaRd": actionDiscard, + "DISCarD": actionDiscard, + "DISCard": actionDiscard, + "DIScARD": actionDiscard, + "DIScARd": actionDiscard, + "DIScArD": actionDiscard, + "DIScArd": actionDiscard, + "DIScaRD": actionDiscard, + "DIScaRd": actionDiscard, + "DIScarD": actionDiscard, + "DIScard": actionDiscard, + "DIsCARD": actionDiscard, + "DIsCARd": actionDiscard, + "DIsCArD": actionDiscard, + "DIsCArd": actionDiscard, + "DIsCaRD": actionDiscard, + "DIsCaRd": actionDiscard, + "DIsCarD": actionDiscard, + "DIsCard": actionDiscard, + "DIscARD": actionDiscard, + "DIscARd": actionDiscard, + "DIscArD": actionDiscard, + "DIscArd": actionDiscard, + "DIscaRD": actionDiscard, + "DIscaRd": actionDiscard, + "DIscarD": actionDiscard, + "DIscard": actionDiscard, + "DiSCARD": actionDiscard, + "DiSCARd": actionDiscard, + "DiSCArD": actionDiscard, + "DiSCArd": actionDiscard, + "DiSCaRD": actionDiscard, + "DiSCaRd": actionDiscard, + "DiSCarD": actionDiscard, + "DiSCard": actionDiscard, + "DiScARD": actionDiscard, + "DiScARd": actionDiscard, + "DiScArD": actionDiscard, + "DiScArd": actionDiscard, + "DiScaRD": actionDiscard, + "DiScaRd": actionDiscard, + "DiScarD": actionDiscard, + "DiScard": actionDiscard, + "DisCARD": actionDiscard, + "DisCARd": actionDiscard, + "DisCArD": actionDiscard, + "DisCArd": actionDiscard, + "DisCaRD": actionDiscard, + "DisCaRd": actionDiscard, + "DisCarD": actionDiscard, + "DisCard": actionDiscard, + "DiscARD": actionDiscard, + "DiscARd": actionDiscard, + "DiscArD": actionDiscard, + "DiscArd": actionDiscard, + "DiscaRD": actionDiscard, + "DiscaRd": actionDiscard, + "DiscarD": actionDiscard, + "Discard": actionDiscard, + "dISCARD": actionDiscard, + "dISCARd": actionDiscard, + "dISCArD": actionDiscard, + "dISCArd": actionDiscard, + "dISCaRD": actionDiscard, + "dISCaRd": actionDiscard, + "dISCarD": actionDiscard, + "dISCard": actionDiscard, + "dIScARD": actionDiscard, + "dIScARd": actionDiscard, + "dIScArD": actionDiscard, + "dIScArd": actionDiscard, + "dIScaRD": actionDiscard, + "dIScaRd": actionDiscard, + "dIScarD": actionDiscard, + "dIScard": actionDiscard, + "dIsCARD": actionDiscard, + "dIsCARd": actionDiscard, + "dIsCArD": actionDiscard, + "dIsCArd": actionDiscard, + "dIsCaRD": actionDiscard, + "dIsCaRd": actionDiscard, + "dIsCarD": actionDiscard, + "dIsCard": actionDiscard, + "dIscARD": actionDiscard, + "dIscARd": actionDiscard, + "dIscArD": actionDiscard, + "dIscArd": actionDiscard, + "dIscaRD": actionDiscard, + "dIscaRd": actionDiscard, + "dIscarD": actionDiscard, + "dIscard": actionDiscard, + "diSCARD": actionDiscard, + "diSCARd": actionDiscard, + "diSCArD": actionDiscard, + "diSCArd": actionDiscard, + "diSCaRD": actionDiscard, + "diSCaRd": actionDiscard, + "diSCarD": actionDiscard, + "diSCard": actionDiscard, + "diScARD": actionDiscard, + "diScARd": actionDiscard, + "diScArD": actionDiscard, + "diScArd": actionDiscard, + "diScaRD": actionDiscard, + "diScaRd": actionDiscard, + "diScarD": actionDiscard, + "diScard": actionDiscard, + "disCARD": actionDiscard, + "disCARd": actionDiscard, + "disCArD": actionDiscard, + "disCArd": actionDiscard, + "disCaRD": actionDiscard, + "disCaRd": actionDiscard, + "disCarD": actionDiscard, + "disCard": actionDiscard, + "discARD": actionDiscard, + "discARd": actionDiscard, + "discArD": actionDiscard, + "discArd": actionDiscard, + "discaRD": actionDiscard, + "discaRd": actionDiscard, + "discarD": actionDiscard, + "discard": actionDiscard, + "PSUBSCRIBE": actionPsubscribe, + "PSUBSCRIBe": actionPsubscribe, + "PSUBSCRIbE": actionPsubscribe, + "PSUBSCRIbe": actionPsubscribe, + "PSUBSCRiBE": actionPsubscribe, + "PSUBSCRiBe": actionPsubscribe, + "PSUBSCRibE": actionPsubscribe, + "PSUBSCRibe": actionPsubscribe, + "PSUBSCrIBE": actionPsubscribe, + "PSUBSCrIBe": actionPsubscribe, + "PSUBSCrIbE": actionPsubscribe, + "PSUBSCrIbe": actionPsubscribe, + "PSUBSCriBE": actionPsubscribe, + "PSUBSCriBe": actionPsubscribe, + "PSUBSCribE": actionPsubscribe, + "PSUBSCribe": actionPsubscribe, + "PSUBScRIBE": actionPsubscribe, + "PSUBScRIBe": actionPsubscribe, + "PSUBScRIbE": actionPsubscribe, + "PSUBScRIbe": actionPsubscribe, + "PSUBScRiBE": actionPsubscribe, + "PSUBScRiBe": actionPsubscribe, + "PSUBScRibE": actionPsubscribe, + "PSUBScRibe": actionPsubscribe, + "PSUBScrIBE": actionPsubscribe, + "PSUBScrIBe": actionPsubscribe, + "PSUBScrIbE": actionPsubscribe, + "PSUBScrIbe": actionPsubscribe, + "PSUBScriBE": actionPsubscribe, + "PSUBScriBe": actionPsubscribe, + "PSUBScribE": actionPsubscribe, + "PSUBScribe": actionPsubscribe, + "PSUBsCRIBE": actionPsubscribe, + "PSUBsCRIBe": actionPsubscribe, + "PSUBsCRIbE": actionPsubscribe, + "PSUBsCRIbe": actionPsubscribe, + "PSUBsCRiBE": actionPsubscribe, + "PSUBsCRiBe": actionPsubscribe, + "PSUBsCRibE": actionPsubscribe, + "PSUBsCRibe": actionPsubscribe, + "PSUBsCrIBE": actionPsubscribe, + "PSUBsCrIBe": actionPsubscribe, + "PSUBsCrIbE": actionPsubscribe, + "PSUBsCrIbe": actionPsubscribe, + "PSUBsCriBE": actionPsubscribe, + "PSUBsCriBe": actionPsubscribe, + "PSUBsCribE": actionPsubscribe, + "PSUBsCribe": actionPsubscribe, + "PSUBscRIBE": actionPsubscribe, + "PSUBscRIBe": actionPsubscribe, + "PSUBscRIbE": actionPsubscribe, + "PSUBscRIbe": actionPsubscribe, + "PSUBscRiBE": actionPsubscribe, + "PSUBscRiBe": actionPsubscribe, + "PSUBscRibE": actionPsubscribe, + "PSUBscRibe": actionPsubscribe, + "PSUBscrIBE": actionPsubscribe, + "PSUBscrIBe": actionPsubscribe, + "PSUBscrIbE": actionPsubscribe, + "PSUBscrIbe": actionPsubscribe, + "PSUBscriBE": actionPsubscribe, + "PSUBscriBe": actionPsubscribe, + "PSUBscribE": actionPsubscribe, + "PSUBscribe": actionPsubscribe, + "PSUbSCRIBE": actionPsubscribe, + "PSUbSCRIBe": actionPsubscribe, + "PSUbSCRIbE": actionPsubscribe, + "PSUbSCRIbe": actionPsubscribe, + "PSUbSCRiBE": actionPsubscribe, + "PSUbSCRiBe": actionPsubscribe, + "PSUbSCRibE": actionPsubscribe, + "PSUbSCRibe": actionPsubscribe, + "PSUbSCrIBE": actionPsubscribe, + "PSUbSCrIBe": actionPsubscribe, + "PSUbSCrIbE": actionPsubscribe, + "PSUbSCrIbe": actionPsubscribe, + "PSUbSCriBE": actionPsubscribe, + "PSUbSCriBe": actionPsubscribe, + "PSUbSCribE": actionPsubscribe, + "PSUbSCribe": actionPsubscribe, + "PSUbScRIBE": actionPsubscribe, + "PSUbScRIBe": actionPsubscribe, + "PSUbScRIbE": actionPsubscribe, + "PSUbScRIbe": actionPsubscribe, + "PSUbScRiBE": actionPsubscribe, + "PSUbScRiBe": actionPsubscribe, + "PSUbScRibE": actionPsubscribe, + "PSUbScRibe": actionPsubscribe, + "PSUbScrIBE": actionPsubscribe, + "PSUbScrIBe": actionPsubscribe, + "PSUbScrIbE": actionPsubscribe, + "PSUbScrIbe": actionPsubscribe, + "PSUbScriBE": actionPsubscribe, + "PSUbScriBe": actionPsubscribe, + "PSUbScribE": actionPsubscribe, + "PSUbScribe": actionPsubscribe, + "PSUbsCRIBE": actionPsubscribe, + "PSUbsCRIBe": actionPsubscribe, + "PSUbsCRIbE": actionPsubscribe, + "PSUbsCRIbe": actionPsubscribe, + "PSUbsCRiBE": actionPsubscribe, + "PSUbsCRiBe": actionPsubscribe, + "PSUbsCRibE": actionPsubscribe, + "PSUbsCRibe": actionPsubscribe, + "PSUbsCrIBE": actionPsubscribe, + "PSUbsCrIBe": actionPsubscribe, + "PSUbsCrIbE": actionPsubscribe, + "PSUbsCrIbe": actionPsubscribe, + "PSUbsCriBE": actionPsubscribe, + "PSUbsCriBe": actionPsubscribe, + "PSUbsCribE": actionPsubscribe, + "PSUbsCribe": actionPsubscribe, + "PSUbscRIBE": actionPsubscribe, + "PSUbscRIBe": actionPsubscribe, + "PSUbscRIbE": actionPsubscribe, + "PSUbscRIbe": actionPsubscribe, + "PSUbscRiBE": actionPsubscribe, + "PSUbscRiBe": actionPsubscribe, + "PSUbscRibE": actionPsubscribe, + "PSUbscRibe": actionPsubscribe, + "PSUbscrIBE": actionPsubscribe, + "PSUbscrIBe": actionPsubscribe, + "PSUbscrIbE": actionPsubscribe, + "PSUbscrIbe": actionPsubscribe, + "PSUbscriBE": actionPsubscribe, + "PSUbscriBe": actionPsubscribe, + "PSUbscribE": actionPsubscribe, + "PSUbscribe": actionPsubscribe, + "PSuBSCRIBE": actionPsubscribe, + "PSuBSCRIBe": actionPsubscribe, + "PSuBSCRIbE": actionPsubscribe, + "PSuBSCRIbe": actionPsubscribe, + "PSuBSCRiBE": actionPsubscribe, + "PSuBSCRiBe": actionPsubscribe, + "PSuBSCRibE": actionPsubscribe, + "PSuBSCRibe": actionPsubscribe, + "PSuBSCrIBE": actionPsubscribe, + "PSuBSCrIBe": actionPsubscribe, + "PSuBSCrIbE": actionPsubscribe, + "PSuBSCrIbe": actionPsubscribe, + "PSuBSCriBE": actionPsubscribe, + "PSuBSCriBe": actionPsubscribe, + "PSuBSCribE": actionPsubscribe, + "PSuBSCribe": actionPsubscribe, + "PSuBScRIBE": actionPsubscribe, + "PSuBScRIBe": actionPsubscribe, + "PSuBScRIbE": actionPsubscribe, + "PSuBScRIbe": actionPsubscribe, + "PSuBScRiBE": actionPsubscribe, + "PSuBScRiBe": actionPsubscribe, + "PSuBScRibE": actionPsubscribe, + "PSuBScRibe": actionPsubscribe, + "PSuBScrIBE": actionPsubscribe, + "PSuBScrIBe": actionPsubscribe, + "PSuBScrIbE": actionPsubscribe, + "PSuBScrIbe": actionPsubscribe, + "PSuBScriBE": actionPsubscribe, + "PSuBScriBe": actionPsubscribe, + "PSuBScribE": actionPsubscribe, + "PSuBScribe": actionPsubscribe, + "PSuBsCRIBE": actionPsubscribe, + "PSuBsCRIBe": actionPsubscribe, + "PSuBsCRIbE": actionPsubscribe, + "PSuBsCRIbe": actionPsubscribe, + "PSuBsCRiBE": actionPsubscribe, + "PSuBsCRiBe": actionPsubscribe, + "PSuBsCRibE": actionPsubscribe, + "PSuBsCRibe": actionPsubscribe, + "PSuBsCrIBE": actionPsubscribe, + "PSuBsCrIBe": actionPsubscribe, + "PSuBsCrIbE": actionPsubscribe, + "PSuBsCrIbe": actionPsubscribe, + "PSuBsCriBE": actionPsubscribe, + "PSuBsCriBe": actionPsubscribe, + "PSuBsCribE": actionPsubscribe, + "PSuBsCribe": actionPsubscribe, + "PSuBscRIBE": actionPsubscribe, + "PSuBscRIBe": actionPsubscribe, + "PSuBscRIbE": actionPsubscribe, + "PSuBscRIbe": actionPsubscribe, + "PSuBscRiBE": actionPsubscribe, + "PSuBscRiBe": actionPsubscribe, + "PSuBscRibE": actionPsubscribe, + "PSuBscRibe": actionPsubscribe, + "PSuBscrIBE": actionPsubscribe, + "PSuBscrIBe": actionPsubscribe, + "PSuBscrIbE": actionPsubscribe, + "PSuBscrIbe": actionPsubscribe, + "PSuBscriBE": actionPsubscribe, + "PSuBscriBe": actionPsubscribe, + "PSuBscribE": actionPsubscribe, + "PSuBscribe": actionPsubscribe, + "PSubSCRIBE": actionPsubscribe, + "PSubSCRIBe": actionPsubscribe, + "PSubSCRIbE": actionPsubscribe, + "PSubSCRIbe": actionPsubscribe, + "PSubSCRiBE": actionPsubscribe, + "PSubSCRiBe": actionPsubscribe, + "PSubSCRibE": actionPsubscribe, + "PSubSCRibe": actionPsubscribe, + "PSubSCrIBE": actionPsubscribe, + "PSubSCrIBe": actionPsubscribe, + "PSubSCrIbE": actionPsubscribe, + "PSubSCrIbe": actionPsubscribe, + "PSubSCriBE": actionPsubscribe, + "PSubSCriBe": actionPsubscribe, + "PSubSCribE": actionPsubscribe, + "PSubSCribe": actionPsubscribe, + "PSubScRIBE": actionPsubscribe, + "PSubScRIBe": actionPsubscribe, + "PSubScRIbE": actionPsubscribe, + "PSubScRIbe": actionPsubscribe, + "PSubScRiBE": actionPsubscribe, + "PSubScRiBe": actionPsubscribe, + "PSubScRibE": actionPsubscribe, + "PSubScRibe": actionPsubscribe, + "PSubScrIBE": actionPsubscribe, + "PSubScrIBe": actionPsubscribe, + "PSubScrIbE": actionPsubscribe, + "PSubScrIbe": actionPsubscribe, + "PSubScriBE": actionPsubscribe, + "PSubScriBe": actionPsubscribe, + "PSubScribE": actionPsubscribe, + "PSubScribe": actionPsubscribe, + "PSubsCRIBE": actionPsubscribe, + "PSubsCRIBe": actionPsubscribe, + "PSubsCRIbE": actionPsubscribe, + "PSubsCRIbe": actionPsubscribe, + "PSubsCRiBE": actionPsubscribe, + "PSubsCRiBe": actionPsubscribe, + "PSubsCRibE": actionPsubscribe, + "PSubsCRibe": actionPsubscribe, + "PSubsCrIBE": actionPsubscribe, + "PSubsCrIBe": actionPsubscribe, + "PSubsCrIbE": actionPsubscribe, + "PSubsCrIbe": actionPsubscribe, + "PSubsCriBE": actionPsubscribe, + "PSubsCriBe": actionPsubscribe, + "PSubsCribE": actionPsubscribe, + "PSubsCribe": actionPsubscribe, + "PSubscRIBE": actionPsubscribe, + "PSubscRIBe": actionPsubscribe, + "PSubscRIbE": actionPsubscribe, + "PSubscRIbe": actionPsubscribe, + "PSubscRiBE": actionPsubscribe, + "PSubscRiBe": actionPsubscribe, + "PSubscRibE": actionPsubscribe, + "PSubscRibe": actionPsubscribe, + "PSubscrIBE": actionPsubscribe, + "PSubscrIBe": actionPsubscribe, + "PSubscrIbE": actionPsubscribe, + "PSubscrIbe": actionPsubscribe, + "PSubscriBE": actionPsubscribe, + "PSubscriBe": actionPsubscribe, + "PSubscribE": actionPsubscribe, + "PSubscribe": actionPsubscribe, + "PsUBSCRIBE": actionPsubscribe, + "PsUBSCRIBe": actionPsubscribe, + "PsUBSCRIbE": actionPsubscribe, + "PsUBSCRIbe": actionPsubscribe, + "PsUBSCRiBE": actionPsubscribe, + "PsUBSCRiBe": actionPsubscribe, + "PsUBSCRibE": actionPsubscribe, + "PsUBSCRibe": actionPsubscribe, + "PsUBSCrIBE": actionPsubscribe, + "PsUBSCrIBe": actionPsubscribe, + "PsUBSCrIbE": actionPsubscribe, + "PsUBSCrIbe": actionPsubscribe, + "PsUBSCriBE": actionPsubscribe, + "PsUBSCriBe": actionPsubscribe, + "PsUBSCribE": actionPsubscribe, + "PsUBSCribe": actionPsubscribe, + "PsUBScRIBE": actionPsubscribe, + "PsUBScRIBe": actionPsubscribe, + "PsUBScRIbE": actionPsubscribe, + "PsUBScRIbe": actionPsubscribe, + "PsUBScRiBE": actionPsubscribe, + "PsUBScRiBe": actionPsubscribe, + "PsUBScRibE": actionPsubscribe, + "PsUBScRibe": actionPsubscribe, + "PsUBScrIBE": actionPsubscribe, + "PsUBScrIBe": actionPsubscribe, + "PsUBScrIbE": actionPsubscribe, + "PsUBScrIbe": actionPsubscribe, + "PsUBScriBE": actionPsubscribe, + "PsUBScriBe": actionPsubscribe, + "PsUBScribE": actionPsubscribe, + "PsUBScribe": actionPsubscribe, + "PsUBsCRIBE": actionPsubscribe, + "PsUBsCRIBe": actionPsubscribe, + "PsUBsCRIbE": actionPsubscribe, + "PsUBsCRIbe": actionPsubscribe, + "PsUBsCRiBE": actionPsubscribe, + "PsUBsCRiBe": actionPsubscribe, + "PsUBsCRibE": actionPsubscribe, + "PsUBsCRibe": actionPsubscribe, + "PsUBsCrIBE": actionPsubscribe, + "PsUBsCrIBe": actionPsubscribe, + "PsUBsCrIbE": actionPsubscribe, + "PsUBsCrIbe": actionPsubscribe, + "PsUBsCriBE": actionPsubscribe, + "PsUBsCriBe": actionPsubscribe, + "PsUBsCribE": actionPsubscribe, + "PsUBsCribe": actionPsubscribe, + "PsUBscRIBE": actionPsubscribe, + "PsUBscRIBe": actionPsubscribe, + "PsUBscRIbE": actionPsubscribe, + "PsUBscRIbe": actionPsubscribe, + "PsUBscRiBE": actionPsubscribe, + "PsUBscRiBe": actionPsubscribe, + "PsUBscRibE": actionPsubscribe, + "PsUBscRibe": actionPsubscribe, + "PsUBscrIBE": actionPsubscribe, + "PsUBscrIBe": actionPsubscribe, + "PsUBscrIbE": actionPsubscribe, + "PsUBscrIbe": actionPsubscribe, + "PsUBscriBE": actionPsubscribe, + "PsUBscriBe": actionPsubscribe, + "PsUBscribE": actionPsubscribe, + "PsUBscribe": actionPsubscribe, + "PsUbSCRIBE": actionPsubscribe, + "PsUbSCRIBe": actionPsubscribe, + "PsUbSCRIbE": actionPsubscribe, + "PsUbSCRIbe": actionPsubscribe, + "PsUbSCRiBE": actionPsubscribe, + "PsUbSCRiBe": actionPsubscribe, + "PsUbSCRibE": actionPsubscribe, + "PsUbSCRibe": actionPsubscribe, + "PsUbSCrIBE": actionPsubscribe, + "PsUbSCrIBe": actionPsubscribe, + "PsUbSCrIbE": actionPsubscribe, + "PsUbSCrIbe": actionPsubscribe, + "PsUbSCriBE": actionPsubscribe, + "PsUbSCriBe": actionPsubscribe, + "PsUbSCribE": actionPsubscribe, + "PsUbSCribe": actionPsubscribe, + "PsUbScRIBE": actionPsubscribe, + "PsUbScRIBe": actionPsubscribe, + "PsUbScRIbE": actionPsubscribe, + "PsUbScRIbe": actionPsubscribe, + "PsUbScRiBE": actionPsubscribe, + "PsUbScRiBe": actionPsubscribe, + "PsUbScRibE": actionPsubscribe, + "PsUbScRibe": actionPsubscribe, + "PsUbScrIBE": actionPsubscribe, + "PsUbScrIBe": actionPsubscribe, + "PsUbScrIbE": actionPsubscribe, + "PsUbScrIbe": actionPsubscribe, + "PsUbScriBE": actionPsubscribe, + "PsUbScriBe": actionPsubscribe, + "PsUbScribE": actionPsubscribe, + "PsUbScribe": actionPsubscribe, + "PsUbsCRIBE": actionPsubscribe, + "PsUbsCRIBe": actionPsubscribe, + "PsUbsCRIbE": actionPsubscribe, + "PsUbsCRIbe": actionPsubscribe, + "PsUbsCRiBE": actionPsubscribe, + "PsUbsCRiBe": actionPsubscribe, + "PsUbsCRibE": actionPsubscribe, + "PsUbsCRibe": actionPsubscribe, + "PsUbsCrIBE": actionPsubscribe, + "PsUbsCrIBe": actionPsubscribe, + "PsUbsCrIbE": actionPsubscribe, + "PsUbsCrIbe": actionPsubscribe, + "PsUbsCriBE": actionPsubscribe, + "PsUbsCriBe": actionPsubscribe, + "PsUbsCribE": actionPsubscribe, + "PsUbsCribe": actionPsubscribe, + "PsUbscRIBE": actionPsubscribe, + "PsUbscRIBe": actionPsubscribe, + "PsUbscRIbE": actionPsubscribe, + "PsUbscRIbe": actionPsubscribe, + "PsUbscRiBE": actionPsubscribe, + "PsUbscRiBe": actionPsubscribe, + "PsUbscRibE": actionPsubscribe, + "PsUbscRibe": actionPsubscribe, + "PsUbscrIBE": actionPsubscribe, + "PsUbscrIBe": actionPsubscribe, + "PsUbscrIbE": actionPsubscribe, + "PsUbscrIbe": actionPsubscribe, + "PsUbscriBE": actionPsubscribe, + "PsUbscriBe": actionPsubscribe, + "PsUbscribE": actionPsubscribe, + "PsUbscribe": actionPsubscribe, + "PsuBSCRIBE": actionPsubscribe, + "PsuBSCRIBe": actionPsubscribe, + "PsuBSCRIbE": actionPsubscribe, + "PsuBSCRIbe": actionPsubscribe, + "PsuBSCRiBE": actionPsubscribe, + "PsuBSCRiBe": actionPsubscribe, + "PsuBSCRibE": actionPsubscribe, + "PsuBSCRibe": actionPsubscribe, + "PsuBSCrIBE": actionPsubscribe, + "PsuBSCrIBe": actionPsubscribe, + "PsuBSCrIbE": actionPsubscribe, + "PsuBSCrIbe": actionPsubscribe, + "PsuBSCriBE": actionPsubscribe, + "PsuBSCriBe": actionPsubscribe, + "PsuBSCribE": actionPsubscribe, + "PsuBSCribe": actionPsubscribe, + "PsuBScRIBE": actionPsubscribe, + "PsuBScRIBe": actionPsubscribe, + "PsuBScRIbE": actionPsubscribe, + "PsuBScRIbe": actionPsubscribe, + "PsuBScRiBE": actionPsubscribe, + "PsuBScRiBe": actionPsubscribe, + "PsuBScRibE": actionPsubscribe, + "PsuBScRibe": actionPsubscribe, + "PsuBScrIBE": actionPsubscribe, + "PsuBScrIBe": actionPsubscribe, + "PsuBScrIbE": actionPsubscribe, + "PsuBScrIbe": actionPsubscribe, + "PsuBScriBE": actionPsubscribe, + "PsuBScriBe": actionPsubscribe, + "PsuBScribE": actionPsubscribe, + "PsuBScribe": actionPsubscribe, + "PsuBsCRIBE": actionPsubscribe, + "PsuBsCRIBe": actionPsubscribe, + "PsuBsCRIbE": actionPsubscribe, + "PsuBsCRIbe": actionPsubscribe, + "PsuBsCRiBE": actionPsubscribe, + "PsuBsCRiBe": actionPsubscribe, + "PsuBsCRibE": actionPsubscribe, + "PsuBsCRibe": actionPsubscribe, + "PsuBsCrIBE": actionPsubscribe, + "PsuBsCrIBe": actionPsubscribe, + "PsuBsCrIbE": actionPsubscribe, + "PsuBsCrIbe": actionPsubscribe, + "PsuBsCriBE": actionPsubscribe, + "PsuBsCriBe": actionPsubscribe, + "PsuBsCribE": actionPsubscribe, + "PsuBsCribe": actionPsubscribe, + "PsuBscRIBE": actionPsubscribe, + "PsuBscRIBe": actionPsubscribe, + "PsuBscRIbE": actionPsubscribe, + "PsuBscRIbe": actionPsubscribe, + "PsuBscRiBE": actionPsubscribe, + "PsuBscRiBe": actionPsubscribe, + "PsuBscRibE": actionPsubscribe, + "PsuBscRibe": actionPsubscribe, + "PsuBscrIBE": actionPsubscribe, + "PsuBscrIBe": actionPsubscribe, + "PsuBscrIbE": actionPsubscribe, + "PsuBscrIbe": actionPsubscribe, + "PsuBscriBE": actionPsubscribe, + "PsuBscriBe": actionPsubscribe, + "PsuBscribE": actionPsubscribe, + "PsuBscribe": actionPsubscribe, + "PsubSCRIBE": actionPsubscribe, + "PsubSCRIBe": actionPsubscribe, + "PsubSCRIbE": actionPsubscribe, + "PsubSCRIbe": actionPsubscribe, + "PsubSCRiBE": actionPsubscribe, + "PsubSCRiBe": actionPsubscribe, + "PsubSCRibE": actionPsubscribe, + "PsubSCRibe": actionPsubscribe, + "PsubSCrIBE": actionPsubscribe, + "PsubSCrIBe": actionPsubscribe, + "PsubSCrIbE": actionPsubscribe, + "PsubSCrIbe": actionPsubscribe, + "PsubSCriBE": actionPsubscribe, + "PsubSCriBe": actionPsubscribe, + "PsubSCribE": actionPsubscribe, + "PsubSCribe": actionPsubscribe, + "PsubScRIBE": actionPsubscribe, + "PsubScRIBe": actionPsubscribe, + "PsubScRIbE": actionPsubscribe, + "PsubScRIbe": actionPsubscribe, + "PsubScRiBE": actionPsubscribe, + "PsubScRiBe": actionPsubscribe, + "PsubScRibE": actionPsubscribe, + "PsubScRibe": actionPsubscribe, + "PsubScrIBE": actionPsubscribe, + "PsubScrIBe": actionPsubscribe, + "PsubScrIbE": actionPsubscribe, + "PsubScrIbe": actionPsubscribe, + "PsubScriBE": actionPsubscribe, + "PsubScriBe": actionPsubscribe, + "PsubScribE": actionPsubscribe, + "PsubScribe": actionPsubscribe, + "PsubsCRIBE": actionPsubscribe, + "PsubsCRIBe": actionPsubscribe, + "PsubsCRIbE": actionPsubscribe, + "PsubsCRIbe": actionPsubscribe, + "PsubsCRiBE": actionPsubscribe, + "PsubsCRiBe": actionPsubscribe, + "PsubsCRibE": actionPsubscribe, + "PsubsCRibe": actionPsubscribe, + "PsubsCrIBE": actionPsubscribe, + "PsubsCrIBe": actionPsubscribe, + "PsubsCrIbE": actionPsubscribe, + "PsubsCrIbe": actionPsubscribe, + "PsubsCriBE": actionPsubscribe, + "PsubsCriBe": actionPsubscribe, + "PsubsCribE": actionPsubscribe, + "PsubsCribe": actionPsubscribe, + "PsubscRIBE": actionPsubscribe, + "PsubscRIBe": actionPsubscribe, + "PsubscRIbE": actionPsubscribe, + "PsubscRIbe": actionPsubscribe, + "PsubscRiBE": actionPsubscribe, + "PsubscRiBe": actionPsubscribe, + "PsubscRibE": actionPsubscribe, + "PsubscRibe": actionPsubscribe, + "PsubscrIBE": actionPsubscribe, + "PsubscrIBe": actionPsubscribe, + "PsubscrIbE": actionPsubscribe, + "PsubscrIbe": actionPsubscribe, + "PsubscriBE": actionPsubscribe, + "PsubscriBe": actionPsubscribe, + "PsubscribE": actionPsubscribe, + "Psubscribe": actionPsubscribe, + "pSUBSCRIBE": actionPsubscribe, + "pSUBSCRIBe": actionPsubscribe, + "pSUBSCRIbE": actionPsubscribe, + "pSUBSCRIbe": actionPsubscribe, + "pSUBSCRiBE": actionPsubscribe, + "pSUBSCRiBe": actionPsubscribe, + "pSUBSCRibE": actionPsubscribe, + "pSUBSCRibe": actionPsubscribe, + "pSUBSCrIBE": actionPsubscribe, + "pSUBSCrIBe": actionPsubscribe, + "pSUBSCrIbE": actionPsubscribe, + "pSUBSCrIbe": actionPsubscribe, + "pSUBSCriBE": actionPsubscribe, + "pSUBSCriBe": actionPsubscribe, + "pSUBSCribE": actionPsubscribe, + "pSUBSCribe": actionPsubscribe, + "pSUBScRIBE": actionPsubscribe, + "pSUBScRIBe": actionPsubscribe, + "pSUBScRIbE": actionPsubscribe, + "pSUBScRIbe": actionPsubscribe, + "pSUBScRiBE": actionPsubscribe, + "pSUBScRiBe": actionPsubscribe, + "pSUBScRibE": actionPsubscribe, + "pSUBScRibe": actionPsubscribe, + "pSUBScrIBE": actionPsubscribe, + "pSUBScrIBe": actionPsubscribe, + "pSUBScrIbE": actionPsubscribe, + "pSUBScrIbe": actionPsubscribe, + "pSUBScriBE": actionPsubscribe, + "pSUBScriBe": actionPsubscribe, + "pSUBScribE": actionPsubscribe, + "pSUBScribe": actionPsubscribe, + "pSUBsCRIBE": actionPsubscribe, + "pSUBsCRIBe": actionPsubscribe, + "pSUBsCRIbE": actionPsubscribe, + "pSUBsCRIbe": actionPsubscribe, + "pSUBsCRiBE": actionPsubscribe, + "pSUBsCRiBe": actionPsubscribe, + "pSUBsCRibE": actionPsubscribe, + "pSUBsCRibe": actionPsubscribe, + "pSUBsCrIBE": actionPsubscribe, + "pSUBsCrIBe": actionPsubscribe, + "pSUBsCrIbE": actionPsubscribe, + "pSUBsCrIbe": actionPsubscribe, + "pSUBsCriBE": actionPsubscribe, + "pSUBsCriBe": actionPsubscribe, + "pSUBsCribE": actionPsubscribe, + "pSUBsCribe": actionPsubscribe, + "pSUBscRIBE": actionPsubscribe, + "pSUBscRIBe": actionPsubscribe, + "pSUBscRIbE": actionPsubscribe, + "pSUBscRIbe": actionPsubscribe, + "pSUBscRiBE": actionPsubscribe, + "pSUBscRiBe": actionPsubscribe, + "pSUBscRibE": actionPsubscribe, + "pSUBscRibe": actionPsubscribe, + "pSUBscrIBE": actionPsubscribe, + "pSUBscrIBe": actionPsubscribe, + "pSUBscrIbE": actionPsubscribe, + "pSUBscrIbe": actionPsubscribe, + "pSUBscriBE": actionPsubscribe, + "pSUBscriBe": actionPsubscribe, + "pSUBscribE": actionPsubscribe, + "pSUBscribe": actionPsubscribe, + "pSUbSCRIBE": actionPsubscribe, + "pSUbSCRIBe": actionPsubscribe, + "pSUbSCRIbE": actionPsubscribe, + "pSUbSCRIbe": actionPsubscribe, + "pSUbSCRiBE": actionPsubscribe, + "pSUbSCRiBe": actionPsubscribe, + "pSUbSCRibE": actionPsubscribe, + "pSUbSCRibe": actionPsubscribe, + "pSUbSCrIBE": actionPsubscribe, + "pSUbSCrIBe": actionPsubscribe, + "pSUbSCrIbE": actionPsubscribe, + "pSUbSCrIbe": actionPsubscribe, + "pSUbSCriBE": actionPsubscribe, + "pSUbSCriBe": actionPsubscribe, + "pSUbSCribE": actionPsubscribe, + "pSUbSCribe": actionPsubscribe, + "pSUbScRIBE": actionPsubscribe, + "pSUbScRIBe": actionPsubscribe, + "pSUbScRIbE": actionPsubscribe, + "pSUbScRIbe": actionPsubscribe, + "pSUbScRiBE": actionPsubscribe, + "pSUbScRiBe": actionPsubscribe, + "pSUbScRibE": actionPsubscribe, + "pSUbScRibe": actionPsubscribe, + "pSUbScrIBE": actionPsubscribe, + "pSUbScrIBe": actionPsubscribe, + "pSUbScrIbE": actionPsubscribe, + "pSUbScrIbe": actionPsubscribe, + "pSUbScriBE": actionPsubscribe, + "pSUbScriBe": actionPsubscribe, + "pSUbScribE": actionPsubscribe, + "pSUbScribe": actionPsubscribe, + "pSUbsCRIBE": actionPsubscribe, + "pSUbsCRIBe": actionPsubscribe, + "pSUbsCRIbE": actionPsubscribe, + "pSUbsCRIbe": actionPsubscribe, + "pSUbsCRiBE": actionPsubscribe, + "pSUbsCRiBe": actionPsubscribe, + "pSUbsCRibE": actionPsubscribe, + "pSUbsCRibe": actionPsubscribe, + "pSUbsCrIBE": actionPsubscribe, + "pSUbsCrIBe": actionPsubscribe, + "pSUbsCrIbE": actionPsubscribe, + "pSUbsCrIbe": actionPsubscribe, + "pSUbsCriBE": actionPsubscribe, + "pSUbsCriBe": actionPsubscribe, + "pSUbsCribE": actionPsubscribe, + "pSUbsCribe": actionPsubscribe, + "pSUbscRIBE": actionPsubscribe, + "pSUbscRIBe": actionPsubscribe, + "pSUbscRIbE": actionPsubscribe, + "pSUbscRIbe": actionPsubscribe, + "pSUbscRiBE": actionPsubscribe, + "pSUbscRiBe": actionPsubscribe, + "pSUbscRibE": actionPsubscribe, + "pSUbscRibe": actionPsubscribe, + "pSUbscrIBE": actionPsubscribe, + "pSUbscrIBe": actionPsubscribe, + "pSUbscrIbE": actionPsubscribe, + "pSUbscrIbe": actionPsubscribe, + "pSUbscriBE": actionPsubscribe, + "pSUbscriBe": actionPsubscribe, + "pSUbscribE": actionPsubscribe, + "pSUbscribe": actionPsubscribe, + "pSuBSCRIBE": actionPsubscribe, + "pSuBSCRIBe": actionPsubscribe, + "pSuBSCRIbE": actionPsubscribe, + "pSuBSCRIbe": actionPsubscribe, + "pSuBSCRiBE": actionPsubscribe, + "pSuBSCRiBe": actionPsubscribe, + "pSuBSCRibE": actionPsubscribe, + "pSuBSCRibe": actionPsubscribe, + "pSuBSCrIBE": actionPsubscribe, + "pSuBSCrIBe": actionPsubscribe, + "pSuBSCrIbE": actionPsubscribe, + "pSuBSCrIbe": actionPsubscribe, + "pSuBSCriBE": actionPsubscribe, + "pSuBSCriBe": actionPsubscribe, + "pSuBSCribE": actionPsubscribe, + "pSuBSCribe": actionPsubscribe, + "pSuBScRIBE": actionPsubscribe, + "pSuBScRIBe": actionPsubscribe, + "pSuBScRIbE": actionPsubscribe, + "pSuBScRIbe": actionPsubscribe, + "pSuBScRiBE": actionPsubscribe, + "pSuBScRiBe": actionPsubscribe, + "pSuBScRibE": actionPsubscribe, + "pSuBScRibe": actionPsubscribe, + "pSuBScrIBE": actionPsubscribe, + "pSuBScrIBe": actionPsubscribe, + "pSuBScrIbE": actionPsubscribe, + "pSuBScrIbe": actionPsubscribe, + "pSuBScriBE": actionPsubscribe, + "pSuBScriBe": actionPsubscribe, + "pSuBScribE": actionPsubscribe, + "pSuBScribe": actionPsubscribe, + "pSuBsCRIBE": actionPsubscribe, + "pSuBsCRIBe": actionPsubscribe, + "pSuBsCRIbE": actionPsubscribe, + "pSuBsCRIbe": actionPsubscribe, + "pSuBsCRiBE": actionPsubscribe, + "pSuBsCRiBe": actionPsubscribe, + "pSuBsCRibE": actionPsubscribe, + "pSuBsCRibe": actionPsubscribe, + "pSuBsCrIBE": actionPsubscribe, + "pSuBsCrIBe": actionPsubscribe, + "pSuBsCrIbE": actionPsubscribe, + "pSuBsCrIbe": actionPsubscribe, + "pSuBsCriBE": actionPsubscribe, + "pSuBsCriBe": actionPsubscribe, + "pSuBsCribE": actionPsubscribe, + "pSuBsCribe": actionPsubscribe, + "pSuBscRIBE": actionPsubscribe, + "pSuBscRIBe": actionPsubscribe, + "pSuBscRIbE": actionPsubscribe, + "pSuBscRIbe": actionPsubscribe, + "pSuBscRiBE": actionPsubscribe, + "pSuBscRiBe": actionPsubscribe, + "pSuBscRibE": actionPsubscribe, + "pSuBscRibe": actionPsubscribe, + "pSuBscrIBE": actionPsubscribe, + "pSuBscrIBe": actionPsubscribe, + "pSuBscrIbE": actionPsubscribe, + "pSuBscrIbe": actionPsubscribe, + "pSuBscriBE": actionPsubscribe, + "pSuBscriBe": actionPsubscribe, + "pSuBscribE": actionPsubscribe, + "pSuBscribe": actionPsubscribe, + "pSubSCRIBE": actionPsubscribe, + "pSubSCRIBe": actionPsubscribe, + "pSubSCRIbE": actionPsubscribe, + "pSubSCRIbe": actionPsubscribe, + "pSubSCRiBE": actionPsubscribe, + "pSubSCRiBe": actionPsubscribe, + "pSubSCRibE": actionPsubscribe, + "pSubSCRibe": actionPsubscribe, + "pSubSCrIBE": actionPsubscribe, + "pSubSCrIBe": actionPsubscribe, + "pSubSCrIbE": actionPsubscribe, + "pSubSCrIbe": actionPsubscribe, + "pSubSCriBE": actionPsubscribe, + "pSubSCriBe": actionPsubscribe, + "pSubSCribE": actionPsubscribe, + "pSubSCribe": actionPsubscribe, + "pSubScRIBE": actionPsubscribe, + "pSubScRIBe": actionPsubscribe, + "pSubScRIbE": actionPsubscribe, + "pSubScRIbe": actionPsubscribe, + "pSubScRiBE": actionPsubscribe, + "pSubScRiBe": actionPsubscribe, + "pSubScRibE": actionPsubscribe, + "pSubScRibe": actionPsubscribe, + "pSubScrIBE": actionPsubscribe, + "pSubScrIBe": actionPsubscribe, + "pSubScrIbE": actionPsubscribe, + "pSubScrIbe": actionPsubscribe, + "pSubScriBE": actionPsubscribe, + "pSubScriBe": actionPsubscribe, + "pSubScribE": actionPsubscribe, + "pSubScribe": actionPsubscribe, + "pSubsCRIBE": actionPsubscribe, + "pSubsCRIBe": actionPsubscribe, + "pSubsCRIbE": actionPsubscribe, + "pSubsCRIbe": actionPsubscribe, + "pSubsCRiBE": actionPsubscribe, + "pSubsCRiBe": actionPsubscribe, + "pSubsCRibE": actionPsubscribe, + "pSubsCRibe": actionPsubscribe, + "pSubsCrIBE": actionPsubscribe, + "pSubsCrIBe": actionPsubscribe, + "pSubsCrIbE": actionPsubscribe, + "pSubsCrIbe": actionPsubscribe, + "pSubsCriBE": actionPsubscribe, + "pSubsCriBe": actionPsubscribe, + "pSubsCribE": actionPsubscribe, + "pSubsCribe": actionPsubscribe, + "pSubscRIBE": actionPsubscribe, + "pSubscRIBe": actionPsubscribe, + "pSubscRIbE": actionPsubscribe, + "pSubscRIbe": actionPsubscribe, + "pSubscRiBE": actionPsubscribe, + "pSubscRiBe": actionPsubscribe, + "pSubscRibE": actionPsubscribe, + "pSubscRibe": actionPsubscribe, + "pSubscrIBE": actionPsubscribe, + "pSubscrIBe": actionPsubscribe, + "pSubscrIbE": actionPsubscribe, + "pSubscrIbe": actionPsubscribe, + "pSubscriBE": actionPsubscribe, + "pSubscriBe": actionPsubscribe, + "pSubscribE": actionPsubscribe, + "pSubscribe": actionPsubscribe, + "psUBSCRIBE": actionPsubscribe, + "psUBSCRIBe": actionPsubscribe, + "psUBSCRIbE": actionPsubscribe, + "psUBSCRIbe": actionPsubscribe, + "psUBSCRiBE": actionPsubscribe, + "psUBSCRiBe": actionPsubscribe, + "psUBSCRibE": actionPsubscribe, + "psUBSCRibe": actionPsubscribe, + "psUBSCrIBE": actionPsubscribe, + "psUBSCrIBe": actionPsubscribe, + "psUBSCrIbE": actionPsubscribe, + "psUBSCrIbe": actionPsubscribe, + "psUBSCriBE": actionPsubscribe, + "psUBSCriBe": actionPsubscribe, + "psUBSCribE": actionPsubscribe, + "psUBSCribe": actionPsubscribe, + "psUBScRIBE": actionPsubscribe, + "psUBScRIBe": actionPsubscribe, + "psUBScRIbE": actionPsubscribe, + "psUBScRIbe": actionPsubscribe, + "psUBScRiBE": actionPsubscribe, + "psUBScRiBe": actionPsubscribe, + "psUBScRibE": actionPsubscribe, + "psUBScRibe": actionPsubscribe, + "psUBScrIBE": actionPsubscribe, + "psUBScrIBe": actionPsubscribe, + "psUBScrIbE": actionPsubscribe, + "psUBScrIbe": actionPsubscribe, + "psUBScriBE": actionPsubscribe, + "psUBScriBe": actionPsubscribe, + "psUBScribE": actionPsubscribe, + "psUBScribe": actionPsubscribe, + "psUBsCRIBE": actionPsubscribe, + "psUBsCRIBe": actionPsubscribe, + "psUBsCRIbE": actionPsubscribe, + "psUBsCRIbe": actionPsubscribe, + "psUBsCRiBE": actionPsubscribe, + "psUBsCRiBe": actionPsubscribe, + "psUBsCRibE": actionPsubscribe, + "psUBsCRibe": actionPsubscribe, + "psUBsCrIBE": actionPsubscribe, + "psUBsCrIBe": actionPsubscribe, + "psUBsCrIbE": actionPsubscribe, + "psUBsCrIbe": actionPsubscribe, + "psUBsCriBE": actionPsubscribe, + "psUBsCriBe": actionPsubscribe, + "psUBsCribE": actionPsubscribe, + "psUBsCribe": actionPsubscribe, + "psUBscRIBE": actionPsubscribe, + "psUBscRIBe": actionPsubscribe, + "psUBscRIbE": actionPsubscribe, + "psUBscRIbe": actionPsubscribe, + "psUBscRiBE": actionPsubscribe, + "psUBscRiBe": actionPsubscribe, + "psUBscRibE": actionPsubscribe, + "psUBscRibe": actionPsubscribe, + "psUBscrIBE": actionPsubscribe, + "psUBscrIBe": actionPsubscribe, + "psUBscrIbE": actionPsubscribe, + "psUBscrIbe": actionPsubscribe, + "psUBscriBE": actionPsubscribe, + "psUBscriBe": actionPsubscribe, + "psUBscribE": actionPsubscribe, + "psUBscribe": actionPsubscribe, + "psUbSCRIBE": actionPsubscribe, + "psUbSCRIBe": actionPsubscribe, + "psUbSCRIbE": actionPsubscribe, + "psUbSCRIbe": actionPsubscribe, + "psUbSCRiBE": actionPsubscribe, + "psUbSCRiBe": actionPsubscribe, + "psUbSCRibE": actionPsubscribe, + "psUbSCRibe": actionPsubscribe, + "psUbSCrIBE": actionPsubscribe, + "psUbSCrIBe": actionPsubscribe, + "psUbSCrIbE": actionPsubscribe, + "psUbSCrIbe": actionPsubscribe, + "psUbSCriBE": actionPsubscribe, + "psUbSCriBe": actionPsubscribe, + "psUbSCribE": actionPsubscribe, + "psUbSCribe": actionPsubscribe, + "psUbScRIBE": actionPsubscribe, + "psUbScRIBe": actionPsubscribe, + "psUbScRIbE": actionPsubscribe, + "psUbScRIbe": actionPsubscribe, + "psUbScRiBE": actionPsubscribe, + "psUbScRiBe": actionPsubscribe, + "psUbScRibE": actionPsubscribe, + "psUbScRibe": actionPsubscribe, + "psUbScrIBE": actionPsubscribe, + "psUbScrIBe": actionPsubscribe, + "psUbScrIbE": actionPsubscribe, + "psUbScrIbe": actionPsubscribe, + "psUbScriBE": actionPsubscribe, + "psUbScriBe": actionPsubscribe, + "psUbScribE": actionPsubscribe, + "psUbScribe": actionPsubscribe, + "psUbsCRIBE": actionPsubscribe, + "psUbsCRIBe": actionPsubscribe, + "psUbsCRIbE": actionPsubscribe, + "psUbsCRIbe": actionPsubscribe, + "psUbsCRiBE": actionPsubscribe, + "psUbsCRiBe": actionPsubscribe, + "psUbsCRibE": actionPsubscribe, + "psUbsCRibe": actionPsubscribe, + "psUbsCrIBE": actionPsubscribe, + "psUbsCrIBe": actionPsubscribe, + "psUbsCrIbE": actionPsubscribe, + "psUbsCrIbe": actionPsubscribe, + "psUbsCriBE": actionPsubscribe, + "psUbsCriBe": actionPsubscribe, + "psUbsCribE": actionPsubscribe, + "psUbsCribe": actionPsubscribe, + "psUbscRIBE": actionPsubscribe, + "psUbscRIBe": actionPsubscribe, + "psUbscRIbE": actionPsubscribe, + "psUbscRIbe": actionPsubscribe, + "psUbscRiBE": actionPsubscribe, + "psUbscRiBe": actionPsubscribe, + "psUbscRibE": actionPsubscribe, + "psUbscRibe": actionPsubscribe, + "psUbscrIBE": actionPsubscribe, + "psUbscrIBe": actionPsubscribe, + "psUbscrIbE": actionPsubscribe, + "psUbscrIbe": actionPsubscribe, + "psUbscriBE": actionPsubscribe, + "psUbscriBe": actionPsubscribe, + "psUbscribE": actionPsubscribe, + "psUbscribe": actionPsubscribe, + "psuBSCRIBE": actionPsubscribe, + "psuBSCRIBe": actionPsubscribe, + "psuBSCRIbE": actionPsubscribe, + "psuBSCRIbe": actionPsubscribe, + "psuBSCRiBE": actionPsubscribe, + "psuBSCRiBe": actionPsubscribe, + "psuBSCRibE": actionPsubscribe, + "psuBSCRibe": actionPsubscribe, + "psuBSCrIBE": actionPsubscribe, + "psuBSCrIBe": actionPsubscribe, + "psuBSCrIbE": actionPsubscribe, + "psuBSCrIbe": actionPsubscribe, + "psuBSCriBE": actionPsubscribe, + "psuBSCriBe": actionPsubscribe, + "psuBSCribE": actionPsubscribe, + "psuBSCribe": actionPsubscribe, + "psuBScRIBE": actionPsubscribe, + "psuBScRIBe": actionPsubscribe, + "psuBScRIbE": actionPsubscribe, + "psuBScRIbe": actionPsubscribe, + "psuBScRiBE": actionPsubscribe, + "psuBScRiBe": actionPsubscribe, + "psuBScRibE": actionPsubscribe, + "psuBScRibe": actionPsubscribe, + "psuBScrIBE": actionPsubscribe, + "psuBScrIBe": actionPsubscribe, + "psuBScrIbE": actionPsubscribe, + "psuBScrIbe": actionPsubscribe, + "psuBScriBE": actionPsubscribe, + "psuBScriBe": actionPsubscribe, + "psuBScribE": actionPsubscribe, + "psuBScribe": actionPsubscribe, + "psuBsCRIBE": actionPsubscribe, + "psuBsCRIBe": actionPsubscribe, + "psuBsCRIbE": actionPsubscribe, + "psuBsCRIbe": actionPsubscribe, + "psuBsCRiBE": actionPsubscribe, + "psuBsCRiBe": actionPsubscribe, + "psuBsCRibE": actionPsubscribe, + "psuBsCRibe": actionPsubscribe, + "psuBsCrIBE": actionPsubscribe, + "psuBsCrIBe": actionPsubscribe, + "psuBsCrIbE": actionPsubscribe, + "psuBsCrIbe": actionPsubscribe, + "psuBsCriBE": actionPsubscribe, + "psuBsCriBe": actionPsubscribe, + "psuBsCribE": actionPsubscribe, + "psuBsCribe": actionPsubscribe, + "psuBscRIBE": actionPsubscribe, + "psuBscRIBe": actionPsubscribe, + "psuBscRIbE": actionPsubscribe, + "psuBscRIbe": actionPsubscribe, + "psuBscRiBE": actionPsubscribe, + "psuBscRiBe": actionPsubscribe, + "psuBscRibE": actionPsubscribe, + "psuBscRibe": actionPsubscribe, + "psuBscrIBE": actionPsubscribe, + "psuBscrIBe": actionPsubscribe, + "psuBscrIbE": actionPsubscribe, + "psuBscrIbe": actionPsubscribe, + "psuBscriBE": actionPsubscribe, + "psuBscriBe": actionPsubscribe, + "psuBscribE": actionPsubscribe, + "psuBscribe": actionPsubscribe, + "psubSCRIBE": actionPsubscribe, + "psubSCRIBe": actionPsubscribe, + "psubSCRIbE": actionPsubscribe, + "psubSCRIbe": actionPsubscribe, + "psubSCRiBE": actionPsubscribe, + "psubSCRiBe": actionPsubscribe, + "psubSCRibE": actionPsubscribe, + "psubSCRibe": actionPsubscribe, + "psubSCrIBE": actionPsubscribe, + "psubSCrIBe": actionPsubscribe, + "psubSCrIbE": actionPsubscribe, + "psubSCrIbe": actionPsubscribe, + "psubSCriBE": actionPsubscribe, + "psubSCriBe": actionPsubscribe, + "psubSCribE": actionPsubscribe, + "psubSCribe": actionPsubscribe, + "psubScRIBE": actionPsubscribe, + "psubScRIBe": actionPsubscribe, + "psubScRIbE": actionPsubscribe, + "psubScRIbe": actionPsubscribe, + "psubScRiBE": actionPsubscribe, + "psubScRiBe": actionPsubscribe, + "psubScRibE": actionPsubscribe, + "psubScRibe": actionPsubscribe, + "psubScrIBE": actionPsubscribe, + "psubScrIBe": actionPsubscribe, + "psubScrIbE": actionPsubscribe, + "psubScrIbe": actionPsubscribe, + "psubScriBE": actionPsubscribe, + "psubScriBe": actionPsubscribe, + "psubScribE": actionPsubscribe, + "psubScribe": actionPsubscribe, + "psubsCRIBE": actionPsubscribe, + "psubsCRIBe": actionPsubscribe, + "psubsCRIbE": actionPsubscribe, + "psubsCRIbe": actionPsubscribe, + "psubsCRiBE": actionPsubscribe, + "psubsCRiBe": actionPsubscribe, + "psubsCRibE": actionPsubscribe, + "psubsCRibe": actionPsubscribe, + "psubsCrIBE": actionPsubscribe, + "psubsCrIBe": actionPsubscribe, + "psubsCrIbE": actionPsubscribe, + "psubsCrIbe": actionPsubscribe, + "psubsCriBE": actionPsubscribe, + "psubsCriBe": actionPsubscribe, + "psubsCribE": actionPsubscribe, + "psubsCribe": actionPsubscribe, + "psubscRIBE": actionPsubscribe, + "psubscRIBe": actionPsubscribe, + "psubscRIbE": actionPsubscribe, + "psubscRIbe": actionPsubscribe, + "psubscRiBE": actionPsubscribe, + "psubscRiBe": actionPsubscribe, + "psubscRibE": actionPsubscribe, + "psubscRibe": actionPsubscribe, + "psubscrIBE": actionPsubscribe, + "psubscrIBe": actionPsubscribe, + "psubscrIbE": actionPsubscribe, + "psubscrIbe": actionPsubscribe, + "psubscriBE": actionPsubscribe, + "psubscriBe": actionPsubscribe, + "psubscribE": actionPsubscribe, + "psubscribe": actionPsubscribe, + "SUBSCRIBE": actionSubscribe, + "SUBSCRIBe": actionSubscribe, + "SUBSCRIbE": actionSubscribe, + "SUBSCRIbe": actionSubscribe, + "SUBSCRiBE": actionSubscribe, + "SUBSCRiBe": actionSubscribe, + "SUBSCRibE": actionSubscribe, + "SUBSCRibe": actionSubscribe, + "SUBSCrIBE": actionSubscribe, + "SUBSCrIBe": actionSubscribe, + "SUBSCrIbE": actionSubscribe, + "SUBSCrIbe": actionSubscribe, + "SUBSCriBE": actionSubscribe, + "SUBSCriBe": actionSubscribe, + "SUBSCribE": actionSubscribe, + "SUBSCribe": actionSubscribe, + "SUBScRIBE": actionSubscribe, + "SUBScRIBe": actionSubscribe, + "SUBScRIbE": actionSubscribe, + "SUBScRIbe": actionSubscribe, + "SUBScRiBE": actionSubscribe, + "SUBScRiBe": actionSubscribe, + "SUBScRibE": actionSubscribe, + "SUBScRibe": actionSubscribe, + "SUBScrIBE": actionSubscribe, + "SUBScrIBe": actionSubscribe, + "SUBScrIbE": actionSubscribe, + "SUBScrIbe": actionSubscribe, + "SUBScriBE": actionSubscribe, + "SUBScriBe": actionSubscribe, + "SUBScribE": actionSubscribe, + "SUBScribe": actionSubscribe, + "SUBsCRIBE": actionSubscribe, + "SUBsCRIBe": actionSubscribe, + "SUBsCRIbE": actionSubscribe, + "SUBsCRIbe": actionSubscribe, + "SUBsCRiBE": actionSubscribe, + "SUBsCRiBe": actionSubscribe, + "SUBsCRibE": actionSubscribe, + "SUBsCRibe": actionSubscribe, + "SUBsCrIBE": actionSubscribe, + "SUBsCrIBe": actionSubscribe, + "SUBsCrIbE": actionSubscribe, + "SUBsCrIbe": actionSubscribe, + "SUBsCriBE": actionSubscribe, + "SUBsCriBe": actionSubscribe, + "SUBsCribE": actionSubscribe, + "SUBsCribe": actionSubscribe, + "SUBscRIBE": actionSubscribe, + "SUBscRIBe": actionSubscribe, + "SUBscRIbE": actionSubscribe, + "SUBscRIbe": actionSubscribe, + "SUBscRiBE": actionSubscribe, + "SUBscRiBe": actionSubscribe, + "SUBscRibE": actionSubscribe, + "SUBscRibe": actionSubscribe, + "SUBscrIBE": actionSubscribe, + "SUBscrIBe": actionSubscribe, + "SUBscrIbE": actionSubscribe, + "SUBscrIbe": actionSubscribe, + "SUBscriBE": actionSubscribe, + "SUBscriBe": actionSubscribe, + "SUBscribE": actionSubscribe, + "SUBscribe": actionSubscribe, + "SUbSCRIBE": actionSubscribe, + "SUbSCRIBe": actionSubscribe, + "SUbSCRIbE": actionSubscribe, + "SUbSCRIbe": actionSubscribe, + "SUbSCRiBE": actionSubscribe, + "SUbSCRiBe": actionSubscribe, + "SUbSCRibE": actionSubscribe, + "SUbSCRibe": actionSubscribe, + "SUbSCrIBE": actionSubscribe, + "SUbSCrIBe": actionSubscribe, + "SUbSCrIbE": actionSubscribe, + "SUbSCrIbe": actionSubscribe, + "SUbSCriBE": actionSubscribe, + "SUbSCriBe": actionSubscribe, + "SUbSCribE": actionSubscribe, + "SUbSCribe": actionSubscribe, + "SUbScRIBE": actionSubscribe, + "SUbScRIBe": actionSubscribe, + "SUbScRIbE": actionSubscribe, + "SUbScRIbe": actionSubscribe, + "SUbScRiBE": actionSubscribe, + "SUbScRiBe": actionSubscribe, + "SUbScRibE": actionSubscribe, + "SUbScRibe": actionSubscribe, + "SUbScrIBE": actionSubscribe, + "SUbScrIBe": actionSubscribe, + "SUbScrIbE": actionSubscribe, + "SUbScrIbe": actionSubscribe, + "SUbScriBE": actionSubscribe, + "SUbScriBe": actionSubscribe, + "SUbScribE": actionSubscribe, + "SUbScribe": actionSubscribe, + "SUbsCRIBE": actionSubscribe, + "SUbsCRIBe": actionSubscribe, + "SUbsCRIbE": actionSubscribe, + "SUbsCRIbe": actionSubscribe, + "SUbsCRiBE": actionSubscribe, + "SUbsCRiBe": actionSubscribe, + "SUbsCRibE": actionSubscribe, + "SUbsCRibe": actionSubscribe, + "SUbsCrIBE": actionSubscribe, + "SUbsCrIBe": actionSubscribe, + "SUbsCrIbE": actionSubscribe, + "SUbsCrIbe": actionSubscribe, + "SUbsCriBE": actionSubscribe, + "SUbsCriBe": actionSubscribe, + "SUbsCribE": actionSubscribe, + "SUbsCribe": actionSubscribe, + "SUbscRIBE": actionSubscribe, + "SUbscRIBe": actionSubscribe, + "SUbscRIbE": actionSubscribe, + "SUbscRIbe": actionSubscribe, + "SUbscRiBE": actionSubscribe, + "SUbscRiBe": actionSubscribe, + "SUbscRibE": actionSubscribe, + "SUbscRibe": actionSubscribe, + "SUbscrIBE": actionSubscribe, + "SUbscrIBe": actionSubscribe, + "SUbscrIbE": actionSubscribe, + "SUbscrIbe": actionSubscribe, + "SUbscriBE": actionSubscribe, + "SUbscriBe": actionSubscribe, + "SUbscribE": actionSubscribe, + "SUbscribe": actionSubscribe, + "SuBSCRIBE": actionSubscribe, + "SuBSCRIBe": actionSubscribe, + "SuBSCRIbE": actionSubscribe, + "SuBSCRIbe": actionSubscribe, + "SuBSCRiBE": actionSubscribe, + "SuBSCRiBe": actionSubscribe, + "SuBSCRibE": actionSubscribe, + "SuBSCRibe": actionSubscribe, + "SuBSCrIBE": actionSubscribe, + "SuBSCrIBe": actionSubscribe, + "SuBSCrIbE": actionSubscribe, + "SuBSCrIbe": actionSubscribe, + "SuBSCriBE": actionSubscribe, + "SuBSCriBe": actionSubscribe, + "SuBSCribE": actionSubscribe, + "SuBSCribe": actionSubscribe, + "SuBScRIBE": actionSubscribe, + "SuBScRIBe": actionSubscribe, + "SuBScRIbE": actionSubscribe, + "SuBScRIbe": actionSubscribe, + "SuBScRiBE": actionSubscribe, + "SuBScRiBe": actionSubscribe, + "SuBScRibE": actionSubscribe, + "SuBScRibe": actionSubscribe, + "SuBScrIBE": actionSubscribe, + "SuBScrIBe": actionSubscribe, + "SuBScrIbE": actionSubscribe, + "SuBScrIbe": actionSubscribe, + "SuBScriBE": actionSubscribe, + "SuBScriBe": actionSubscribe, + "SuBScribE": actionSubscribe, + "SuBScribe": actionSubscribe, + "SuBsCRIBE": actionSubscribe, + "SuBsCRIBe": actionSubscribe, + "SuBsCRIbE": actionSubscribe, + "SuBsCRIbe": actionSubscribe, + "SuBsCRiBE": actionSubscribe, + "SuBsCRiBe": actionSubscribe, + "SuBsCRibE": actionSubscribe, + "SuBsCRibe": actionSubscribe, + "SuBsCrIBE": actionSubscribe, + "SuBsCrIBe": actionSubscribe, + "SuBsCrIbE": actionSubscribe, + "SuBsCrIbe": actionSubscribe, + "SuBsCriBE": actionSubscribe, + "SuBsCriBe": actionSubscribe, + "SuBsCribE": actionSubscribe, + "SuBsCribe": actionSubscribe, + "SuBscRIBE": actionSubscribe, + "SuBscRIBe": actionSubscribe, + "SuBscRIbE": actionSubscribe, + "SuBscRIbe": actionSubscribe, + "SuBscRiBE": actionSubscribe, + "SuBscRiBe": actionSubscribe, + "SuBscRibE": actionSubscribe, + "SuBscRibe": actionSubscribe, + "SuBscrIBE": actionSubscribe, + "SuBscrIBe": actionSubscribe, + "SuBscrIbE": actionSubscribe, + "SuBscrIbe": actionSubscribe, + "SuBscriBE": actionSubscribe, + "SuBscriBe": actionSubscribe, + "SuBscribE": actionSubscribe, + "SuBscribe": actionSubscribe, + "SubSCRIBE": actionSubscribe, + "SubSCRIBe": actionSubscribe, + "SubSCRIbE": actionSubscribe, + "SubSCRIbe": actionSubscribe, + "SubSCRiBE": actionSubscribe, + "SubSCRiBe": actionSubscribe, + "SubSCRibE": actionSubscribe, + "SubSCRibe": actionSubscribe, + "SubSCrIBE": actionSubscribe, + "SubSCrIBe": actionSubscribe, + "SubSCrIbE": actionSubscribe, + "SubSCrIbe": actionSubscribe, + "SubSCriBE": actionSubscribe, + "SubSCriBe": actionSubscribe, + "SubSCribE": actionSubscribe, + "SubSCribe": actionSubscribe, + "SubScRIBE": actionSubscribe, + "SubScRIBe": actionSubscribe, + "SubScRIbE": actionSubscribe, + "SubScRIbe": actionSubscribe, + "SubScRiBE": actionSubscribe, + "SubScRiBe": actionSubscribe, + "SubScRibE": actionSubscribe, + "SubScRibe": actionSubscribe, + "SubScrIBE": actionSubscribe, + "SubScrIBe": actionSubscribe, + "SubScrIbE": actionSubscribe, + "SubScrIbe": actionSubscribe, + "SubScriBE": actionSubscribe, + "SubScriBe": actionSubscribe, + "SubScribE": actionSubscribe, + "SubScribe": actionSubscribe, + "SubsCRIBE": actionSubscribe, + "SubsCRIBe": actionSubscribe, + "SubsCRIbE": actionSubscribe, + "SubsCRIbe": actionSubscribe, + "SubsCRiBE": actionSubscribe, + "SubsCRiBe": actionSubscribe, + "SubsCRibE": actionSubscribe, + "SubsCRibe": actionSubscribe, + "SubsCrIBE": actionSubscribe, + "SubsCrIBe": actionSubscribe, + "SubsCrIbE": actionSubscribe, + "SubsCrIbe": actionSubscribe, + "SubsCriBE": actionSubscribe, + "SubsCriBe": actionSubscribe, + "SubsCribE": actionSubscribe, + "SubsCribe": actionSubscribe, + "SubscRIBE": actionSubscribe, + "SubscRIBe": actionSubscribe, + "SubscRIbE": actionSubscribe, + "SubscRIbe": actionSubscribe, + "SubscRiBE": actionSubscribe, + "SubscRiBe": actionSubscribe, + "SubscRibE": actionSubscribe, + "SubscRibe": actionSubscribe, + "SubscrIBE": actionSubscribe, + "SubscrIBe": actionSubscribe, + "SubscrIbE": actionSubscribe, + "SubscrIbe": actionSubscribe, + "SubscriBE": actionSubscribe, + "SubscriBe": actionSubscribe, + "SubscribE": actionSubscribe, + "Subscribe": actionSubscribe, + "sUBSCRIBE": actionSubscribe, + "sUBSCRIBe": actionSubscribe, + "sUBSCRIbE": actionSubscribe, + "sUBSCRIbe": actionSubscribe, + "sUBSCRiBE": actionSubscribe, + "sUBSCRiBe": actionSubscribe, + "sUBSCRibE": actionSubscribe, + "sUBSCRibe": actionSubscribe, + "sUBSCrIBE": actionSubscribe, + "sUBSCrIBe": actionSubscribe, + "sUBSCrIbE": actionSubscribe, + "sUBSCrIbe": actionSubscribe, + "sUBSCriBE": actionSubscribe, + "sUBSCriBe": actionSubscribe, + "sUBSCribE": actionSubscribe, + "sUBSCribe": actionSubscribe, + "sUBScRIBE": actionSubscribe, + "sUBScRIBe": actionSubscribe, + "sUBScRIbE": actionSubscribe, + "sUBScRIbe": actionSubscribe, + "sUBScRiBE": actionSubscribe, + "sUBScRiBe": actionSubscribe, + "sUBScRibE": actionSubscribe, + "sUBScRibe": actionSubscribe, + "sUBScrIBE": actionSubscribe, + "sUBScrIBe": actionSubscribe, + "sUBScrIbE": actionSubscribe, + "sUBScrIbe": actionSubscribe, + "sUBScriBE": actionSubscribe, + "sUBScriBe": actionSubscribe, + "sUBScribE": actionSubscribe, + "sUBScribe": actionSubscribe, + "sUBsCRIBE": actionSubscribe, + "sUBsCRIBe": actionSubscribe, + "sUBsCRIbE": actionSubscribe, + "sUBsCRIbe": actionSubscribe, + "sUBsCRiBE": actionSubscribe, + "sUBsCRiBe": actionSubscribe, + "sUBsCRibE": actionSubscribe, + "sUBsCRibe": actionSubscribe, + "sUBsCrIBE": actionSubscribe, + "sUBsCrIBe": actionSubscribe, + "sUBsCrIbE": actionSubscribe, + "sUBsCrIbe": actionSubscribe, + "sUBsCriBE": actionSubscribe, + "sUBsCriBe": actionSubscribe, + "sUBsCribE": actionSubscribe, + "sUBsCribe": actionSubscribe, + "sUBscRIBE": actionSubscribe, + "sUBscRIBe": actionSubscribe, + "sUBscRIbE": actionSubscribe, + "sUBscRIbe": actionSubscribe, + "sUBscRiBE": actionSubscribe, + "sUBscRiBe": actionSubscribe, + "sUBscRibE": actionSubscribe, + "sUBscRibe": actionSubscribe, + "sUBscrIBE": actionSubscribe, + "sUBscrIBe": actionSubscribe, + "sUBscrIbE": actionSubscribe, + "sUBscrIbe": actionSubscribe, + "sUBscriBE": actionSubscribe, + "sUBscriBe": actionSubscribe, + "sUBscribE": actionSubscribe, + "sUBscribe": actionSubscribe, + "sUbSCRIBE": actionSubscribe, + "sUbSCRIBe": actionSubscribe, + "sUbSCRIbE": actionSubscribe, + "sUbSCRIbe": actionSubscribe, + "sUbSCRiBE": actionSubscribe, + "sUbSCRiBe": actionSubscribe, + "sUbSCRibE": actionSubscribe, + "sUbSCRibe": actionSubscribe, + "sUbSCrIBE": actionSubscribe, + "sUbSCrIBe": actionSubscribe, + "sUbSCrIbE": actionSubscribe, + "sUbSCrIbe": actionSubscribe, + "sUbSCriBE": actionSubscribe, + "sUbSCriBe": actionSubscribe, + "sUbSCribE": actionSubscribe, + "sUbSCribe": actionSubscribe, + "sUbScRIBE": actionSubscribe, + "sUbScRIBe": actionSubscribe, + "sUbScRIbE": actionSubscribe, + "sUbScRIbe": actionSubscribe, + "sUbScRiBE": actionSubscribe, + "sUbScRiBe": actionSubscribe, + "sUbScRibE": actionSubscribe, + "sUbScRibe": actionSubscribe, + "sUbScrIBE": actionSubscribe, + "sUbScrIBe": actionSubscribe, + "sUbScrIbE": actionSubscribe, + "sUbScrIbe": actionSubscribe, + "sUbScriBE": actionSubscribe, + "sUbScriBe": actionSubscribe, + "sUbScribE": actionSubscribe, + "sUbScribe": actionSubscribe, + "sUbsCRIBE": actionSubscribe, + "sUbsCRIBe": actionSubscribe, + "sUbsCRIbE": actionSubscribe, + "sUbsCRIbe": actionSubscribe, + "sUbsCRiBE": actionSubscribe, + "sUbsCRiBe": actionSubscribe, + "sUbsCRibE": actionSubscribe, + "sUbsCRibe": actionSubscribe, + "sUbsCrIBE": actionSubscribe, + "sUbsCrIBe": actionSubscribe, + "sUbsCrIbE": actionSubscribe, + "sUbsCrIbe": actionSubscribe, + "sUbsCriBE": actionSubscribe, + "sUbsCriBe": actionSubscribe, + "sUbsCribE": actionSubscribe, + "sUbsCribe": actionSubscribe, + "sUbscRIBE": actionSubscribe, + "sUbscRIBe": actionSubscribe, + "sUbscRIbE": actionSubscribe, + "sUbscRIbe": actionSubscribe, + "sUbscRiBE": actionSubscribe, + "sUbscRiBe": actionSubscribe, + "sUbscRibE": actionSubscribe, + "sUbscRibe": actionSubscribe, + "sUbscrIBE": actionSubscribe, + "sUbscrIBe": actionSubscribe, + "sUbscrIbE": actionSubscribe, + "sUbscrIbe": actionSubscribe, + "sUbscriBE": actionSubscribe, + "sUbscriBe": actionSubscribe, + "sUbscribE": actionSubscribe, + "sUbscribe": actionSubscribe, + "suBSCRIBE": actionSubscribe, + "suBSCRIBe": actionSubscribe, + "suBSCRIbE": actionSubscribe, + "suBSCRIbe": actionSubscribe, + "suBSCRiBE": actionSubscribe, + "suBSCRiBe": actionSubscribe, + "suBSCRibE": actionSubscribe, + "suBSCRibe": actionSubscribe, + "suBSCrIBE": actionSubscribe, + "suBSCrIBe": actionSubscribe, + "suBSCrIbE": actionSubscribe, + "suBSCrIbe": actionSubscribe, + "suBSCriBE": actionSubscribe, + "suBSCriBe": actionSubscribe, + "suBSCribE": actionSubscribe, + "suBSCribe": actionSubscribe, + "suBScRIBE": actionSubscribe, + "suBScRIBe": actionSubscribe, + "suBScRIbE": actionSubscribe, + "suBScRIbe": actionSubscribe, + "suBScRiBE": actionSubscribe, + "suBScRiBe": actionSubscribe, + "suBScRibE": actionSubscribe, + "suBScRibe": actionSubscribe, + "suBScrIBE": actionSubscribe, + "suBScrIBe": actionSubscribe, + "suBScrIbE": actionSubscribe, + "suBScrIbe": actionSubscribe, + "suBScriBE": actionSubscribe, + "suBScriBe": actionSubscribe, + "suBScribE": actionSubscribe, + "suBScribe": actionSubscribe, + "suBsCRIBE": actionSubscribe, + "suBsCRIBe": actionSubscribe, + "suBsCRIbE": actionSubscribe, + "suBsCRIbe": actionSubscribe, + "suBsCRiBE": actionSubscribe, + "suBsCRiBe": actionSubscribe, + "suBsCRibE": actionSubscribe, + "suBsCRibe": actionSubscribe, + "suBsCrIBE": actionSubscribe, + "suBsCrIBe": actionSubscribe, + "suBsCrIbE": actionSubscribe, + "suBsCrIbe": actionSubscribe, + "suBsCriBE": actionSubscribe, + "suBsCriBe": actionSubscribe, + "suBsCribE": actionSubscribe, + "suBsCribe": actionSubscribe, + "suBscRIBE": actionSubscribe, + "suBscRIBe": actionSubscribe, + "suBscRIbE": actionSubscribe, + "suBscRIbe": actionSubscribe, + "suBscRiBE": actionSubscribe, + "suBscRiBe": actionSubscribe, + "suBscRibE": actionSubscribe, + "suBscRibe": actionSubscribe, + "suBscrIBE": actionSubscribe, + "suBscrIBe": actionSubscribe, + "suBscrIbE": actionSubscribe, + "suBscrIbe": actionSubscribe, + "suBscriBE": actionSubscribe, + "suBscriBe": actionSubscribe, + "suBscribE": actionSubscribe, + "suBscribe": actionSubscribe, + "subSCRIBE": actionSubscribe, + "subSCRIBe": actionSubscribe, + "subSCRIbE": actionSubscribe, + "subSCRIbe": actionSubscribe, + "subSCRiBE": actionSubscribe, + "subSCRiBe": actionSubscribe, + "subSCRibE": actionSubscribe, + "subSCRibe": actionSubscribe, + "subSCrIBE": actionSubscribe, + "subSCrIBe": actionSubscribe, + "subSCrIbE": actionSubscribe, + "subSCrIbe": actionSubscribe, + "subSCriBE": actionSubscribe, + "subSCriBe": actionSubscribe, + "subSCribE": actionSubscribe, + "subSCribe": actionSubscribe, + "subScRIBE": actionSubscribe, + "subScRIBe": actionSubscribe, + "subScRIbE": actionSubscribe, + "subScRIbe": actionSubscribe, + "subScRiBE": actionSubscribe, + "subScRiBe": actionSubscribe, + "subScRibE": actionSubscribe, + "subScRibe": actionSubscribe, + "subScrIBE": actionSubscribe, + "subScrIBe": actionSubscribe, + "subScrIbE": actionSubscribe, + "subScrIbe": actionSubscribe, + "subScriBE": actionSubscribe, + "subScriBe": actionSubscribe, + "subScribE": actionSubscribe, + "subScribe": actionSubscribe, + "subsCRIBE": actionSubscribe, + "subsCRIBe": actionSubscribe, + "subsCRIbE": actionSubscribe, + "subsCRIbe": actionSubscribe, + "subsCRiBE": actionSubscribe, + "subsCRiBe": actionSubscribe, + "subsCRibE": actionSubscribe, + "subsCRibe": actionSubscribe, + "subsCrIBE": actionSubscribe, + "subsCrIBe": actionSubscribe, + "subsCrIbE": actionSubscribe, + "subsCrIbe": actionSubscribe, + "subsCriBE": actionSubscribe, + "subsCriBe": actionSubscribe, + "subsCribE": actionSubscribe, + "subsCribe": actionSubscribe, + "subscRIBE": actionSubscribe, + "subscRIBe": actionSubscribe, + "subscRIbE": actionSubscribe, + "subscRIbe": actionSubscribe, + "subscRiBE": actionSubscribe, + "subscRiBe": actionSubscribe, + "subscRibE": actionSubscribe, + "subscRibe": actionSubscribe, + "subscrIBE": actionSubscribe, + "subscrIBe": actionSubscribe, + "subscrIbE": actionSubscribe, + "subscrIbe": actionSubscribe, + "subscriBE": actionSubscribe, + "subscriBe": actionSubscribe, + "subscribE": actionSubscribe, + "subscribe": actionSubscribe, + "MONITOR": actionMonitor, + "MONITOr": actionMonitor, + "MONIToR": actionMonitor, + "MONITor": actionMonitor, + "MONItOR": actionMonitor, + "MONItOr": actionMonitor, + "MONItoR": actionMonitor, + "MONItor": actionMonitor, + "MONiTOR": actionMonitor, + "MONiTOr": actionMonitor, + "MONiToR": actionMonitor, + "MONiTor": actionMonitor, + "MONitOR": actionMonitor, + "MONitOr": actionMonitor, + "MONitoR": actionMonitor, + "MONitor": actionMonitor, + "MOnITOR": actionMonitor, + "MOnITOr": actionMonitor, + "MOnIToR": actionMonitor, + "MOnITor": actionMonitor, + "MOnItOR": actionMonitor, + "MOnItOr": actionMonitor, + "MOnItoR": actionMonitor, + "MOnItor": actionMonitor, + "MOniTOR": actionMonitor, + "MOniTOr": actionMonitor, + "MOniToR": actionMonitor, + "MOniTor": actionMonitor, + "MOnitOR": actionMonitor, + "MOnitOr": actionMonitor, + "MOnitoR": actionMonitor, + "MOnitor": actionMonitor, + "MoNITOR": actionMonitor, + "MoNITOr": actionMonitor, + "MoNIToR": actionMonitor, + "MoNITor": actionMonitor, + "MoNItOR": actionMonitor, + "MoNItOr": actionMonitor, + "MoNItoR": actionMonitor, + "MoNItor": actionMonitor, + "MoNiTOR": actionMonitor, + "MoNiTOr": actionMonitor, + "MoNiToR": actionMonitor, + "MoNiTor": actionMonitor, + "MoNitOR": actionMonitor, + "MoNitOr": actionMonitor, + "MoNitoR": actionMonitor, + "MoNitor": actionMonitor, + "MonITOR": actionMonitor, + "MonITOr": actionMonitor, + "MonIToR": actionMonitor, + "MonITor": actionMonitor, + "MonItOR": actionMonitor, + "MonItOr": actionMonitor, + "MonItoR": actionMonitor, + "MonItor": actionMonitor, + "MoniTOR": actionMonitor, + "MoniTOr": actionMonitor, + "MoniToR": actionMonitor, + "MoniTor": actionMonitor, + "MonitOR": actionMonitor, + "MonitOr": actionMonitor, + "MonitoR": actionMonitor, + "Monitor": actionMonitor, + "mONITOR": actionMonitor, + "mONITOr": actionMonitor, + "mONIToR": actionMonitor, + "mONITor": actionMonitor, + "mONItOR": actionMonitor, + "mONItOr": actionMonitor, + "mONItoR": actionMonitor, + "mONItor": actionMonitor, + "mONiTOR": actionMonitor, + "mONiTOr": actionMonitor, + "mONiToR": actionMonitor, + "mONiTor": actionMonitor, + "mONitOR": actionMonitor, + "mONitOr": actionMonitor, + "mONitoR": actionMonitor, + "mONitor": actionMonitor, + "mOnITOR": actionMonitor, + "mOnITOr": actionMonitor, + "mOnIToR": actionMonitor, + "mOnITor": actionMonitor, + "mOnItOR": actionMonitor, + "mOnItOr": actionMonitor, + "mOnItoR": actionMonitor, + "mOnItor": actionMonitor, + "mOniTOR": actionMonitor, + "mOniTOr": actionMonitor, + "mOniToR": actionMonitor, + "mOniTor": actionMonitor, + "mOnitOR": actionMonitor, + "mOnitOr": actionMonitor, + "mOnitoR": actionMonitor, + "mOnitor": actionMonitor, + "moNITOR": actionMonitor, + "moNITOr": actionMonitor, + "moNIToR": actionMonitor, + "moNITor": actionMonitor, + "moNItOR": actionMonitor, + "moNItOr": actionMonitor, + "moNItoR": actionMonitor, + "moNItor": actionMonitor, + "moNiTOR": actionMonitor, + "moNiTOr": actionMonitor, + "moNiToR": actionMonitor, + "moNiTor": actionMonitor, + "moNitOR": actionMonitor, + "moNitOr": actionMonitor, + "moNitoR": actionMonitor, + "moNitor": actionMonitor, + "monITOR": actionMonitor, + "monITOr": actionMonitor, + "monIToR": actionMonitor, + "monITor": actionMonitor, + "monItOR": actionMonitor, + "monItOr": actionMonitor, + "monItoR": actionMonitor, + "monItor": actionMonitor, + "moniTOR": actionMonitor, + "moniTOr": actionMonitor, + "moniToR": actionMonitor, + "moniTor": actionMonitor, + "monitOR": actionMonitor, + "monitOr": actionMonitor, + "monitoR": actionMonitor, + "monitor": actionMonitor, + "CLIENT": actionClient, + "CLIENt": actionClient, + "CLIEnT": actionClient, + "CLIEnt": actionClient, + "CLIeNT": actionClient, + "CLIeNt": actionClient, + "CLIenT": actionClient, + "CLIent": actionClient, + "CLiENT": actionClient, + "CLiENt": actionClient, + "CLiEnT": actionClient, + "CLiEnt": actionClient, + "CLieNT": actionClient, + "CLieNt": actionClient, + "CLienT": actionClient, + "CLient": actionClient, + "ClIENT": actionClient, + "ClIENt": actionClient, + "ClIEnT": actionClient, + "ClIEnt": actionClient, + "ClIeNT": actionClient, + "ClIeNt": actionClient, + "ClIenT": actionClient, + "ClIent": actionClient, + "CliENT": actionClient, + "CliENt": actionClient, + "CliEnT": actionClient, + "CliEnt": actionClient, + "ClieNT": actionClient, + "ClieNt": actionClient, + "ClienT": actionClient, + "Client": actionClient, + "cLIENT": actionClient, + "cLIENt": actionClient, + "cLIEnT": actionClient, + "cLIEnt": actionClient, + "cLIeNT": actionClient, + "cLIeNt": actionClient, + "cLIenT": actionClient, + "cLIent": actionClient, + "cLiENT": actionClient, + "cLiENt": actionClient, + "cLiEnT": actionClient, + "cLiEnt": actionClient, + "cLieNT": actionClient, + "cLieNt": actionClient, + "cLienT": actionClient, + "cLient": actionClient, + "clIENT": actionClient, + "clIENt": actionClient, + "clIEnT": actionClient, + "clIEnt": actionClient, + "clIeNT": actionClient, + "clIeNt": actionClient, + "clIenT": actionClient, + "clIent": actionClient, + "cliENT": actionClient, + "cliENt": actionClient, + "cliEnT": actionClient, + "cliEnt": actionClient, + "clieNT": actionClient, + "clieNt": actionClient, + "clienT": actionClient, + "client": actionClient, + } + connActions = map[string]*commandAction{ + "CLIENT": actionClient, + "CLIENt": actionClient, + "CLIEnT": actionClient, + "CLIEnt": actionClient, + "CLIeNT": actionClient, + "CLIeNt": actionClient, + "CLIenT": actionClient, + "CLIent": actionClient, + "CLiENT": actionClient, + "CLiENt": actionClient, + "CLiEnT": actionClient, + "CLiEnt": actionClient, + "CLieNT": actionClient, + "CLieNt": actionClient, + "CLienT": actionClient, + "CLient": actionClient, + "ClIENT": actionClient, + "ClIENt": actionClient, + "ClIEnT": actionClient, + "ClIEnt": actionClient, + "ClIeNT": actionClient, + "ClIeNt": actionClient, + "ClIenT": actionClient, + "ClIent": actionClient, + "CliENT": actionClient, + "CliENt": actionClient, + "CliEnT": actionClient, + "CliEnt": actionClient, + "ClieNT": actionClient, + "ClieNt": actionClient, + "ClienT": actionClient, + "Client": actionClient, + "cLIENT": actionClient, + "cLIENt": actionClient, + "cLIEnT": actionClient, + "cLIEnt": actionClient, + "cLIeNT": actionClient, + "cLIeNt": actionClient, + "cLIenT": actionClient, + "cLIent": actionClient, + "cLiENT": actionClient, + "cLiENt": actionClient, + "cLiEnT": actionClient, + "cLiEnt": actionClient, + "cLieNT": actionClient, + "cLieNt": actionClient, + "cLienT": actionClient, + "cLient": actionClient, + "clIENT": actionClient, + "clIENt": actionClient, + "clIEnT": actionClient, + "clIEnt": actionClient, + "clIeNT": actionClient, + "clIeNt": actionClient, + "clIenT": actionClient, + "clIent": actionClient, + "cliENT": actionClient, + "cliENt": actionClient, + "cliEnT": actionClient, + "cliEnt": actionClient, + "clieNT": actionClient, + "clieNt": actionClient, + "clienT": actionClient, + "client": actionClient, + } +) diff --git a/redis/command_action_gen.go b/redis/command_action_gen.go new file mode 100644 index 00000000..71075080 --- /dev/null +++ b/redis/command_action_gen.go @@ -0,0 +1,198 @@ +// command_action_gen generates maps and actions for command processing. +//go:build generate + +package main + +import ( + "bytes" + "fmt" + "go/format" + "log" + "os" + "strings" + "text/template" + "unicode" +) + +// commandInfo represents a command which requires a special action +// on a connection when run. +type commandInfo struct { + Name string + Variable string + Action string + State string + Permutations []string + Next []*commandInfo +} + +// newCommandInfo create a new commandInfo. +func newCommandInfo(name, action string) *commandInfo { + return &commandInfo{ + Name: name, + Action: action, + } +} + +var activeConnCommands = &commandInfo{ + Variable: "activeConnActions", + Next: []*commandInfo{ + newCommandInfo("watch", "*state |= stateWatch"), + newCommandInfo("unwatch", "*state &^= stateWatch"), + newCommandInfo("multi", "*state |= stateMulti"), + newCommandInfo("exec", "*state &^= stateWatch|stateMulti"), + newCommandInfo("discard", "*state &^= stateWatch|stateMulti"), + newCommandInfo("psubscribe", "*state |= stateSubscribe"), + newCommandInfo("subscribe", "*state |= stateSubscribe"), + newCommandInfo("monitor", "*state |= stateMonitor"), + { + Name: "client", + Next: []*commandInfo{ + { + Name: "reply", + Next: []*commandInfo{ + newCommandInfo("off", "*state |= stateClientReplyOff"), + newCommandInfo("on", "*state &^= stateClientReplyOff|stateClientReplySkip"), + newCommandInfo("skip", `if *state&stateClientReplyOff == 0 { + *state |= stateClientReplySkipNext + }`), + }, + }, + }, + }, + }, +} + +var connCommands = &commandInfo{ + Variable: "connActions", + Next: []*commandInfo{ + { + Name: "client", + Variable: "actionClient", + }, + }, +} + +const baseTemplate = ` +{{define "base" -}} +// Code generated by commandinfo_gen. DO NOT EDIT. + +package redis + +var ( + {{- template "var" .ActiveConns}} + {{- template "var" .Conns}} +) +{{end}} + +{{define "var" -}} + {{if .Next}} + {{- range .Next -}} + {{template "var" .}} + {{- end}} + {{- if eq .Name ""}} + {{.Variable}} = map[string]*commandAction{ + {{- range .Next}} + {{- $ci := . -}} + {{range .Permutations}} + "{{.}}": {{$ci.Variable}}, + {{- end}} + {{- end}} + } + {{- else}} + {{.Variable}} = &commandAction{ + Next: map[string]*commandAction{ + {{- range .Next}} + {{- $ci := . -}} + {{range .Permutations}} + "{{.}}": {{$ci.Variable}}, + {{- end}} + {{- end}} + }, + } + {{- end -}} + {{- end -}} + {{- if .Action}} + {{.Variable}} = &commandAction{ + Action: func(state *connectionState) { + {{.Action}} + }, + } + {{- end -}} +{{end}} +` + +// permute returns all combinations of upper and lower case src. +func permute(src, dest []rune) []string { + if len(src) == 0 { + return []string{string(dest)} + } + + upper := unicode.ToUpper(src[0]) + lower := unicode.ToLower(src[0]) + src = src[1:] + if upper == lower { + return permute(src, append(dest, upper)) + } + + return append( + permute(src, append(dest, upper)), + permute(src, append(dest, lower))..., + ) +} + +// processCommands processes commands setting their variable names +// and permutations. +func processCommands(parent string, commands []*commandInfo) { + for _, ci := range commands { + prefix := parent + if ci.Variable == "" { + ci.Variable = parent + strings.Title(ci.Name) + prefix = ci.Variable + } + if ci.Next != nil { + processCommands(prefix, ci.Next) + } + ci.Permutations = permute([]rune(ci.Name), nil) + } +} + +// generate generates the details required for commands and their +// possible named permutations to optimise lookups for performance. +func generate() error { + processCommands("action", []*commandInfo{connCommands}) + processCommands("action", []*commandInfo{activeConnCommands}) + + var buf bytes.Buffer + tmpl, err := template.New("base").Parse(baseTemplate) + if err != nil { + return fmt.Errorf("parse template: %w", err) + } + + data := struct { + ActiveConns *commandInfo + Conns *commandInfo + }{ + ActiveConns: activeConnCommands, + Conns: connCommands, + } + if err = tmpl.Execute(&buf, data); err != nil { + return fmt.Errorf("execute template: %w", err) + } + + formatted, err := format.Source(buf.Bytes()) + if err != nil { + return fmt.Errorf("format code %s: %w", buf.String(), err) + } + + if err = os.WriteFile("command_action.gen.go", formatted, 0666); err != nil { + return fmt.Errorf("write code: %w", err) + } + + return nil +} + +func main() { + if err := generate(); err != nil { + log.Fatal(err) + } +} diff --git a/redis/commandinfo.go b/redis/commandinfo.go deleted file mode 100644 index b6df6a25..00000000 --- a/redis/commandinfo.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2014 Gary Burd -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. - -package redis - -import ( - "strings" -) - -const ( - connectionWatchState = 1 << iota - connectionMultiState - connectionSubscribeState - connectionMonitorState -) - -type commandInfo struct { - // Set or Clear these states on connection. - Set, Clear int -} - -var commandInfos = map[string]commandInfo{ - "WATCH": {Set: connectionWatchState}, - "UNWATCH": {Clear: connectionWatchState}, - "MULTI": {Set: connectionMultiState}, - "EXEC": {Clear: connectionWatchState | connectionMultiState}, - "DISCARD": {Clear: connectionWatchState | connectionMultiState}, - "PSUBSCRIBE": {Set: connectionSubscribeState}, - "SUBSCRIBE": {Set: connectionSubscribeState}, - "MONITOR": {Set: connectionMonitorState}, -} - -func init() { - for n, ci := range commandInfos { - commandInfos[strings.ToLower(n)] = ci - } -} - -func lookupCommandInfo(commandName string) commandInfo { - if ci, ok := commandInfos[commandName]; ok { - return ci - } - return commandInfos[strings.ToUpper(commandName)] -} diff --git a/redis/commandinfo_test.go b/redis/commandinfo_test.go deleted file mode 100644 index 799b9292..00000000 --- a/redis/commandinfo_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package redis - -import "testing" - -func TestLookupCommandInfo(t *testing.T) { - for _, n := range []string{"watch", "WATCH", "wAtch"} { - if lookupCommandInfo(n) == (commandInfo{}) { - t.Errorf("LookupCommandInfo(%q) = CommandInfo{}, expected non-zero value", n) - } - } -} - -func benchmarkLookupCommandInfo(b *testing.B, names ...string) { - for i := 0; i < b.N; i++ { - for _, c := range names { - lookupCommandInfo(c) - } - } -} - -func BenchmarkLookupCommandInfoCorrectCase(b *testing.B) { - benchmarkLookupCommandInfo(b, "watch", "WATCH", "monitor", "MONITOR") -} - -func BenchmarkLookupCommandInfoMixedCase(b *testing.B) { - benchmarkLookupCommandInfo(b, "wAtch", "WeTCH", "monItor", "MONiTOR") -} diff --git a/redis/conn.go b/redis/conn.go index 753644b1..57380b97 100644 --- a/redis/conn.go +++ b/redis/conn.go @@ -37,10 +37,13 @@ var ( // conn is the low-level implementation of Conn type conn struct { // Shared + conn net.Conn + + // Mutex protected fields. mu sync.Mutex - pending int err error - conn net.Conn + pending int + state connectionState // Read readTimeout time.Duration @@ -679,10 +682,18 @@ func (c *conn) readReply() (interface{}, error) { return nil, protocolError("unexpected response line") } +func (c *conn) stateUpdate(cmd string, args ...interface{}) { + c.state.update(connActions, cmd, args...) +} + func (c *conn) Send(cmd string, args ...interface{}) error { c.mu.Lock() - c.pending += 1 + c.stateUpdate(cmd, args...) + if c.state&(stateClientReplyOff|stateClientReplySkipNext|stateClientReplySkip) == 0 { + c.pending += 1 + } c.mu.Unlock() + if c.writeTimeout != 0 { if err := c.conn.SetWriteDeadline(time.Now().Add(c.writeTimeout)); err != nil { return c.fatal(err) @@ -745,13 +756,14 @@ func (c *conn) ReceiveWithTimeout(timeout time.Duration) (reply interface{}, err if timeout != 0 { deadline = time.Now().Add(timeout) } - if err := c.conn.SetReadDeadline(deadline); err != nil { + if err = c.conn.SetReadDeadline(deadline); err != nil { return nil, c.fatal(err) } if reply, err = c.readReply(); err != nil { return nil, c.fatal(err) } + // When using pub/sub, the number of receives can be greater than the // number of sends. To enable normal use of the connection after // unsubscribing from all channels, we do not decrement pending to a @@ -764,10 +776,12 @@ func (c *conn) ReceiveWithTimeout(timeout time.Duration) (reply interface{}, err c.pending -= 1 } c.mu.Unlock() + if err, ok := reply.(Error); ok { return nil, err } - return + + return reply, nil } func (c *conn) Do(cmd string, args ...interface{}) (interface{}, error) { @@ -805,9 +819,15 @@ func (c *conn) DoContext(ctx context.Context, cmd string, args ...interface{}) ( } func (c *conn) DoWithTimeout(readTimeout time.Duration, cmd string, args ...interface{}) (interface{}, error) { + var doPending int c.mu.Lock() + c.stateUpdate(cmd, args...) pending := c.pending c.pending = 0 + if cmd != "" && c.state&(stateClientReplyOff|stateClientReplySkipNext|stateClientReplySkip) == 0 { + // Do is expecting a reply. + doPending = 1 + } c.mu.Unlock() if cmd == "" && pending == 0 { @@ -839,6 +859,7 @@ func (c *conn) DoWithTimeout(readTimeout time.Duration, cmd string, args ...inte } if cmd == "" { + // Empty command indicates we want to ensure unread replies from Send are read. reply := make([]interface{}, pending) for i := range reply { r, e := c.readReply() @@ -850,16 +871,20 @@ func (c *conn) DoWithTimeout(readTimeout time.Duration, cmd string, args ...inte return reply, nil } + // Read all pending replies, from previous Send and the current Do. var err error var reply interface{} - for i := 0; i <= pending; i++ { + pending += doPending + for i := 0; i < pending; i++ { var e error if reply, e = c.readReply(); e != nil { return nil, c.fatal(e) } if e, ok := reply.(Error); ok && err == nil { + // First non-nil error is the error we will return. err = e } } + return reply, err } diff --git a/redis/conn_test.go b/redis/conn_test.go index 0c942ce2..12b8ff7f 100644 --- a/redis/conn_test.go +++ b/redis/conn_test.go @@ -23,10 +23,10 @@ import ( "io" "math" "net" - "sync" "os" "reflect" "strings" + "sync" "testing" "time" @@ -974,33 +974,55 @@ func TestExecError(t *testing.T) { } } -func BenchmarkDoEmpty(b *testing.B) { - b.StopTimer() +func BenchmarkConnDo(b *testing.B) { c, err := redis.DialDefaultServer() - if err != nil { - b.Fatal(err) - } + require.NoError(b, err) defer c.Close() - b.StartTimer() - for i := 0; i < b.N; i++ { - if _, err := c.Do(""); err != nil { - b.Fatal(err) - } - } -} -func BenchmarkDoPing(b *testing.B) { - b.StopTimer() - c, err := redis.DialDefaultServer() - if err != nil { - b.Fatal(err) + // Setup required data. + _, err = c.Do("MSET", "foo", "bar", "bar", "baz") + require.NoError(b, err) + _, err = c.Do("HMSET", "hfoo", "bar", "baz", "qux", "quux", "thing", "bob") + require.NoError(b, err) + + tests := map[string]struct { + cmd string + args []interface{} + }{ + "set": { + cmd: "SET", + args: []interface{}{"foo", "bar"}, + }, + "get": { + cmd: "GET", + args: []interface{}{"foo"}, + }, + "mget": { + cmd: "MGET", + args: []interface{}{"foo", "bar"}, + }, + "hmset": { + cmd: "HMSET", + args: []interface{}{"hfoo", "bar", "baz", "qux", "baz1", "qux1", "stuff"}, + }, + "hgetall": { + cmd: "HGETALL", + args: []interface{}{"hfoo"}, + }, + "blank": { + cmd: "", + }, + "ping": { + cmd: "PING", + }, } - defer c.Close() - b.StartTimer() - for i := 0; i < b.N; i++ { - if _, err := c.Do("PING"); err != nil { - b.Fatal(err) - } + for name, tc := range tests { + b.Run(name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + _, err := c.Do(tc.cmd, tc.args...) + require.NoError(b, err) + } + }) } } diff --git a/redis/connection_state.go b/redis/connection_state.go new file mode 100644 index 00000000..35c45ccf --- /dev/null +++ b/redis/connection_state.go @@ -0,0 +1,71 @@ +// Copyright 2014 Gary Burd +// +// Licensed under the Apache License, Version 2.0 (the "License"): you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +package redis + +// connectionState represents a connection state. +type connectionState uint8 + +const ( + stateWatch connectionState = 1 << iota + stateMulti + stateSubscribe + stateMonitor + stateClientReplyOff + stateClientReplySkipNext + stateClientReplySkip +) + +// commandAction represents an action to be taken when processing a command. +type commandAction struct { + Action func(*connectionState) + + // Next specifies sub actions for given arguments. + Next map[string]*commandAction +} + +// update updates the connection state based on the command and arguments if needed. +func (cs *connectionState) update(info map[string]*commandAction, first string, args ...interface{}) { + *cs &^= stateClientReplySkip + if *cs&stateClientReplySkipNext != 0 { + *cs |= stateClientReplySkip + *cs &^= stateClientReplySkipNext + } + + ci, ok := info[first] + if !ok { + // No match. + return + } + + if ci.Action != nil { + // Match with no more args. + ci.Action(cs) + return + } + + if len(args) == 0 { + // No match due to lack of args. + return + } + + first, ok = args[0].(string) + if !ok { + // No match due type miss-match. + return + } + + // Check the next argument. + cs.update(ci.Next, first, args[1:]...) +} diff --git a/redis/connection_state_test.go b/redis/connection_state_test.go new file mode 100644 index 00000000..f3a60d01 --- /dev/null +++ b/redis/connection_state_test.go @@ -0,0 +1,195 @@ +package redis + +import ( + "strings" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +type lookupTest struct { + state connectionState + expected connectionState + commandName string + args []interface{} + info map[string]*commandAction +} + +func buildLookupTests(tests map[string]lookupTest, root, infos map[string]*commandAction, args ...string) { + for cmd, ci := range infos { + if cmd != strings.ToLower(cmd) { + // Skip non lower case commands as we only need to test one case per action. + continue + } + + cmdArgs := append(args, cmd) + if ci.Next != nil { + buildLookupTests(tests, root, ci.Next, cmdArgs...) + continue + } + + t := lookupTest{ + commandName: cmdArgs[0], + args: make([]interface{}, len(cmdArgs)-1), + info: root, + } + for i, arg := range cmdArgs[1:] { + t.args[i] = arg + } + var state connectionState + ci.Action(&state) + if state != 0 { + // Action is a Set. + t.expected = state + } else { + // Action is a Clear. + state = ^connectionState(0) + ci.Action(&state) + t.state = ^state + } + + tests[strings.Join(cmdArgs, "-")] = t + } +} + +func TestConnectionStateUpdate(t *testing.T) { + tests := make(map[string]lookupTest) + buildLookupTests(tests, activeConnActions, activeConnActions) + buildLookupTests(tests, connActions, connActions) + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + tc.state.update(tc.info, tc.commandName, tc.args...) + require.Equal(t, tc.expected, tc.state) + }) + } +} + +func benchmarkStateUpdate(b *testing.B, names ...string) { + var state connectionState + for i := 0; i < b.N; i++ { + for _, cmd := range names { + state.update(activeConnActions, cmd) + } + } +} + +func BenchmarkConnectionStateUpdateCorrectCase(b *testing.B) { + benchmarkStateUpdate(b, "watch", "WATCH", "monitor", "MONITOR") +} + +func BenchmarkConnectionStateUpdateMixedCase(b *testing.B) { + benchmarkStateUpdate(b, "wAtch", "WeTCH", "monItor", "MONiTOR") +} + +func BenchmarkConnectionStateUpdateNoMatch(b *testing.B) { + benchmarkStateUpdate(b, "GET", "SET", "HMGET", "HMSET") +} + +func TestClientReply(t *testing.T) { + p := &Pool{ + MaxIdle: 1, + MaxActive: 2, + Dial: func() (Conn, error) { + return DialDefaultServer() + }, + } + defer p.Close() + + closeCheck := func(t *testing.T, c Conn) { + t.Helper() + + done := make(chan error) + go func() { + done <- c.Close() + }() + + select { + case err := <-done: + require.NoError(t, err) + case <-time.After(time.Second): + t.Fatal("timeout waiting for connection close") + } + } + + var defaultState connectionState + tests := map[string]func(t *testing.T){ + "off": func(t *testing.T) { + c := p.Get() + defer closeCheck(t, c) + + err := c.Send("CLIENT", "REPLY", "OFF") + require.NoError(t, err) + require.Equal(t, stateClientReplyOff, c.(*activeConn).state) + + err = c.Send("ECHO", "first") + require.NoError(t, err) + require.Equal(t, stateClientReplyOff, c.(*activeConn).state) + + _, err = c.Do("CLIENT", "REPLY", "ON") + require.NoError(t, err) + require.Equal(t, defaultState, c.(*activeConn).state) + + reply, err := String(c.Do("ECHO", "second")) + require.NoError(t, err) + require.Equal(t, "second", reply) + }, + "off-skip": func(t *testing.T) { + c := p.Get() + defer closeCheck(t, c) + + err := c.Send("CLIENT", "REPLY", "OFF") + require.NoError(t, err) + require.Equal(t, stateClientReplyOff, c.(*activeConn).state) + + err = c.Send("ECHO", "first") + require.NoError(t, err) + require.Equal(t, stateClientReplyOff, c.(*activeConn).state) + + // Skip should be ignored as we are already in a off state. + err = c.Send("CLIENT", "REPLY", "SKIP") + require.NoError(t, err) + require.Equal(t, stateClientReplyOff, c.(*activeConn).state) + + _, err = c.Do("CLIENT", "REPLY", "ON") + require.NoError(t, err) + require.Equal(t, defaultState, c.(*activeConn).state) + + reply, err := String(c.Do("ECHO", "second")) + require.NoError(t, err) + require.Equal(t, "second", reply) + }, + "skip": func(t *testing.T) { + c := p.Get() + defer closeCheck(t, c) + + err := c.Send("CLIENT", "REPLY", "SKIP") + require.NoError(t, err) + require.Equal(t, stateClientReplySkipNext, c.(*activeConn).state) + + err = c.Send("ECHO", "first") + require.NoError(t, err) + require.Equal(t, stateClientReplySkip, c.(*activeConn).state) + + err = c.Send("ECHO", "second") + require.NoError(t, err) + require.Equal(t, defaultState, c.(*activeConn).state) + + err = c.Flush() + require.NoError(t, err) + + reply, err := String(c.Receive()) + require.NoError(t, err) + require.Equal(t, "second", reply) + + reply, err = String(c.Do("ECHO", "third")) + require.NoError(t, err) + require.Equal(t, "third", reply) + }, + } + + for name, tc := range tests { + t.Run(name, tc) + } +} diff --git a/redis/generate.go b/redis/generate.go new file mode 100644 index 00000000..9a10f2a3 --- /dev/null +++ b/redis/generate.go @@ -0,0 +1,3 @@ +package redis + +//go:generate go run command_action_gen.go diff --git a/redis/pool.go b/redis/pool.go index d7bb71e0..113ce76e 100644 --- a/redis/pool.go +++ b/redis/pool.go @@ -51,72 +51,71 @@ var ( // request handlers using a package level variable. The pool configuration used // here is an example, not a recommendation. // -// func newPool(addr string) *redis.Pool { -// return &redis.Pool{ -// MaxIdle: 3, -// IdleTimeout: 240 * time.Second, -// // Dial or DialContext must be set. When both are set, DialContext takes precedence over Dial. -// Dial: func () (redis.Conn, error) { return redis.Dial("tcp", addr) }, -// } -// } +// func newPool(addr string) *redis.Pool { +// return &redis.Pool{ +// MaxIdle: 3, +// IdleTimeout: 240 * time.Second, +// // Dial or DialContext must be set. When both are set, DialContext takes precedence over Dial. +// Dial: func () (redis.Conn, error) { return redis.Dial("tcp", addr) }, +// } +// } // -// var ( -// pool *redis.Pool -// redisServer = flag.String("redisServer", ":6379", "") -// ) +// var ( +// pool *redis.Pool +// redisServer = flag.String("redisServer", ":6379", "") +// ) // -// func main() { -// flag.Parse() -// pool = newPool(*redisServer) -// ... -// } +// func main() { +// flag.Parse() +// pool = newPool(*redisServer) +// ... +// } // // A request handler gets a connection from the pool and closes the connection // when the handler is done: // -// func serveHome(w http.ResponseWriter, r *http.Request) { -// conn := pool.Get() -// defer conn.Close() -// ... -// } +// func serveHome(w http.ResponseWriter, r *http.Request) { +// conn := pool.Get() +// defer conn.Close() +// ... +// } // // Use the Dial function to authenticate connections with the AUTH command or // select a database with the SELECT command: // -// pool := &redis.Pool{ -// // Other pool configuration not shown in this example. -// Dial: func () (redis.Conn, error) { -// c, err := redis.Dial("tcp", server) -// if err != nil { -// return nil, err -// } -// if _, err := c.Do("AUTH", password); err != nil { -// c.Close() -// return nil, err -// } -// if _, err := c.Do("SELECT", db); err != nil { -// c.Close() -// return nil, err -// } -// return c, nil -// }, -// } +// pool := &redis.Pool{ +// // Other pool configuration not shown in this example. +// Dial: func () (redis.Conn, error) { +// c, err := redis.Dial("tcp", server) +// if err != nil { +// return nil, err +// } +// if _, err := c.Do("AUTH", password); err != nil { +// c.Close() +// return nil, err +// } +// if _, err := c.Do("SELECT", db); err != nil { +// c.Close() +// return nil, err +// } +// return c, nil +// }, +// } // // Use the TestOnBorrow function to check the health of an idle connection // before the connection is returned to the application. This example PINGs // connections that have been idle more than a minute: // -// pool := &redis.Pool{ -// // Other pool configuration not shown in this example. -// TestOnBorrow: func(c redis.Conn, t time.Time) error { -// if time.Since(t) < time.Minute { -// return nil -// } -// _, err := c.Do("PING") -// return err -// }, -// } -// +// pool := &redis.Pool{ +// // Other pool configuration not shown in this example. +// TestOnBorrow: func(c redis.Conn, t time.Time) error { +// if time.Since(t) < time.Minute { +// return nil +// } +// _, err := c.Do("PING") +// return err +// }, +// } type Pool struct { // Dial is an application supplied function for creating and configuring a // connection. @@ -269,6 +268,7 @@ type PoolStats struct { // ActiveCount is the number of connections in the pool. The count includes // idle connections and connections in use. ActiveCount int + // IdleCount is the number of idle connections in the pool. IdleCount int @@ -429,7 +429,7 @@ func (p *Pool) put(pc *poolConn, forceClose bool) error { type activeConn struct { p *Pool pc *poolConn - state int + state connectionState } var ( @@ -449,6 +449,10 @@ func initSentinel() { } } +func (ac *activeConn) stateUpdate(cmd string, args ...interface{}) { + ac.state.update(activeConnActions, cmd, args...) +} + func (ac *activeConn) firstError(errs ...error) error { for _, err := range errs[:len(errs)-1] { if err != nil { @@ -465,14 +469,18 @@ func (ac *activeConn) Close() (err error) { } ac.pc = nil - if ac.state&connectionMultiState != 0 { - err = pc.c.Send("DISCARD") - ac.state &^= (connectionMultiState | connectionWatchState) - } else if ac.state&connectionWatchState != 0 { - err = pc.c.Send("UNWATCH") - ac.state &^= connectionWatchState + // Return the connection to a clean state if possible. + if ac.state&(stateClientReplyOff|stateClientReplySkip) != 0 { + err = pc.c.Send("CLIENT", "REPLY", "ON") } - if ac.state&connectionSubscribeState != 0 { + + if ac.state&stateMulti != 0 { + err = ac.firstError(err, pc.c.Send("DISCARD")) + } else if ac.state&stateWatch != 0 { + err = ac.firstError(err, pc.c.Send("UNWATCH")) + } + + if ac.state&stateSubscribe != 0 { err = ac.firstError(err, pc.c.Send("UNSUBSCRIBE"), pc.c.Send("PUNSUBSCRIBE"), @@ -491,11 +499,13 @@ func (ac *activeConn) Close() (err error) { break } if p, ok := p.([]byte); ok && bytes.Equal(p, sentinel) { - ac.state &^= connectionSubscribeState + ac.state &^= stateSubscribe break } } } + + // Ensure any pending reads have completed. _, err2 := pc.c.Do("") return ac.firstError( err, @@ -517,13 +527,13 @@ func (ac *activeConn) DoContext(ctx context.Context, commandName string, args .. if pc == nil { return nil, errConnClosed } - cwt, ok := pc.c.(ConnWithContext) + cwc, ok := pc.c.(ConnWithContext) if !ok { return nil, errContextNotSupported } - ci := lookupCommandInfo(commandName) - ac.state = (ac.state | ci.Set) &^ ci.Clear - return cwt.DoContext(ctx, commandName, args...) + ac.stateUpdate(commandName, args...) + + return cwc.DoContext(ctx, commandName, args...) } func (ac *activeConn) Do(commandName string, args ...interface{}) (reply interface{}, err error) { @@ -531,8 +541,8 @@ func (ac *activeConn) Do(commandName string, args ...interface{}) (reply interfa if pc == nil { return nil, errConnClosed } - ci := lookupCommandInfo(commandName) - ac.state = (ac.state | ci.Set) &^ ci.Clear + ac.stateUpdate(commandName, args...) + return pc.c.Do(commandName, args...) } @@ -545,8 +555,8 @@ func (ac *activeConn) DoWithTimeout(timeout time.Duration, commandName string, a if !ok { return nil, errTimeoutNotSupported } - ci := lookupCommandInfo(commandName) - ac.state = (ac.state | ci.Set) &^ ci.Clear + ac.stateUpdate(commandName, args...) + return cwt.DoWithTimeout(timeout, commandName, args...) } @@ -555,8 +565,8 @@ func (ac *activeConn) Send(commandName string, args ...interface{}) error { if pc == nil { return errConnClosed } - ci := lookupCommandInfo(commandName) - ac.state = (ac.state | ci.Set) &^ ci.Clear + ac.stateUpdate(commandName, args...) + return pc.c.Send(commandName, args...) } diff --git a/redis/pool_test.go b/redis/pool_test.go index f420b124..b8572370 100644 --- a/redis/pool_test.go +++ b/redis/pool_test.go @@ -807,6 +807,72 @@ func BenchmarkPoolGet(b *testing.B) { } } +func BenchmarkPoolDo(b *testing.B) { + p := redis.Pool{ + MaxIdle: 2, + Dial: func() (redis.Conn, error) { + return redis.DialDefaultServer() + }, + } + + func() { + // Setup required data. + c := p.Get() + require.NoError(b, c.Err()) + defer func() { + require.NoError(b, c.Close()) + }() + + _, err = c.Do("MSET", "foo", "bar", "bar", "baz") + require.NoError(b, err) + _, err = c.Do("HMSET", "hfoo", "bar", "baz", "qux", "quux", "thing", "bob") + require.NoError(b, err) + }() + + tests := map[string]struct { + cmd string + args []interface{} + }{ + "set": { + cmd: "SET", + args: []interface{}{"foo", "bar"}, + }, + "get": { + cmd: "GET", + args: []interface{}{"foo"}, + }, + "mget": { + cmd: "MGET", + args: []interface{}{"foo", "bar"}, + }, + "hmset": { + cmd: "HMSET", + args: []interface{}{"hfoo", "bar", "baz", "qux", "baz1", "qux1", "stuff"}, + }, + "hgetall": { + cmd: "HGETALL", + args: []interface{}{"hfoo"}, + }, + "blank": { + cmd: "", + }, + "ping": { + cmd: "PING", + }, + } + for name, tc := range tests { + b.Run(name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + c := p.Get() + _, err := c.Do(tc.cmd, tc.args...) + require.NoError(b, err) + err = c.Close() + require.NoError(b, err) + } + }) + } +} + func BenchmarkPoolGetErr(b *testing.B) { b.StopTimer() p := redis.Pool{Dial: func() (redis.Conn, error) { return redis.DialDefaultServer() }, MaxIdle: 2}