x      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   Safe None?"Quote types for string formatting.}Single quote on each side of the formatted string. The parameter sets whether to use Unicode (otherwise use ASCII fallback). }Double quote on each side of the formatted string. The parameter sets whether to use Unicode (otherwise use ASCII fallback). .Backtick on each side of the formatted string. HA bot session action which reacts to a single event which came from an  .Type parameters:e - custom bot environment types - custom bot state typea - event type An  action, possibly running forever, which produces events for the bot to process. These event sources are run by the bot in dedicated threads.Type parameters:e - custom bot environment types - custom bot state typea - event typeBot behavior definition.2Handle a channel member list received. Parameters:  Channel nameChannel privacyVList of channel members: their privilege level in the channel and their nicknamesWhere an event matcher applies.-Tries to match a client event to a bot event.mA ping was sent to the bot. The parameters contain the arguments passed, which should be passed in the Pong.jUsers (2nd parameter) have been kicked from a channel (1st parameter) for a given reason (3rd parameter).8A user (2nd parameter) joined a channel (1st parameter).BA user (2nd parameter) left a channel (1st parameter), 3rd=reason. User, reason.Message (3rd parameter) sent in a channel (1st parameter) by a user with the given nickname (2nd parameter). The last parameter says whether the bot's nick is mentioned in the message.Like !, but it's a pseudo action (/me).Like , but this is a notice. The bot shouldn't send a response (but it can modify its state etc.). First parameter: Just channel, or Nothing. The latter means a private message.4Message referring to the bot sent in a channel. The message begins with the bot's nick, followed by a colon or a comma. For example, if the message was "funbot, hello!" then the 3rd parameter will be "hello!". The parameters are: Channel, nickname, stripped message, full message including the reference.A bot command, which is a message with a special prefix, was sent to a channel or privately to the bot. Parameters: Source, prefix character, command name, command arguments.A private message sent specifically to the bot, from a user with the given nickname (1st parameter) and with the given content (2nd parameter).Like !, but it's a pseudo action (/me).Old nick, new nick.Channel, nickname, topicThe server sent a list of nicknames present in a channel. Parameters: Channel privacy mode, channel name, list of users. Each list item is a pair of a user privilege level in the channel, and the user's nickname.TUnrecognized or unimplemented event. The parameter contains (possibly empty) input. Bot monad. It provides read-only bot environment (e.g. the configuration), read-writable bot state (for use by bot commands) and IO.!8A message sent previously by an IRC user into a channel.(1Per-channel information to return to the API user*<Whether user-in-channel tracking is enabled for this channel+4Whether message counting is enabled for this channel,3Whether logging-to-file is enabled for this channel-;Maximal number of channel message history lines to remember.Message counter log entry./$Number of messages sent in a channel0User joined the channel1User left the channel2The bot recognizes commands by picking IRC channel messages which begin with a special character, the command prefix. It's possible to have several prefixes, maybe give each its own role or meaning. A command set is a set of commands which share a prefix.&A command can be in more than one set.Common prefixes are !, \@, , :.6QA bot command, triggered by a message sent to an IRC channel the bot has joined.The type parameter eG is the type of environment, i.e. real-only state. The type parameter s is the type of the writable state the bot holds. For example, maybe you want your bot to keep a list of to-do items and manage it using bot commands. The bot state is where you store the to-do list.8 The command's name string, e.g. "echo"k. More than one name is allowed per command, so that localized names and shortcuts can be made available.-The first name in the list is considered the  primary nameN. When one name is shown, e.g. in help messages, it will be the primary name.9What to do in response to the command being triggered by an IRC user. The bot can send an IRC message back to the channel, or modify its state, or both.The returned value is in the   monad (it is really  behind the scenes), which allows the bot to access the configuration and bot state, store and load data from files, communicate through the network (e.g. download RSS feeds) and more. Parameters: 2Channel in which the command was triggered, if any*Nickname of user who triggered the commandCommand parameters givenDAction for sending a message back to the sender, same as using sendBack with the channel and nickname:Help string for the command, explaining it purpose, its parameters and its usage, possibly giving an example. May contain newlines.;'Describes wrong usage of a bot command.<&The number of arguments given is wrong==<first-param> arguments were given, instead of <second-param>>(At least one of the arguments is invalid?DArgument in position <first-param> and value <second-param> invalid@*Some other error, with a given descriptionIA message for the bot can come privately or in a channel by a given user.A,Configuration for the bot connection to IRC.C<Connection details, including nickname and optional passwordD8The list of channels for the bot to join is generally set in the state file, but when the bot launches it joins both the channels listed there and the ones listed here. This list is intended to be used as hard-coded backup, i.e. the bot will always join these channels regardless of what the state file says.EuDirectory path under which IRC log files will be placed. Relative to the bot process working directory, or absolute.FDirectory path for the state file. This enables Git commits of the state file. A relative (to the bot process working dir) or absolute path to the Git repository. You must create the directory yourself if it doesn't exist, but repo will be auto-created for you if needed.GtFilename into the bot state managed by this library will be stored. The custom part of the state isn't handled. If stateDir is n, this is a path relative to the bot process working directory, or absolute. Otherwise, it's relative to the stateDir.HMinimal time interval between state saves. For example, to say "don't write state to file more than once per three seconds", set this field to 3 seconds, i.e. time (3 :: Second).INFilename for the bot's main event log, i.e. produced by the IRC event source.JFilename for writing error messages generated by invalid IRC lines or errors in their analysis or in event detection. Useful for debugging.KsMaximal number of characters in a message the bot can send to a user or a channel. Longer messages will be split. Y means no limit, i.e. let the IRC server truncate long messages. This limit applies to  sendToUser and  sendToChannelY and all the functions which use them. A safe default if you want to set a limit is 400.LVTime interval for sending PINGs to the server, to make sure the connection is alive.  means no PINGs sent.M.Maximal lag time allowed before the bot quits.N Maximal number of messages to count per channel in the message counter. Possibly a bit more will be counted, in cases it doesn't require more memory anyway. If a user misses more than that number N, they will simply be notified "you missed at least N messages!".TODO actually right now this is the maximal length of the per-channel log, which includes messages, joins and parts. It's just a tool to limit memory usage, nothing more.O#IRC messages can be sent to users or channels either instantly, or through a dedicated sender thread. That thread creates a delay between messages, to avoid flooding, since that may result with the server blocking some of the messages. This option sets the time to wait between messages. =The bot configuration. The event source may find this useful.DThe bot's custom environment. The event source may find this useful.A non-blocking ; action which sends a given event to the processing queue.A non-blocking D action which sends a given list of events to the processing queue.An  action which creates a logger with a given target filename. An event source can use it to log events, errors, debug into, etc. into files efficiently.  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO   !"#$%&'()*+,-./01 23456789:;<=>?@ABCDEFGHIJKLMNONoneO  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOOABCDEFGHIJKLMNO;<=>?@6789:2345!"#$%&'()*+,-./01   NonePAdd quotes to a string.Q"Optionally add quotes to a string.RFormat a list of labels.0putStrLn $ showNames (Just $ SingleQuotes False)", "["one", "two", "three"]'one', 'two', 'three'PQR"Optionally wrap labels with quotes/Separate between labels, e.g. spaces or newlineList of labelsPQRPQRPQRNoneSA default behavior definition which be convenienty overridden and extended using record syntax. It currently simply doesn't do anything (pings do get handled behind the scenes), but things like default responses and logging could be added in the future.TsTake a command name (without prefix) and a command set, and return the (leftmost) command which has that name, or  if there is no such command.UuFind a command in a list of command sets, using the given prefix character and command name. This is a shortcut for Va which doesn't return the matched command set (for the cases you only need to find the command).V{Find a command in a list of command sets, using the given prefix character and command name. If the prefix isn't matched, ? is returned. If the prefix is matched but the command isn't,  * the command set is returned. Otherwise,  ! the matched command is returned.WkTake a command prefix and a list of command sets, and return the (leftmost) set which has that prefex, or  if there is no such set.XSearch for commands by testing a search string against their textual fields: Names and help strings. Each returned pair is a command and the prefix under which it was found.YFormat a list of command names.Z9Format a list of the primary names of the given commands.STUVCommand prefix to search forCommand name to search forCommand set in which to searchWXY+Optionally prepend the prefix char to names&Optionally add quotes around the names5Whether to separate with commas (otherwise spaces)List of command namesZ.Optionally prepend the prefix char to names&Optionally add quotes around the names5Whether to separate with commas (otherwise spaces)List of commandsSTUVWXYZSTUVWXYZSTUVWXYZNone[Fetch the bot configuration.\-Retrieve a function of the bot configuration.]"Fetch the bot behavior definition.^3Retrieve a function of the bot behavior definition._0Fetch the bot environment, i.e. read-only state.`+Retrieve a function of the bot environment.$Fetch the bot session socket handle.aFetch the time getter. The actual time data is cached and updated at most once per second depending on need. You can safely use it at any frequency withou overloading IO and time formatting.8The second item is a formatted time string in the form 2015-09-01 18:10:00!, and is always expressed in UTC.Fetch the minute getter. The actual data is cached and updated at most once per minute depending on need. You can safely use it at any frequency withou overloading IO and time formatting.bIGet the number of minutes since the epoch using an auto updating counter.c8Fetch the current value of the state within the session.dMGet a specific component of the state, using a projection function supplied.e!Set the state within the session.fLUpdate the state to the result of applying a function to the current state.gIGet a mapping between channel names and sequences of their last messages.hZGet channel state information, in the form of a mapping from channel names to their data.iCCheck whether a channel is listed in persistent state to be joined.jCheck whether, as far as the bot knows, if it currently a member of the given channel. Currently kicks, bans, etc. are fully tracked, therefore this information isn't 100% accurate, but if you aren't planning to ban your bot you can probably rely on it.[\]^_`abcdefgh    ij[\]^_`abcdefgh    ij[\]^_`abcdefgh    ijNonekSend an IRC message to the server. This should only be used if the other wrappers don't provide what you need. If that's the case, it may be a good idea for reusability to add a new wrapper.kkkNonel.Check whether a given channel is being logged.mMStart logging all the channels the bot has joined which aren't being logged.n=Start logging the given channel, if not being logged already.oBStart logging the channels not being logged, among the ones given.p!Stop logging all logged channels.q0Stop logging the given channel, if being logged.r<Stop logging the channels being logged among the ones given.  lmnopqr lmnopqr  lmnopqrNonelmnopqrlmnopqrNones/Check whether a given channel is being tracked.tXStart tracking nicks in all the channels the bot has joined which aren't being tracked.uBStart tracking nicks in the given channel, if not tracked already.vGStart tracking nicks in the channels not tracked, among the ones given.w,Stop tracking nicks in all tracked channels.x5Stop tracking nicks in the given channel, if tracked.yAStop tracking nicks in the tracked channels among the ones given.z1Check whether a nickname is present in a channel.{.Check in which channels a nickname is present.-Record a nickname being present in a channel.yRecord a nickname change. Remove old nickname from the channels in which it's present, and add the new nickname to them.2Record a channel with the given present nicknames.5Record a channel not having a given nickname anymore.;Record a nickname not being present in any channel anymore."Remove a channel from the records.!Remove channels from the records.stuvwxyz{stuvwxyz{stuvwxyz{None stuvwxyz{ tuvwxysz{None}eAdd a channel to the persistent list of channels to be joined. Next time the bot launches (or, say,  joinConfig[ is called), it will join this channel. If the channel is already listed, nothing happens.~Remove a channel from the persistent list of channels to be joined. Next time the bot launches, it won't join this channel (unless listed in the config or otherwise requested). If the channel isn't listed, nothing happens.Add default channel state for the given channel. It will be stored into the state file. If the channel already has state, nothing will happen.|}~ !"#|}~|}~ !"#None[\]^_`abcdefghij|}~[\]^ab_`cdefgh}~ij|NoneRStart counting in all the channels the bot has joined which aren't being counted.<Start counting in the given channel, if not counted already.AStart counting in the channels not counted, among the ones given.&Stop counting in all counted channels./Stop counting in the given channel, if counted.;Stop counting in the counted channels among the ones given.RGet a mapping between channel names and sequences of their message counting data.VGet the count log for a specific channel. If there is none, an empty log is returned./Check whether a given channel is being counted.WCheck whether a given user ever parted the channel, as far as the count log remembers.WCheck whether a given user ever joined the channel, as far as the count log remembers.8Determine how many messages a log sequence has recorded._Find out how many messages the channel had since the given user parted it. On success, return D it. Otherwise, i.e. if no parting of the user is recorded, return  the total recorded messages.$+Count a message in the channel's count log.%(Count a join in the channel's count log.&ACount a part (i.e. leave one channel) in the channel's count log.'BCount a quit (i.e. leave all channels) in the channel's count log.(BIf en event needs to be considered in message counting, handle it.)*+,$%&'($%&'()*+,$%&'( None NoneCreate a logger in the  monad.'Create a logger inside the bot session.$Flush buffers and release resources.When the logger is paused for a long period of time (i.e. not momentarily - e.g. by a user disabling channel logging via UI), you can use this to release resources. Later, when logging is needed again, create a fresh new logger.Write a log message.1Action which returns a formatted time string. YouPath of the log file--None  None.<Remember someone said something, for use later when quoting./8If a client event is a message to remember, get details..Channel User nicknameMessage6Whether a /me action (True) or regular message (False)/././NoneDisconnect from IRC by closing the bot's side of the connection. This function is mainly provided for completeness and cases of error. You should probably use the QUIT command of IRC to quit the network in a manner coordinated with the server.=After disconnection, make sure not to send more IRC commands.BFinish the IRC session, asking the server to close the connection.0Connect to an IRC server and run the bot sessionnLog in as an IRC user and identify with the bot's nickname and password. This is the first thing to do after  botConnecting to the server.IRC servers send PING messages at regular intervals to test the presence of an active client, at least if no other activity is detected on the connection. The server closes the connection automatically if a PONG response isn't sent from the client within a certain amount of time.Therefore, an IRC client (both human users and bots) usually listens to these PINGs and sends back PONG messages. This function sends a PONG. The parameters should simply be the ones received in the PING message.Join an IRC channel.Join one or more IRC channels.Join the IRC channels listed for joining in the persistent state and in the configuration, without leaving any other channels the bot already joined.Leave an IRC channel.Leave one or more IRC channels.&Leave all IRC channels the bot joined.!Send a message to an IRC channel.This usually requires that the bot joins the channel first, because many channels have the +n flag set. This flag forbids sending a messages into a channel from outside it.This function doesn't instantly send the message, but instead queues it for sending by the sending scheduler thread, which adds delay to avoid flood. If you want to send instantly, see 0.0 A variant of * which sends instantly, without any delay.&Send a private message to an IRC user.This function doesn't instantly send the message, but instead queues it for sending by the sending scheduler thread, which adds delay to avoid flood. If you want to send instantly, see 1.1 A variant of * which sends instantly, without any delay.sSend a message back to the sender. If a channel is specified, send to the channel. If not, send a private message.2 A variant of * which sends instantly, without any delay..Optional message, e.g. the reason for quitting3IRC configurationBot behavior definition(Custom bot environment (read-only state)Initial custom bot stateSession definition Server nameOptional server to forward to Channel nameOptional channel key (password)"List of channels and optional keys Channel name5Optional part message, e.g. the reason for leavingList of channel names5Optional part message, e.g. the reason for leaving456789:;<=>?The channel name{The message to send. It may contain newlines, in which case it will be split into multiple messages and sent sequentially.0The channel name{The message to send. It may contain newlines, in which case it will be split into multiple messages and sent sequentially.The user's nicknameThe message to send. It may contain newlines, in which case it will be split into multiple messages and sent sequentially.1The user's nicknameThe message to send. It may contain newlines, in which case it will be split into multiple messages and sent sequentially.TChannel name, specify if replying to a message sent in a channel. Otherwise pass .The sender user's nicknameThe message to send. It may contain newlines, in which case it will be split into multiple messages and sent sequentially.2TChannel name, specify if replying to a message sent in a channel. Otherwise pass .The sender user's nicknameThe message to send. It may contain newlines, in which case it will be split into multiple messages and sent sequentially.90123456789:;<=>?012None@+Send the default response to an IRC channelA(Send the default response to an IRC user4Send message explaining a failure to an IRC channel.1Send message explaining a failure to an IRC user.5Send message explaining a failure back to the sender.B@ACDTarget channelUser to whom to referProblem indication Target userProblem indicationOptional target channel,  means private messageTarget user nicknameProblem indication@AB@ACDNoneE3Handle a bot event, or log a log event into a file.)FGHIJKLMNOPQRSTUVWXYZ[\EWE)FGHIJKLMNOPQRSTUVWXYZ[\E NoneNonekk NoneA default bot configuration. You can use it with record syntax to override just the fields you need. It also allows your code to remain valid when a new config option is added, since you won't be using the A constructor directy.In the future the constructor may be removed, and then this function will be the only way to create a configuration. It allows adding a field without incrementing the library's major version and breaking compatibility.Start the bot and run its event loop. The bot will listen to messages from the IRC server and other provided sources, and will respond according to the behavior definitions. ]^_`abcdIRC connection configuration&Event detection (high-to-low priority)"Behavior definition for IRC events&Additional event source threads to run,Handler for events coming from those sources(Custom bot environment (read-only state)'Initial state to hold in the backgroundDInitialization action to run at the very beginning of the session ]^_`abcde  ! " # $ % & ' ( ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : : ; < = > ? @ @ A B C D E F G H I I J K L L M N O P Q R S T U V V W X Y Z [ \ ] ^ _ ` a b cdefghijklmnopqrstuvwxyz{|}~                              '                       !"#$%&'()*+,-./'(00123456789:;<=>?'(@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnop q r s t u v w xyircfu_035kaU5cFB26q7tHvzl1kmNetwork.IRC.Fun.Bot.TypesNetwork.IRC.Fun.Bot.LoggerNetwork.IRC.Fun.Bot.UtilNetwork.IRC.Fun.Bot.BehaviorNetwork.IRC.Fun.Bot.StateNetwork.IRC.Fun.Bot.ChatNetwork.IRC.Fun.Bot.IrcLogNetwork.IRC.Fun.Bot.NicksNetwork.IRC.Fun.Bot.MsgCountNetwork.IRC.Fun.Bot.EventMatchNetwork.IRC.Fun.BotData.Sequence.Util"Network.IRC.Fun.Bot.Internal.Types"Network.IRC.Fun.Bot.Internal.State$Network.IRC.Fun.Bot.Internal.ChatExt#Network.IRC.Fun.Bot.Internal.IrcLog"Network.IRC.Fun.Bot.Internal.Nicks$Network.IRC.Fun.Bot.Internal.Persist%Network.IRC.Fun.Bot.Internal.MsgCount#Network.IRC.Fun.Bot.Internal.Logger$Network.IRC.Fun.Bot.Internal.History!Network.IRC.Fun.Bot.Internal.Chat$Network.IRC.Fun.Bot.Internal.Failure"Network.IRC.Fun.Bot.Internal.Eventircfu_1WZqFV284MaG9dQhDAYeIcNetwork.IRC.Fun.Client.IO connPasswordconnNickconnTlsconnPort connServer ConnectionQuotes SingleQuotes DoubleQuotes BackTicks EventHandler EventSourceLoggerBehavior handleJoin handlePart handleQuit handleMsg handleAction handleBotMsg commandSetshandlePersonalMsghandlePersonalActionhandleNickChangehandleTopicChange handleNamesEventMatchSpaceMatchInChannelMatchInPrivate MatchInBothSession HistoryLinehlTimehlNick hlMessagehlActionhlMinuteChanInfociTrackciCountciLogciHistoryLines MsgCountEntry MsgCountMsgs MsgCountJoin MsgCountPart CommandSet csetPrefix csetCommandsCommandcmdNames cmdRespondcmdHelpFailure WrongNumArgs WrongNumArgsN InvalidArgs InvalidArg OtherFailConfig cfgConnection cfgChannels cfgLogDir cfgStateRepo cfgStateFilecfgSaveIntervalcfgBotEventLogFilecfgIrcErrorLogFilecfgMaxMsgChars cfgLagCheck cfgLagMaxcfgMaxMsgCount cfgMsgDelayquote maybeQuote showNamesdefaultBehavior findCmdInSet findCmdInSetsfindCmdfindSet searchCmds listNameslistPrimaryNames askConfig askConfigS askBehavior askBehaviorSaskEnvaskEnvS askTimeGetter getMinutesgetState getStateSputState modifyState getHistory getChanInfochannelSelected botMemberOfputIrcchannelIsLoggedstartLoggingAllstartLoggingChannelstartLoggingChannelsstopLoggingAllstopLoggingChannelstopLoggingChannelschannelIsTrackedstartTrackingAllstartTrackingChannelstartTrackingChannelsstopTrackingAllstopTrackingChannelstopTrackingChannels isInChannelpresence saveBotState selectChannelunselectChanneladdChannelStatestartCountingAllstartCountingChanstartCountingChansstopCountingAllstopCountingChanstopCountingChans getCountLogs getCountLog chanIsCounted everParted everJoined countMsgsmsgsSinceParted newLogger newLogger' removeLoggerlogLine disconnectquitrunloginpong joinChannel joinMulti joinConfig partChannel partMultipartAll sendToChannel sendToUsersendBack failToChannel failToUserfailBackmodId modPrefix modPrefixes modPrefixCI modPrefixesCImodPleasePrefixmodPleasePrefix'matchPrefixedCommandmatchPrefixedCommandFromSetmatchPrefixedCommandFromNamesmatchRefCommandmatchRefCommandFromSetmatchRefCommandFromNamesmatchPlainPrivateCommand matchNoticematchRef defaultMatch defConfigrunBottailghc-prim GHC.TypesIO EventMatcherPingKickJoinPartQuitMessageActionNotice BotMessage BotCommandPersonalMessagePersonalAction NickChange TopicChangeNames OtherEvent GHC.Classes>trans_7m6PsD4vGWRLSOXZcRxLfrControl.Monad.Trans.RWS.LazyRWST MessageSourcebaseGHC.BaseNothingMsg MsgLogEventMsgHistoryEventMsgCountLogMsgMsgCountLogJoinMsgCountLogPartMsgCountLogQuit MsgBotEvent MsgExtEventMsgQuit loggerSet loggerGetTimeEventBotState bsTracker bsChannels bsCurrChans bsSelChans bsHistory bsMsgCountLogbsPublic ChanState csTracking csCountingcsLoggercsHistoryLinesBotEnvbeConfig beBehaviorbeHandle beGetTime beGetMinute beSaveState beMsgQueuebeCustomIrcMsgmsgRecipmsgLinesChannelUserircfu_4kn1V4y9YHR3PDhJDsofm4'Network.IRC.Fun.Messages.Internal.TypesChannelPrivacySecretPrivatePublic PrivilegeRegularVoiceOperatorJust Data.EitherLeftRight askHandleaskMinuteGetter stateToInfogetChansputChans modifyChans addCurrChanremoveCurrChanclearCurrChans makeLoggerenabledisable addMember changeNick addChannelremoveMemberOnce removeMember removeChannelremoveChannels BotStateJtoJfromJ loadBotStatemkSaveBotState$fToJSONBotState$fToJSONBotStateJ$fFromJSONBotStateJ$fToJSONChanInfo$fFromJSONChanInfo recordMsg recordJoin recordPart recordQuit countEventset modifyLog formatLine rememberMsg checkEventsendToChannelNow sendToUserNow sendBackNow runSessionsplitN makeLines logChanMsgsendToChannelIO sendToUserIOsendIOsendToChannelHeresendToUserHeresendToChannelDefersendToUserDefersendToChannelImplsendToUserImpldefaultRespondToChandefaultRespondToUserdefaultResponsesuffixfailureDescription handleEvent stripPrefixCI detectRefmkCmdexpandmakePrefixedCommandmakePrefixedCommandFromSetmakePrefixedCommandFromNamesmakeRefCommandmakeRefCommandFromSetmakeRefCommandFromNamesmakePlainCommandmakeRefCmakeRefPifPrivifChancombineMatchers applyMatchers matchEvent findCommand runCommandhandleBotEventdetectLogEventshandleLogEventstartBot listenToEventgetNow listenToIrcintervalToSpec manageLag sendMessages botSession