Full Code of gawel/irc3 for AI

main 62446ad4ded8 cached
166 files
746.4 KB
198.8k tokens
873 symbols
1 requests
Download .txt
Showing preview only (791K chars total). Download the full file or copy to clipboard to get everything.
Repository: gawel/irc3
Branch: main
Commit: 62446ad4ded8
Files: 166
Total size: 746.4 KB

Directory structure:
gitextract_t3elpfhu/

├── .coveragerc
├── .github/
│   └── workflows/
│       └── tox.yml
├── .gitignore
├── CHANGES.rst
├── CONTRIBUTING.rst
├── LICENSE
├── MANIFEST.in
├── Makefile
├── README.rst
├── conftest.py
├── docker/
│   ├── Dockerfile
│   └── Makefile
├── docs/
│   ├── Makefile
│   ├── conf.py
│   ├── dcc.rst
│   ├── dec.rst
│   ├── hack.rst
│   ├── index.rst
│   ├── irc3.rst
│   ├── plugins/
│   │   ├── asynchronious.rst
│   │   ├── autocommand.rst
│   │   ├── autojoins.rst
│   │   ├── casefold.rst
│   │   ├── command.rst
│   │   ├── core.rst
│   │   ├── cron.rst
│   │   ├── ctcp.rst
│   │   ├── dcc.rst
│   │   ├── feeds.rst
│   │   ├── fifo.rst
│   │   ├── human.rst
│   │   ├── log.rst
│   │   ├── logger.rst
│   │   ├── pager.rst
│   │   ├── quakenet.rst
│   │   ├── sasl.rst
│   │   ├── search.rst
│   │   ├── shell_command.rst
│   │   ├── slack.rst
│   │   ├── social.rst
│   │   ├── storage.rst
│   │   ├── uptime.rst
│   │   ├── userlist.rst
│   │   └── web.rst
│   ├── reloadable.rst
│   ├── rfc.rst
│   └── utils.rst
├── examples/
│   ├── async_command.py
│   ├── benches.ini
│   ├── benches.py
│   ├── bot.ini
│   ├── commands.rst
│   ├── config.ini
│   ├── dcc_chat.py
│   ├── dcc_send.py
│   ├── dcc_send_and_get.py
│   ├── dev.ini
│   ├── freenode_irc3.py
│   ├── humans.py
│   ├── mybot.py
│   ├── mybot_plugin.py
│   ├── mycommands.py
│   ├── mycrons.py
│   ├── myextends.py
│   ├── nickserv.py
│   ├── paginate.py
│   ├── proxy.py
│   ├── slack.ini
│   ├── spy.ini
│   ├── spy.py
│   ├── topic.py
│   └── wsgiapp.py
├── irc3/
│   ├── __init__.py
│   ├── __main__.py
│   ├── _gen_doc.py
│   ├── _parse_rfc.py
│   ├── _rfc.py
│   ├── asynchronous.py
│   ├── base.py
│   ├── compat.py
│   ├── config.py
│   ├── dcc/
│   │   ├── __init__.py
│   │   ├── client.py
│   │   └── manager.py
│   ├── dec.py
│   ├── plugins/
│   │   ├── __init__.py
│   │   ├── asynchronious.py
│   │   ├── autocommand.py
│   │   ├── autojoins.py
│   │   ├── casefold.py
│   │   ├── command.py
│   │   ├── core.py
│   │   ├── cron.py
│   │   ├── ctcp.py
│   │   ├── dcc.py
│   │   ├── feeds.py
│   │   ├── fifo.py
│   │   ├── human.py
│   │   ├── log.py
│   │   ├── logger.py
│   │   ├── pager.py
│   │   ├── quakenet.py
│   │   ├── sasl.py
│   │   ├── search.py
│   │   ├── shell_command.py
│   │   ├── slack.py
│   │   ├── social.py
│   │   ├── storage.py
│   │   ├── uptime.py
│   │   ├── userlist.py
│   │   └── web.py
│   ├── rfc.py
│   ├── rfc1459.txt
│   ├── rfc2812.txt
│   ├── tags.py
│   ├── template/
│   │   ├── __init__.py
│   │   ├── __main__.py
│   │   ├── config.ini
│   │   └── plugin.py
│   ├── testing.py
│   └── utils.py
├── irc3d/
│   ├── __init__.py
│   ├── __main__.py
│   ├── dec.py
│   ├── motd.txt
│   └── plugins/
│       ├── __init__.py
│       ├── command.py
│       ├── core.py
│       └── userlist.py
├── pyproject.toml
├── tests/
│   ├── __init__.py
│   ├── feed.atom
│   ├── test.ini
│   ├── test_async.py
│   ├── test_autocommand.py
│   ├── test_autojoins.py
│   ├── test_bot.py
│   ├── test_casefold.py
│   ├── test_commands.py
│   ├── test_cron.py
│   ├── test_ctcp.py
│   ├── test_dcc.py
│   ├── test_dec.py
│   ├── test_events.py
│   ├── test_feeds.py
│   ├── test_fifo.py
│   ├── test_irc3d.py
│   ├── test_irc3d_commands.py
│   ├── test_irc3d_userlist.py
│   ├── test_logger.py
│   ├── test_paginate.py
│   ├── test_protocol.py
│   ├── test_quakenet.py
│   ├── test_reconn.py
│   ├── test_reload.py
│   ├── test_run.py
│   ├── test_sasl.py
│   ├── test_search.py
│   ├── test_slack.py
│   ├── test_social.py
│   ├── test_template.py
│   ├── test_uptime.py
│   ├── test_userlist.py
│   ├── test_utils.py
│   └── test_web.py
└── tox.ini

================================================
FILE CONTENTS
================================================

================================================
FILE: .coveragerc
================================================
[run]
include =
    */irc3/*.py
    */irc3/*/*.py
omit =
    conftest.py
    .tox/*
    tests/*
    docs/conf.py
    */examples/social*
    */examples/mycrons*
    */examples/mycommands*
    */examples/myextends*
    */examples/nickserv*
    */examples/freenode*
    */irc3/template/plugin*
    */irc3/_gen_doc*
    */irc3/_parse_rfc*
    */site-packages*
    */lib/python*
    */lib-python*
    */lib_pypy*

[report]
exclude_lines =
    pragma: no cover
    def __repr__
    raise NotImplementedError
    if __name__ == .__main__.:
    def parse_args


================================================
FILE: .github/workflows/tox.yml
================================================
name: tox

on: [push, pull_request]

jobs:
  flake8-and-docs:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v4
        with:
          python-version: 3.12
      - name: Install Tox and any other packages
        run: pip install tox
      - name: Run flake8 / docs
        run: tox -e flake8,docs

  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python: ["3.11", "3.12", "3.13"]

    steps:
      - uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python }}
      - name: Start Redis
        uses: supercharge/redis-github-action@1.8.1
        with:
          redis-version: 8
      - name: Install Tox and any other packages
        run: pip install tox
      - name: Run Tox
        run: tox -e py


================================================
FILE: .gitignore
================================================
*~
*.bck
bin
build
_build
.bzr
.bzrignore
.eggs
.cache
.chutifab
.coverage
coverage*
develop-eggs
dist
downloads
*.egg
*.EGG
*.egg-info
*.EGG-INFO
eggs
fake-eggs
.hg
.hgignore
.idea
.installed.cfg
irssi_config
*.jar
*.mo
.mr.developer.cfg
nosetest*
*.old
*.orig
parts
*.pyc
*.pyd
*.pyo
.ropeproject/
*.so
src
.svn
*.swp
.tox
*.tmp*
var
*.wpr


================================================
FILE: CHANGES.rst
================================================
1.1.11 (unreleased)
===================

- Nothing changed yet.


1.1.10 (2023-04-17)
===================

- fix `shell_command` plugin


1.1.9 (2023-02-27)
==================

- drop support for python 3.5

- python 3.11 compat


1.1.8 (2022-07-17)
==================

- Allow comma-separated chans in server userlist JOIN

- python 3.10 compat

- improve feeds plugin


1.1.7 (2021-02-13)
==================

- Add sqlite storage.

- Escape string that are interpolated into the regular expressions.


1.1.6 (2020-05-13)
==================

- Allow to overrides config values via `os.environ`.


1.1.5 (2020-01-18)
==================

- Allow to use `irc3.rfc.*` as `iotype='out'`

- Use more pop in userlist to avoid bug when a weird event occurs

1.1.4 (2019-11-22)
==================

- Use pop in userlist to avoid bug when a weird event occurs

- Expend filename path in logger plugin

- Force latest venusian version


1.1.3 (2019-08-22)
==================

- Rename async plugin to asynchronious so we can use it with python3.7


1.1.2 (2019-02-28)
==================

- Allow to have more than one `[bot]` section in config file

- IrcString now allow to retrieve username/hostname from mask


1.1.1 (2018-09-22)
==================

- Do not show builtins command in help. Fixed #167


1.1.0 (2018-07-30)
==================

- Backward incompatibility: async is renamed to asynchronous for py37 compat
  (thanks to @JulienPalard)

- Except a KeyError on missing twitter configuration in social plugin

1.0.3 (2018-05-08)
==================

- Add web plugin to allow to POST messages to channel via http

- Add slack plugin

- Avoid bug in userlist when a user parts before join (twitch)

- Drop py33, py34 support

1.0.2 (2017-11-13)
==================

- Add `irc3.__main__` to allow `python -m irc3 config.ini`


1.0.1 (2017-11-11)
==================

- Add `command(error_format=callable)` argument.

- Add ${#} as a shorter alias for ${hash}.

- Bug fix in fifo plugin. We now remove the file first if it's not a pipe.

- Fix some irc3d issues with QUIT and KICK command


1.0.0 (2017-02-05)
==================

- Added storage.getlist()/setlist()

- Improve autocommands


0.9.8 (2017-01-03)
==================

- Command aliases support (#121)

- Add quakenet plugin (#99)

- Allow dash character in command


0.9.7 (2016-12-07)
==================

- Added ``bot.async_cmds.topic()``

- Use shlex to parse command args by default


0.9.6 (2016-10-24)
==================

- Fixed #118: ssl context.check_hostname must be False when using CERT_NONE


0.9.5 (2016-10-15)
==================

- ``.privmsg(nowait=True)`` now really don't wait

- clean up some old py2/3 compat code

0.9.4 (2016-09-15)
==================

- Added SASL Auth support

0.9.3 (2016-05-31)
==================

- New release due to release problem (broken pypi)


0.9.2 (2016-05-31)
==================

- Fixed flood_burst sending one extra line (#92)

0.9.1 (2016-05-22)
==================

- Added autojoin_delay option. Handle reload in autojoin plugin.

- Added flood_rate_delay option.

- Added --help and --version CLI options.

- Fixed #91 bug with command arguments and spaces

0.9.0 (2016-04-20)
==================

- WARNING: we do no longer support python2. python3.3+ is required.

- WARNING: realname is now username and userinfo is now realname in config

- Introduce some plugins: fifo, shell_commands, pager

- Add ``flood_burst`` and ``flood_rate`` options. Queue outgoing messages in a
  single queue handle by ``send_line('...', nowait=False)``.

- ``bot.async`` is now aliased to ``bot.async_cmds`` to be able to use ``await``

0.8.9 (2016-02-23)
==================

- use re.escape to escape command char


0.8.8 (2016-01-27)
==================

- logger plugin now take care of unicode


0.8.7 (2016-01-16)
==================

- fixed 76: split large messages using textwrap.wrap(). This will avoid RevQ
  exceeded.


0.8.6 (2016-01-07)
==================

- fix DCC stuff for python3.5

- added DCC examples at https://github.com/gawel/irc3/tree/master/examples


0.8.5 (2015-12-22)
==================

-  ${hash} is now replaced by # in config files. This allow to set real channel
   names.


0.8.4 (2015-11-29)
==================

- added basic support for IRCv3.2 tags

- fixed #78: plugin can be old style classes

- fixed #75: Ensure we send the PING and PONG data as trailing

- fixed #71: need to pass host and ip to dcc


0.8.3 (2015-11-04)
==================

- fix wheel metadata

- public command was not public if you're using a guard


0.8.2 (2015-11-01)
==================

- Added !help nonexistant error message

- Allow to hide commands from !help

- Don't reject commands with trailing spaces

- Allow to use coroutine guards

- Make commands case insensitive

- Add basic casefolding plugin

- Prevent keyerror when setting keys that don't exist in cache.

0.8.1 (2015-05-14)
==================

-  Fixes bug in userlist plugin `#59 <https://github.com/gawel/irc3/pull/59>`_

-  Strip out self.context.config.cmd from !help arg. Allow to use !help !cmd
   `#57 <https://github.com/gawel/irc3/pull/57>`_


0.8.0 (2015-04-19)
==================

- Added dcc send/get/chat implementation

- Improved storage: can now test the existence of a key

- irc.plugins.storage: `db['foo']` now will raise a `KeyError` if the key does
  not exist to match dictionary behaviour. This will **break** existing
  implementations that make use of this.

- irc.plugins.storage now supports `db.get(key)`  that will return either `None`
  or the value of an optional `default` argument.

- irc3.plugins.feeds is now full async


0.7.1 (2015-02-26)
==================

- Storage plugin documentation

- Support python 3.4.1 again


0.7.0 (2015-02-24)
==================

- the cron plugin now require
  `aiocron <https://pypi.python.org/pypi/aiocron/>`_

- Add `irc3.plugins.async`; Allow to `yield from bot.async.whois('gawel')`

- commands and events can now be coroutines


0.6.0 (2015-02-15)
==================

- Allow to reload modules/plugins

- Add storage plugin

- Fixed #34 Avoid newline injection.


0.5.3 (2014-12-09)
==================

- Bugfix release. Fixed #27 and #30


0.5.2 (2014-11-16)
==================

- Basic irc3d server

- Modules reorganisation

- Add S3 logger


0.5.1 (2014-07-21)
==================

- Fixed #13: venusian 1.0 compat

- Add antiflood option for the command plugin

- commands accept unicode


0.5.0 (2014-06-01)
==================

- Added ``bot.kick()`` and ``bot.mode()``

- Rewrite ctcp plugin so we can ignore flood requests

- Trigger ``{plugin}.server_ready()`` at the end of MOTD

- Fixed #9: The ``command`` plugin uses ``cmd``, not ``cmdchar``.

- Fixed #10. Store server config. Use STATUSMSG config if any in ``userlist``

- ``userlist`` plugin now also store user modes per channel.

- Rename ``add_event`` to ``attach_events`` and added ``detach_events``. This
  allow to add/remove events on the fly.

- The autojoin plugin now detach motd related events after triggering one of
  them.

- Fix compatibility with trollius 0.3


0.4.10 (2014-05-21)
===================

- Fixed #5: autojoin on no motd

- allow to show date/times in console log


0.4.9 (2014-05-08)
==================

- Allow to trigger event on output with ``event(iotype='out')``

- Add a channel logger plugin

- autojoins is now a separate plugin

- userlist plugin take care of kicks

- social plugin is now officially supported and tested


0.4.7 (2014-04-03)
==================

- IrcString use unicode with py2


0.4.6 (2014-03-11)
==================

- Bug fix. The cron need a loop sooner as possible.


0.4.5 (2014-02-25)
==================

- Bug fix. An event was run twice if more than one where using the same regexp


0.4.4 (2014-02-15)
==================

- Add cron plugin

- Improve the command plugin. Fix some security issue.

- Add ``--help-page`` option to generate commands help pages


0.4.3 (2014-01-10)
==================

- Fix a bug on connection_lost.

- Send realname in USER command instead of nickname


0.4.2 (2014-01-09)
==================

- python2.7 support.

- add some plugins (ctcp, uptime, feeds, search)

- add some examples/ (twitter, asterisk)

- improve some internals

0.4.1 (2013-12-30)
==================

- Depends on venusian 1.0a8


0.1 (2013-11-30)
================

- Initial release


================================================
FILE: CONTRIBUTING.rst
================================================
Contribute
==========

First, if you want to add a cool plugin, consider submit a pull request to the
`irc3_plugins <https://github.com/gawel/irc3_plugins>`_ instead of irc3 itself.


Feel free to clone the project on `GitHub <https://github.com/gawel/irc3>`_.

To test your change you can run irc3 in debug mode using::

    $ irc3 --debug path-to-your-conf.ini

Once you made a change, try to add a test for your feature/fix. At least assume
that you have'nt broke anything by running tox::

    $ tox
    ...
    py27: commands succeeded
    py32: commands succeeded
    py33: commands succeeded
    py34: commands succeeded
    flake8: commands succeeded
    docs: commands succeeded
    congratulations :)

 You can run tests for a specific version::

    $ tox -e py34

The `irc3.rfc` module is auto generated from `irc3/rfc1459.txt`. If you want to
hack this file, you need to hack the parser in `irc3/_parse_rfc.py` (warning,
it's ugly)

You can regenerate the module and docs by running::

    $ tox -e build

You can also build the docs with::

    $ tox -e docs

And check the result::

    $ firefox .tox/docs/tmp/html/index.html

The project uses ``setuptools``, you can test-install it using `pip`:

    $ pip install .
    $ irc3 -h


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2016 Gael Pasgrimaud

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: MANIFEST.in
================================================
graft docs
prune docs/_build
prune .github/
graft examples
graft irc3
graft irc3d
graft tests
include Makefile *.rst *.cfg *.ini *.txt
global-exclude *.pyc *.swp
global-exclude __pycache__
include conftest.py
exclude .installed.cfg
exclude .coveragerc
exclude update.sh
exclude Dockerfile
exclude docker
exclude docker/Dockerfile
exclude docker/Makefile
include LICENSE


================================================
FILE: Makefile
================================================
APP:=$(shell basename `pwd`)
HOSTNAME:=$(shell hostname)
HOST:=amandine
PYTHON?=$(HOME)/.venvs/py3/bin/python3

build:
	docker build -t gawel/irc3 .

venv:
	 $(PYTHON) -m venv venv
	./venv/bin/pip install -e .[test,web]

run: venv
	./venv/bin/irc3 config.ini

upgrade: venv
ifeq ($(HOSTNAME), $(HOST))
	git pull origin master
	~/apps/bin/circusctl restart $(APP)
else
	git push origin master
	ssh $(HOST) "cd ~/apps/$(APP) && make upgrade"
endif




================================================
FILE: README.rst
================================================
============================================================
irc3. pluggable irc client library based on python's asyncio
============================================================

.. image:: https://github.com/gawel/irc3/actions/workflows/tox.yml/badge.svg
  :target: https://github.com/gawel/irc3/actions/workflows/tox.yml
.. image:: https://coveralls.io/repos/gawel/irc3/badge.png?branch=master
  :target: https://coveralls.io/r/gawel/irc3?branch=master

A pluggable irc client library based on python's `asyncio
<http://docs.python.org/dev/library/asyncio.html>`_.


.. image:: https://raw.githubusercontent.com/gawel/irc3/master/docs/_static/logo.png
   :width: 100
   :height: 100
   :align: center
   :alt: Ceative Commons – Attribution (CC BY 3.0) - Hydra designed by Huu Nguyen from the Noun Project - http://thenounproject.com/term/hydra/46963/
   :target: http://thenounproject.com/term/hydra/46963/


Requires python 3.11+

Python 2 is no longer supported, but if you don't have a choice you can use
an older version::

    $ pip install "irc3<0.9"

Source: https://github.com/gawel/irc3/

Docs: https://irc3.readthedocs.io/

Irc: irc://irc.freenode.net/irc3 (`www
<https://kiwiirc.com/client/irc.freenode.net/?nick=irc3|?&theme=basic#irc3>`_)


I've spent hours writing this software, with love.
Please consider tipping if you like it:

BTC: 1PruQAwByDndFZ7vTeJhyWefAghaZx9RZg

ETH: 0xb6418036d8E06c60C4D91c17d72Df6e1e5b15CE6

LTC: LY6CdZcDbxnBX9GFBJ45TqVj8NykBBqsmT


================================================
FILE: conftest.py
================================================
# -*- coding: utf-8 -*-
from irc3 import testing
import pytest
import sys
import os

try:
    from redis.exceptions import ConnectionError
    from redis.client import StrictRedis
    StrictRedis().flushdb()
except (ImportError, ConnectionError):
    import re
    req_redis = re.compile(r".*#[^#]*\s*require?\s*redis\s*$", re.IGNORECASE)

    def pytest_runtest_setup(item):
        if getattr(item, 'dtest', None):
            if any(req_redis.match(e.source) for e in item.dtest.examples):
                pytest.skip("No redis server is running")

dirname = os.path.dirname(__file__)
sys.path.append(os.path.join(dirname, 'examples'))


@pytest.fixture(scope="function")
def cls_event_loop(request, event_loop):
    request.cls.loop = event_loop
    request.cls.config['loop'] = event_loop
    yield
    request.cls.config.pop('loop')


@pytest.fixture(scope="function")
def irc3_bot_factory(request, event_loop):
    def _bot(**config):
        config['loop'] = event_loop
        _b['b'] = testing.IrcBot(**config)
        return _b['b']
    _b = {}
    yield _bot
    _b['b'].SIGINT()


================================================
FILE: docker/Dockerfile
================================================
FROM python:3.7

RUN adduser --disabled-password --gecos '' irc3

RUN echo build \
    && cd /usr/src && git clone https://github.com/gawel/irc3.git \
    && cd /usr/src/irc3 && pip install ipython && pip install -e .[test] \
    && mkdir -p /usr/src/bot && chown -R irc3:irc3 /usr/src/bot

WORKDIR /usr/src/bot

ONBUILD COPY . /usr/src/bot

USER irc3

CMD ["/usr/local/bin/irc3", "config.ini"]


================================================
FILE: docker/Makefile
================================================
build:
	docker build --rm=true -f Dockerfile -t irc3:latest .

run:
	docker run -v $(PWD)/../:/usr/src/bot -v $(HOME)/.irc3:/home/irc3/.irc3 irc3:latest irc3 examples/dev.ini


================================================
FILE: docs/Makefile
================================================
# Makefile for Sphinx documentation
#

# You can set these variables from the command line.
SPHINXOPTS    =
SPHINXBUILD   = ../bin/sphinx-build
PAPER         =
BUILDDIR      = _build

# Internal variables.
PAPEROPT_a4     = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .

.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext

help:
	@echo "Please use \`make <target>' where <target> is one of"
	@echo "  html       to make standalone HTML files"
	@echo "  dirhtml    to make HTML files named index.html in directories"
	@echo "  singlehtml to make a single large HTML file"
	@echo "  pickle     to make pickle files"
	@echo "  json       to make JSON files"
	@echo "  htmlhelp   to make HTML files and a HTML help project"
	@echo "  qthelp     to make HTML files and a qthelp project"
	@echo "  devhelp    to make HTML files and a Devhelp project"
	@echo "  epub       to make an epub"
	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
	@echo "  text       to make text files"
	@echo "  man        to make manual pages"
	@echo "  texinfo    to make Texinfo files"
	@echo "  info       to make Texinfo files and run them through makeinfo"
	@echo "  gettext    to make PO message catalogs"
	@echo "  changes    to make an overview of all changed/added/deprecated items"
	@echo "  linkcheck  to check all external links for integrity"
	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"

clean:
	-rm -rf $(BUILDDIR)/*

html:
	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
	@echo
	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."

dirhtml:
	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
	@echo
	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."

singlehtml:
	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
	@echo
	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."

pickle:
	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
	@echo
	@echo "Build finished; now you can process the pickle files."

json:
	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
	@echo
	@echo "Build finished; now you can process the JSON files."

htmlhelp:
	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
	@echo
	@echo "Build finished; now you can run HTML Help Workshop with the" \
	      ".hhp project file in $(BUILDDIR)/htmlhelp."

qthelp:
	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
	@echo
	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/irc3.qhcp"
	@echo "To view the help file:"
	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/irc3.qhc"

devhelp:
	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
	@echo
	@echo "Build finished."
	@echo "To view the help file:"
	@echo "# mkdir -p $$HOME/.local/share/devhelp/irc3"
	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/irc3"
	@echo "# devhelp"

epub:
	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
	@echo
	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."

latex:
	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
	@echo
	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
	@echo "Run \`make' in that directory to run these through (pdf)latex" \
	      "(use \`make latexpdf' here to do that automatically)."

latexpdf:
	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
	@echo "Running LaTeX files through pdflatex..."
	$(MAKE) -C $(BUILDDIR)/latex all-pdf
	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."

text:
	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
	@echo
	@echo "Build finished. The text files are in $(BUILDDIR)/text."

man:
	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
	@echo
	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."

texinfo:
	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
	@echo
	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
	@echo "Run \`make' in that directory to run these through makeinfo" \
	      "(use \`make info' here to do that automatically)."

info:
	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
	@echo "Running Texinfo files through makeinfo..."
	make -C $(BUILDDIR)/texinfo info
	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."

gettext:
	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
	@echo
	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."

changes:
	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
	@echo
	@echo "The overview file is in $(BUILDDIR)/changes."

linkcheck:
	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
	@echo
	@echo "Link check complete; look for any errors in the above output " \
	      "or in $(BUILDDIR)/linkcheck/output.txt."

doctest:
	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
	@echo "Testing of doctests in the sources finished, look at the " \
	      "results in $(BUILDDIR)/doctest/output.txt."


================================================
FILE: docs/conf.py
================================================
# -*- coding: utf-8 -*-
#
# irc3 documentation build configuration file, created by
# sphinx-quickstart on Mon Nov 25 01:03:01 2013.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys, os

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))

# -- General configuration -----------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'

# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# The suffix of source filenames.
source_suffix = '.rst'

# The encoding of source files.
#source_encoding = 'utf-8-sig'

# The master toctree document.
master_doc = 'index'

# General information about the project.
project = 'irc3'
copyright = '2013, Gael Pasgrimaud'

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = ''
# The full version, including alpha/beta/rc tags.
release = ''

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None

# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']

# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None

# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True

# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True

# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'

# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []


# -- Options for HTML output ---------------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
html_theme = 'nature'

# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}

# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []

# The name for this set of Sphinx documents.  If None, it defaults to
# "<project> v<release> documentation".
#html_title = None

# A shorter title for the navigation bar.  Default is the same as html_title.
#html_short_title = None

# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None

# The name of an image file (within the static path) to use as favicon of the
# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'

# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True

# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}

# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}

# If false, no module index is generated.
#html_domain_indices = True

# If false, no index is generated.
#html_use_index = True

# If true, the index is split into individual pages for each letter.
#html_split_index = False

# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True

# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True

# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True

# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it.  The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''

# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None

# Output file base name for HTML help builder.
htmlhelp_basename = 'irc3doc'


# -- Options for LaTeX output --------------------------------------------------

latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',

# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',

# Additional stuff for the LaTeX preamble.
#'preamble': '',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
  ('index', 'irc3.tex', 'irc3 Documentation',
   'Gael Pasgrimaud', 'manual'),
]

# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None

# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False

# If true, show page references after internal links.
#latex_show_pagerefs = False

# If true, show URL addresses after external links.
#latex_show_urls = False

# Documents to append as an appendix to all manuals.
#latex_appendices = []

# If false, no module index is generated.
#latex_domain_indices = True


# -- Options for manual page output --------------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
    ('index', 'irc3', 'irc3 Documentation',
     ['Gael Pasgrimaud'], 1)
]

# If true, show URL addresses after external links.
#man_show_urls = False


# -- Options for Texinfo output ------------------------------------------------

# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
#  dir menu entry, description, category)
texinfo_documents = [
  ('index', 'irc3', 'irc3 Documentation',
   'Gael Pasgrimaud', 'irc3', 'One line description of project.',
   'Miscellaneous'),
]

# Documents to append as an appendix to all manuals.
#texinfo_appendices = []

# If false, no module index is generated.
#texinfo_domain_indices = True

# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'

from importlib.metadata import version
version = version("irc3")
release = version


================================================
FILE: docs/dcc.rst
================================================
========================
:mod:`irc3.dcc` DCC
========================

See :func:`~irc3.IrcBot.dcc_chat`, :func:`~irc3.IrcBot.dcc_get` and
:func:`~irc3.IrcBot.dcc_send`

Here is a simple plugin to send a generated file:

.. literalinclude:: ../examples/dcc_send.py

API
===

.. automodule:: irc3.dcc

.. autoclass:: DCCManager
  :members:

.. autoclass:: DCCChat
  :members:

.. autoclass:: DCCSend
  :members:

.. autoclass:: DCCGet
  :members:


================================================
FILE: docs/dec.rst
================================================
============================
:mod:`irc3.dec` decorators
============================

.. automodule:: irc3.dec

plugin
======

.. autofunction:: plugin

bot event
=========

.. autoclass:: event

bot extend
==========

.. autofunction:: extend


================================================
FILE: docs/hack.rst
================================================
.. include:: ../CONTRIBUTING.rst


================================================
FILE: docs/index.rst
================================================
.. include:: ../README.rst

Installation
==============

Using pip::

    $ pip install irc3

Quick start
===========

irc3 provides a basic template to help you to quickly test a bot.
Here is how to create a bot named ``mybot``.

Create a new directory and cd to it:

.. code-block:: sh

    $ mkdir mybot
    $ cd mybot

Then use the template:

.. code-block:: sh

    $ python -m irc3.template mybot

This will create an almost ready to use ``config.ini`` file and a simple
plugin named ``mybot_plugin.py`` that says «Hi» when the bot or someone else joins a
channel and includes an ``echo`` command.

Here is what the config file will looks like:

.. literalinclude:: ../examples/config.ini
   :language: ini

And here is the plugin:

.. literalinclude:: ../examples/mybot_plugin.py

Have a look at those file and edit the config file for your needs.
You may have to edit:

- the autojoin channel

- your irc mask in the ``irc3.plugins.command.mask`` section

Once you're done with editing, run:

.. code-block:: sh

    $ irc3 config.ini

Check the help of the ``irc3`` command.

.. code-block:: sh

    $ irc3 -h

If you're enjoying it, you can check for more detailed docs below. And some
more examples here: https://github.com/gawel/irc3/tree/master/examples

Documentation
=============

.. toctree::
   :maxdepth: 2
   :glob:

   dec
   utils
   rfc
   dcc
   reloadable
   plugins/*
   hack



Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`



================================================
FILE: docs/irc3.rst
================================================

============================
:mod:`irc3` Irc bot
============================

.. automodule:: irc3

IrcBot
======

.. autoclass:: IrcBot
   :members:
   :inherited-members:

    .. autoattribute:: defaults

IrcConnection
=============

.. autoclass:: IrcConnection
   :members:


================================================
FILE: docs/plugins/asynchronious.rst
================================================
.. automodule:: irc3.plugins.asynchronious



================================================
FILE: docs/plugins/autocommand.rst
================================================
.. automodule:: irc3.plugins.autocommand



================================================
FILE: docs/plugins/autojoins.rst
================================================
.. automodule:: irc3.plugins.autojoins



================================================
FILE: docs/plugins/casefold.rst
================================================
.. automodule:: irc3.plugins.casefold



================================================
FILE: docs/plugins/command.rst
================================================
.. automodule:: irc3.plugins.command



================================================
FILE: docs/plugins/core.rst
================================================
.. automodule:: irc3.plugins.core



================================================
FILE: docs/plugins/cron.rst
================================================
.. automodule:: irc3.plugins.cron



================================================
FILE: docs/plugins/ctcp.rst
================================================
.. automodule:: irc3.plugins.ctcp



================================================
FILE: docs/plugins/dcc.rst
================================================
.. automodule:: irc3.plugins.dcc



================================================
FILE: docs/plugins/feeds.rst
================================================
.. automodule:: irc3.plugins.feeds



================================================
FILE: docs/plugins/fifo.rst
================================================
.. automodule:: irc3.plugins.fifo



================================================
FILE: docs/plugins/human.rst
================================================
.. automodule:: irc3.plugins.human



================================================
FILE: docs/plugins/log.rst
================================================
.. automodule:: irc3.plugins.log



================================================
FILE: docs/plugins/logger.rst
================================================
.. automodule:: irc3.plugins.logger



================================================
FILE: docs/plugins/pager.rst
================================================
.. automodule:: irc3.plugins.pager



================================================
FILE: docs/plugins/quakenet.rst
================================================
.. automodule:: irc3.plugins.quakenet



================================================
FILE: docs/plugins/sasl.rst
================================================
.. automodule:: irc3.plugins.sasl



================================================
FILE: docs/plugins/search.rst
================================================
.. automodule:: irc3.plugins.search



================================================
FILE: docs/plugins/shell_command.rst
================================================
.. automodule:: irc3.plugins.shell_command



================================================
FILE: docs/plugins/slack.rst
================================================
.. automodule:: irc3.plugins.slack



================================================
FILE: docs/plugins/social.rst
================================================
.. automodule:: irc3.plugins.social



================================================
FILE: docs/plugins/storage.rst
================================================
.. automodule:: irc3.plugins.storage



================================================
FILE: docs/plugins/uptime.rst
================================================
.. automodule:: irc3.plugins.uptime



================================================
FILE: docs/plugins/userlist.rst
================================================
.. automodule:: irc3.plugins.userlist



================================================
FILE: docs/plugins/web.rst
================================================
.. automodule:: irc3.plugins.web



================================================
FILE: docs/reloadable.rst
================================================
Reloadable plugins
==================

.. note:: if you just want the bot to restart when you change a file during
    development you can use `hupper <https://pypi.python.org/pypi/huppe>`_::

    $ pip install hupper
    $ hupper -m irc3 config.ini

irc3 provides a way to reload plugins without restarting the bot.

To do that, your plugin should provide a ``reload`` class method::

    class Plugin(object):

        def __init__(self, bot):
            self.bot = bot

        @classmethod
        def reload(cls, old):
            """this method should return a ready to use plugin instance.
            cls is the newly reloaded class. old is the old instance.
            """
            return cls(old.bot)

Plugins can also implement a few hooks to help take care of reloads::

    class Plugin(object):

        def __init__(self, bot):
            self.bot = bot

        def before_reload(self):
            """Do stuff before reload"""

        def after_reload(self):
            """Do stuff after reload"""

..
    >>> from irc3.testing import IrcBot
    >>> bot = IrcBot(includes=['mycommands'])

To reload a plugin, just call the :func:`~irc3.IrcBot.reload` method with
module name(s) to reload::

    >>> bot.reload('mycommands')


================================================
FILE: docs/rfc.rst
================================================
========================
:mod:`irc3.rfc` RFC1459
========================

Replies (REPL)
==============

259 - RPL_ADMINEMAIL
--------------------

Format ``:{srv} 259 {nick} :{admin_info}``

Match ``^:(?P<srv>\S+) 259 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_ADMINEMAIL)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

257 - RPL_ADMINLOC1
-------------------

Format ``:{srv} 257 {nick} :{admin_info}``

Match ``^:(?P<srv>\S+) 257 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_ADMINLOC1)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

258 - RPL_ADMINLOC2
-------------------

Format ``:{srv} 258 {nick} :{admin_info}``

Match ``^:(?P<srv>\S+) 258 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_ADMINLOC2)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

256 - RPL_ADMINME
-----------------

Format ``:{srv} 256 {nick} {server} :Administrative info``

Match ``^:(?P<srv>\S+) 256 (?P<me>\S+) (?P<server>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_ADMINME)
    def myevent(bot, srv=None, me=None, server=None, data=None):
        # do something

301 - RPL_AWAY
--------------

Format ``:{srv} 301 {nick} {nick} :{away_message}``

Match ``^:(?P<srv>\S+) 301 (?P<me>\S+) (?P<nick>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_AWAY)
    def myevent(bot, srv=None, me=None, nick=None, data=None):
        # do something

367 - RPL_BANLIST
-----------------

Format ``:{srv} 367 {nick} {channel} {banid}``

Match ``^:(?P<srv>\S+) 367 (?P<me>\S+) (?P<channel>\S+) (?P<banid>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_BANLIST)
    def myevent(bot, srv=None, me=None, channel=None, banid=None):
        # do something

324 - RPL_CHANNELMODEIS
-----------------------

Format ``:{srv} 324 {nick} {channel} {mode} {mode_params}``

Match ``^:(?P<srv>\S+) 324 (?P<me>\S+) (?P<channel>\S+) (?P<mode>\S+) (?P<mode_params>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_CHANNELMODEIS)
    def myevent(bot, srv=None, me=None, channel=None, mode=None, mode_params=None):
        # do something

368 - RPL_ENDOFBANLIST
----------------------

Format ``:{srv} 368 {nick} {channel} :End of channel ban list``

Match ``^:(?P<srv>\S+) 368 (?P<me>\S+) (?P<channel>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_ENDOFBANLIST)
    def myevent(bot, srv=None, me=None, channel=None, data=None):
        # do something

374 - RPL_ENDOFINFO
-------------------

Format ``:{srv} 374 {nick} :End of /INFO list``

Match ``^:(?P<srv>\S+) 374 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_ENDOFINFO)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

365 - RPL_ENDOFLINKS
--------------------

Format ``:{srv} 365 {nick} {mask} :End of /LINKS list``

Match ``^:(?P<srv>\S+) 365 (?P<me>\S+) (?P<mask>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_ENDOFLINKS)
    def myevent(bot, srv=None, me=None, mask=None, data=None):
        # do something

376 - RPL_ENDOFMOTD
-------------------

Format ``:{srv} 376 {nick} :End of /MOTD command``

Match ``^:(?P<srv>\S+) 376 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_ENDOFMOTD)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

366 - RPL_ENDOFNAMES
--------------------

Format ``:{srv} 366 {nick} {channel} :End of /NAMES list``

Match ``^:(?P<srv>\S+) 366 (?P<me>\S+) (?P<channel>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_ENDOFNAMES)
    def myevent(bot, srv=None, me=None, channel=None, data=None):
        # do something

219 - RPL_ENDOFSTATS
--------------------

Format ``:{srv} 219 {nick} {stats_letter} :End of /STATS report``

Match ``^:(?P<srv>\S+) 219 (?P<me>\S+) (?P<stats_letter>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_ENDOFSTATS)
    def myevent(bot, srv=None, me=None, stats_letter=None, data=None):
        # do something

394 - RPL_ENDOFUSERS
--------------------

Format ``:{srv} 394 {nick} :End of users``

Match ``^:(?P<srv>\S+) 394 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_ENDOFUSERS)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

315 - RPL_ENDOFWHO
------------------

Format ``:{srv} 315 {nick} {nick} :End of /WHO list``

Match ``^:(?P<srv>\S+) 315 (?P<me>\S+) (?P<nick>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_ENDOFWHO)
    def myevent(bot, srv=None, me=None, nick=None, data=None):
        # do something

318 - RPL_ENDOFWHOIS
--------------------

Format ``:{srv} 318 {nick} {nick} :End of /WHOIS list``

Match ``^:(?P<srv>\S+) 318 (?P<me>\S+) (?P<nick>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_ENDOFWHOIS)
    def myevent(bot, srv=None, me=None, nick=None, data=None):
        # do something

369 - RPL_ENDOFWHOWAS
---------------------

Format ``:{srv} 369 {nick} {nick} :End of WHOWAS``

Match ``^:(?P<srv>\S+) 369 (?P<me>\S+) (?P<nick>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_ENDOFWHOWAS)
    def myevent(bot, srv=None, me=None, nick=None, data=None):
        # do something

371 - RPL_INFO
--------------

Format ``:{srv} 371 {nick} :{string}``

Match ``^:(?P<srv>\S+) 371 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_INFO)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

341 - RPL_INVITING
------------------

Format ``:{srv} 341 {nick} {channel} {nick}``

Match ``^:(?P<srv>\S+) 341 (?P<me>\S+) (?P<channel>\S+) (?P<nick>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_INVITING)
    def myevent(bot, srv=None, me=None, channel=None, nick=None):
        # do something

303 - RPL_ISON
--------------

Format ``:{srv} 303 {nick} :{nicknames}``

Match ``^:(?P<srv>\S+) 303 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_ISON)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

364 - RPL_LINKS
---------------

Format ``:{srv} 364 {nick} {mask} {server} :{hopcount} {server_info}``

Match ``^:(?P<srv>\S+) 364 (?P<me>\S+) (?P<mask>\S+) (?P<server>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_LINKS)
    def myevent(bot, srv=None, me=None, mask=None, server=None, data=None):
        # do something

322 - RPL_LIST
--------------

Format ``:{srv} 322 {nick} {channel} {visible} :{topic}``

Match ``^:(?P<srv>\S+) 322 (?P<me>\S+) (?P<channel>\S+) (?P<visible>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_LIST)
    def myevent(bot, srv=None, me=None, channel=None, visible=None, data=None):
        # do something

323 - RPL_LISTEND
-----------------

Format ``:{srv} 323 {nick} :End of /LIST``

Match ``^:(?P<srv>\S+) 323 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_LISTEND)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

321 - RPL_LISTSTART
-------------------

Format ``:{srv} 321 {nick} Channel :Users  Name``

Match ``^:(?P<srv>\S+) 321 (?P<me>\S+) Channel :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_LISTSTART)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

254 - RPL_LUSERCHANNELS
-----------------------

Format ``:{srv} 254 {nick} {x} :channels formed``

Match ``^:(?P<srv>\S+) 254 (?P<me>\S+) (?P<x>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_LUSERCHANNELS)
    def myevent(bot, srv=None, me=None, x=None, data=None):
        # do something

251 - RPL_LUSERCLIENT
---------------------

Format ``:{srv} 251 {nick} :There are {x} users and {y} invisible on {z} servers``

Match ``^:(?P<srv>\S+) 251 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_LUSERCLIENT)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

255 - RPL_LUSERME
-----------------

Format ``:{srv} 255 {nick} :I have {x} clients and {y}``

Match ``^:(?P<srv>\S+) 255 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_LUSERME)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

252 - RPL_LUSEROP
-----------------

Format ``:{srv} 252 {nick} {x} :operator(s) online``

Match ``^:(?P<srv>\S+) 252 (?P<me>\S+) (?P<x>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_LUSEROP)
    def myevent(bot, srv=None, me=None, x=None, data=None):
        # do something

253 - RPL_LUSERUNKNOWN
----------------------

Format ``:{srv} 253 {nick} {x} :unknown connection(s)``

Match ``^:(?P<srv>\S+) 253 (?P<me>\S+) (?P<x>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_LUSERUNKNOWN)
    def myevent(bot, srv=None, me=None, x=None, data=None):
        # do something

372 - RPL_MOTD
--------------

Format ``:{srv} 372 {nick} :- {text}``

Match ``^:(?P<srv>\S+) 372 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_MOTD)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

375 - RPL_MOTDSTART
-------------------

Format ``:{srv} 375 {nick} :- {server} Message of the day -``

Match ``^:(?P<srv>\S+) 375 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_MOTDSTART)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

353 - RPL_NAMREPLY
------------------

Format ``:{srv} 353 {nick} {m} {channel} :{nicknames}``

Match ``^:(?P<srv>\S+) 353 (?P<me>\S+) (?P<m>\S+) (?P<channel>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_NAMREPLY)
    def myevent(bot, srv=None, me=None, m=None, channel=None, data=None):
        # do something

331 - RPL_NOTOPIC
-----------------

Format ``:{srv} 331 {nick} {channel} :No topic is set``

Match ``^:(?P<srv>\S+) 331 (?P<me>\S+) (?P<channel>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_NOTOPIC)
    def myevent(bot, srv=None, me=None, channel=None, data=None):
        # do something

395 - RPL_NOUSERS
-----------------

Format ``:{srv} 395 {nick} :Nobody logged in``

Match ``^:(?P<srv>\S+) 395 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_NOUSERS)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

306 - RPL_NOWAWAY
-----------------

Format ``:{srv} 306 {nick} :You have been marked as being away``

Match ``^:(?P<srv>\S+) 306 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_NOWAWAY)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

382 - RPL_REHASHING
-------------------

Format ``:{srv} 382 {nick} {config_file} :Rehashing``

Match ``^:(?P<srv>\S+) 382 (?P<me>\S+) (?P<config_file>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_REHASHING)
    def myevent(bot, srv=None, me=None, config_file=None, data=None):
        # do something

213 - RPL_STATSCLINE
--------------------

Format ``:{srv} 213 {nick} C {host} * {nick} {port} {class}``

Match ``^:(?P<srv>\S+) 213 (?P<me>\S+) C (?P<host>\S+) . (?P<nick>\S+) (?P<port>\S+) (?P<class>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_STATSCLINE)
    def myevent(bot, srv=None, me=None, host=None, nick=None, port=None, class=None):
        # do something

212 - RPL_STATSCOMMANDS
-----------------------

Format ``:{srv} 212 {nick} {cmd} {count}``

Match ``^:(?P<srv>\S+) 212 (?P<me>\S+) (?P<cmd>\S+) (?P<count>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_STATSCOMMANDS)
    def myevent(bot, srv=None, me=None, cmd=None, count=None):
        # do something

244 - RPL_STATSHLINE
--------------------

Format ``:{srv} 244 {nick} H {hostmask} * {servername}``

Match ``^:(?P<srv>\S+) 244 (?P<me>\S+) H (?P<hostmask>\S+) . (?P<servername>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_STATSHLINE)
    def myevent(bot, srv=None, me=None, hostmask=None, servername=None):
        # do something

215 - RPL_STATSILINE
--------------------

Format ``:{srv} 215 {nick} I {host} * {host1} {port} {class}``

Match ``^:(?P<srv>\S+) 215 (?P<me>\S+) I (?P<host>\S+) . (?P<host1>\S+) (?P<port>\S+) (?P<class>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_STATSILINE)
    def myevent(bot, srv=None, me=None, host=None, host1=None, port=None, class=None):
        # do something

216 - RPL_STATSKLINE
--------------------

Format ``:{srv} 216 {nick} K {host} * {username} {port} {class}``

Match ``^:(?P<srv>\S+) 216 (?P<me>\S+) K (?P<host>\S+) . (?P<username>\S+) (?P<port>\S+) (?P<class>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_STATSKLINE)
    def myevent(bot, srv=None, me=None, host=None, username=None, port=None, class=None):
        # do something

211 - RPL_STATSLINKINFO
-----------------------

Format ``:{srv} 211 {nick} :{linkname} {sendq} {sent_messages} {received_bytes} {time_open}``

Match ``^:(?P<srv>\S+) 211 (?P<me>\S+) (?P<linkname>\S+) (?P<sendq>\S+) (?P<sent_messages>\S+) (?P<received_bytes>\S+) (?P<time_open>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_STATSLINKINFO)
    def myevent(bot, srv=None, me=None, linkname=None, sendq=None, sent_messages=None, received_bytes=None, time_open=None):
        # do something

241 - RPL_STATSLLINE
--------------------

Format ``:{srv} 241 {nick} L {hostmask} * {servername} {maxdepth}``

Match ``^:(?P<srv>\S+) 241 (?P<me>\S+) L (?P<hostmask>\S+) . (?P<servername>\S+) (?P<maxdepth>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_STATSLLINE)
    def myevent(bot, srv=None, me=None, hostmask=None, servername=None, maxdepth=None):
        # do something

214 - RPL_STATSNLINE
--------------------

Format ``:{srv} 214 {nick} N {host} * {nick} {port} {class}``

Match ``^:(?P<srv>\S+) 214 (?P<me>\S+) N (?P<host>\S+) . (?P<nick>\S+) (?P<port>\S+) (?P<class>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_STATSNLINE)
    def myevent(bot, srv=None, me=None, host=None, nick=None, port=None, class=None):
        # do something

243 - RPL_STATSOLINE
--------------------

Format ``:{srv} 243 {nick} O {hostmask} * {nick}``

Match ``^:(?P<srv>\S+) 243 (?P<me>\S+) O (?P<hostmask>\S+) . (?P<nick>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_STATSOLINE)
    def myevent(bot, srv=None, me=None, hostmask=None, nick=None):
        # do something

242 - RPL_STATSUPTIME
---------------------

Format ``:{srv} 242 {nick} :Server Up{days}days {hours}``

Match ``^:(?P<srv>\S+) 242 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_STATSUPTIME)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

218 - RPL_STATSYLINE
--------------------

Format ``:{srv} 218 {nick} frequency> {max_sendq}``

Match ``^:(?P<srv>\S+) 218 (?P<me>\S+) frequency> (?P<max_sendq>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_STATSYLINE)
    def myevent(bot, srv=None, me=None, max_sendq=None):
        # do something

342 - RPL_SUMMONING
-------------------

Format ``:{srv} 342 {nick} {nick} :Summoning user to IRC``

Match ``^:(?P<srv>\S+) 342 (?P<me>\S+) (?P<nick>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_SUMMONING)
    def myevent(bot, srv=None, me=None, nick=None, data=None):
        # do something

391 - RPL_TIME
--------------

Format ``:{srv} 391 {nick} {server} :{string_showing_server's_local_time}``

Match ``^:(?P<srv>\S+) 391 (?P<me>\S+) (?P<server>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_TIME)
    def myevent(bot, srv=None, me=None, server=None, data=None):
        # do something

332 - RPL_TOPIC
---------------

Format ``:{srv} 332 {nick} {channel} :{topic}``

Match ``^:(?P<srv>\S+) 332 (?P<me>\S+) (?P<channel>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_TOPIC)
    def myevent(bot, srv=None, me=None, channel=None, data=None):
        # do something

201 - RPL_TRACECONNECTING
-------------------------

Format ``:{srv} 201 {nick} Try. {class} {server}``

Match ``^:(?P<srv>\S+) 201 (?P<me>\S+) Try. (?P<class>\S+) (?P<server>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_TRACECONNECTING)
    def myevent(bot, srv=None, me=None, class=None, server=None):
        # do something

202 - RPL_TRACEHANDSHAKE
------------------------

Format ``:{srv} 202 {nick} H.S. {class} {server}``

Match ``^:(?P<srv>\S+) 202 (?P<me>\S+) H.S. (?P<class>\S+) (?P<server>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_TRACEHANDSHAKE)
    def myevent(bot, srv=None, me=None, class=None, server=None):
        # do something

200 - RPL_TRACELINK
-------------------

Format ``:{srv} 200 {nick} {next_server}``

Match ``^:(?P<srv>\S+) 200 (?P<me>\S+) (?P<next_server>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_TRACELINK)
    def myevent(bot, srv=None, me=None, next_server=None):
        # do something

261 - RPL_TRACELOG
------------------

Format ``:{srv} 261 {nick} File {logfile} {debug_level}``

Match ``^:(?P<srv>\S+) 261 (?P<me>\S+) File (?P<logfile>\S+) (?P<debug_level>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_TRACELOG)
    def myevent(bot, srv=None, me=None, logfile=None, debug_level=None):
        # do something

208 - RPL_TRACENEWTYPE
----------------------

Format ``:{srv} 208 {nick} {newtype} 0 {client}``

Match ``^:(?P<srv>\S+) 208 (?P<me>\S+) (?P<newtype>\S+) 0 (?P<client>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_TRACENEWTYPE)
    def myevent(bot, srv=None, me=None, newtype=None, client=None):
        # do something

204 - RPL_TRACEOPERATOR
-----------------------

Format ``:{srv} 204 {nick} Oper {class} {nick}``

Match ``^:(?P<srv>\S+) 204 (?P<me>\S+) Oper (?P<class>\S+) (?P<nick>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_TRACEOPERATOR)
    def myevent(bot, srv=None, me=None, class=None, nick=None):
        # do something

206 - RPL_TRACESERVER
---------------------

Format ``:{srv} 206 {nick} {mask}``

Match ``^:(?P<srv>\S+) 206 (?P<me>\S+) (?P<mask>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_TRACESERVER)
    def myevent(bot, srv=None, me=None, mask=None):
        # do something

203 - RPL_TRACEUNKNOWN
----------------------

Format ``:{srv} 203 {nick} ???? {class} [{clientip}]``

Match ``^:(?P<srv>\S+) 203 (?P<me>\S+) \S+ (?P<class>\S+) [(?P<clientip>\S+)]``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_TRACEUNKNOWN)
    def myevent(bot, srv=None, me=None, class=None, clientip=None):
        # do something

205 - RPL_TRACEUSER
-------------------

Format ``:{srv} 205 {nick} User {class} {nick}``

Match ``^:(?P<srv>\S+) 205 (?P<me>\S+) User (?P<class>\S+) (?P<nick>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_TRACEUSER)
    def myevent(bot, srv=None, me=None, class=None, nick=None):
        # do something

221 - RPL_UMODEIS
-----------------

Format ``:{srv} 221 {nick} {user_mode_string}``

Match ``^:(?P<srv>\S+) 221 (?P<me>\S+) (?P<user_mode_string>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_UMODEIS)
    def myevent(bot, srv=None, me=None, user_mode_string=None):
        # do something

305 - RPL_UNAWAY
----------------

Format ``:{srv} 305 {nick} :You are no longer marked as being away``

Match ``^:(?P<srv>\S+) 305 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_UNAWAY)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

302 - RPL_USERHOST
------------------

Format ``:{srv} 302 {nick} :[{reply}{{space}{reply}}]``

Match ``^:(?P<srv>\S+) 302 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_USERHOST)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

393 - RPL_USERS
---------------

Format ``:{srv} 393 {nick} {x} {y} {z}``

Match ``^:(?P<srv>\S+) 393 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_USERS)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

392 - RPL_USERSSTART
--------------------

Format ``:{srv} 392 {nick} :UserID   Terminal  Host``

Match ``^:(?P<srv>\S+) 392 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_USERSSTART)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

351 - RPL_VERSION
-----------------

Format ``:{srv} 351 {nick} {version}.{debuglevel} {server} :{comments}``

Match ``^:(?P<srv>\S+) 351 (?P<me>\S+) (?P<version>\S+).(?P<debuglevel>\S+) (?P<server>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_VERSION)
    def myevent(bot, srv=None, me=None, version=None, debuglevel=None, server=None, data=None):
        # do something

319 - RPL_WHOISCHANNELS
-----------------------

Format ``:{srv} 319 {nick} :{channels}``

Match ``^:(?P<srv>\S+) 319 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_WHOISCHANNELS)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

317 - RPL_WHOISIDLE
-------------------

Format ``:{srv} 317 {nick} {nick} {x} :seconds idle``

Match ``^:(?P<srv>\S+) 317 (?P<me>\S+) (?P<nick>\S+) (?P<x>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_WHOISIDLE)
    def myevent(bot, srv=None, me=None, nick=None, x=None, data=None):
        # do something

313 - RPL_WHOISOPERATOR
-----------------------

Format ``:{srv} 313 {nick} {nick} :is an IRC operator``

Match ``^:(?P<srv>\S+) 313 (?P<me>\S+) (?P<nick>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_WHOISOPERATOR)
    def myevent(bot, srv=None, me=None, nick=None, data=None):
        # do something

312 - RPL_WHOISSERVER
---------------------

Format ``:{srv} 312 {nick} {nick} {server} :{server_info}``

Match ``^:(?P<srv>\S+) 312 (?P<me>\S+) (?P<nick>\S+) (?P<server>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_WHOISSERVER)
    def myevent(bot, srv=None, me=None, nick=None, server=None, data=None):
        # do something

311 - RPL_WHOISUSER
-------------------

Format ``:{srv} 311 {nick} {nick} {username} {host} {m} :{realname}``

Match ``^:(?P<srv>\S+) 311 (?P<me>\S+) (?P<nick>\S+) (?P<username>\S+) (?P<host>\S+) (?P<m>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_WHOISUSER)
    def myevent(bot, srv=None, me=None, nick=None, username=None, host=None, m=None, data=None):
        # do something

352 - RPL_WHOREPLY
------------------

Format ``:{srv} 352 {nick} :{channel} {username} {host} {server} {nick} {modes} :{hopcount} {realname}``

Match ``^:(?P<srv>\S+) 352 (?P<me>\S+) (?P<channel>\S+) (?P<username>\S+) (?P<host>\S+) (?P<server>\S+) (?P<nick>\S+) (?P<modes>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_WHOREPLY)
    def myevent(bot, srv=None, me=None, channel=None, username=None, host=None, server=None, nick=None, modes=None, data=None):
        # do something

314 - RPL_WHOWASUSER
--------------------

Format ``:{srv} 314 {nick} {nick} {username} {host} * :{realname}``

Match ``^:(?P<srv>\S+) 314 (?P<me>\S+) (?P<nick>\S+) (?P<username>\S+) (?P<host>\S+) . :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_WHOWASUSER)
    def myevent(bot, srv=None, me=None, nick=None, username=None, host=None, data=None):
        # do something

381 - RPL_YOUREOPER
-------------------

Format ``:{srv} 381 {nick} :You are now an IRC operator``

Match ``^:(?P<srv>\S+) 381 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.RPL_YOUREOPER)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

Errors (ERR)
============

462 - ERR_ALREADYREGISTRED
--------------------------

Format ``:{srv} 462 {nick} :You may not reregister``

Match ``^:(?P<srv>\S+) 462 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_ALREADYREGISTRED)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

475 - ERR_BADCHANNELKEY
-----------------------

Format ``:{srv} 475 {nick} {channel} :Cannot join channel (+k)``

Match ``^:(?P<srv>\S+) 475 (?P<me>\S+) (?P<channel>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_BADCHANNELKEY)
    def myevent(bot, srv=None, me=None, channel=None, data=None):
        # do something

474 - ERR_BANNEDFROMCHAN
------------------------

Format ``:{srv} 474 {nick} {channel} :Cannot join channel (+b)``

Match ``^:(?P<srv>\S+) 474 (?P<me>\S+) (?P<channel>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_BANNEDFROMCHAN)
    def myevent(bot, srv=None, me=None, channel=None, data=None):
        # do something

404 - ERR_CANNOTSENDTOCHAN
--------------------------

Format ``:{srv} 404 {nick} {channel} :Cannot send to channel``

Match ``^:(?P<srv>\S+) 404 (?P<me>\S+) (?P<channel>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_CANNOTSENDTOCHAN)
    def myevent(bot, srv=None, me=None, channel=None, data=None):
        # do something

483 - ERR_CANTKILLSERVER
------------------------

Format ``:{srv} 483 {nick} :You cant kill a server!``

Match ``^:(?P<srv>\S+) 483 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_CANTKILLSERVER)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

471 - ERR_CHANNELISFULL
-----------------------

Format ``:{srv} 471 {nick} {channel} :Cannot join channel (+l)``

Match ``^:(?P<srv>\S+) 471 (?P<me>\S+) (?P<channel>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_CHANNELISFULL)
    def myevent(bot, srv=None, me=None, channel=None, data=None):
        # do something

482 - ERR_CHANOPRIVSNEEDED
--------------------------

Format ``:{srv} 482 {nick} {channel} :You're not channel operator``

Match ``^:(?P<srv>\S+) 482 (?P<me>\S+) (?P<channel>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_CHANOPRIVSNEEDED)
    def myevent(bot, srv=None, me=None, channel=None, data=None):
        # do something

432 - ERR_ERRONEUSNICKNAME
--------------------------

Format ``:{srv} 432 {nick} {nick} :Erroneus nickname``

Match ``^:(?P<srv>\S+) 432 (?P<me>\S+) (?P<nick>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_ERRONEUSNICKNAME)
    def myevent(bot, srv=None, me=None, nick=None, data=None):
        # do something

473 - ERR_INVITEONLYCHAN
------------------------

Format ``:{srv} 473 {nick} {channel} :Cannot join channel (+i)``

Match ``^:(?P<srv>\S+) 473 (?P<me>\S+) (?P<channel>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_INVITEONLYCHAN)
    def myevent(bot, srv=None, me=None, channel=None, data=None):
        # do something

467 - ERR_KEYSET
----------------

Format ``:{srv} 467 {nick} {channel} :Channel key already set``

Match ``^:(?P<srv>\S+) 467 (?P<me>\S+) (?P<channel>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_KEYSET)
    def myevent(bot, srv=None, me=None, channel=None, data=None):
        # do something

461 - ERR_NEEDMOREPARAMS
------------------------

Format ``:{srv} 461 {nick} {cmd} :Not enough parameters``

Match ``^:(?P<srv>\S+) 461 (?P<me>\S+) (?P<cmd>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_NEEDMOREPARAMS)
    def myevent(bot, srv=None, me=None, cmd=None, data=None):
        # do something

ERR_NICK
--------

Match ``^(@(?P<tags>\S+) )?:(?P<srv>\S+) (?P<retcode>(432|433|436)) (?P<me>\S+) (?P<nick>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_NICK)
    def myevent(bot, srv=None, retcode=None, me=None, nick=None, data=None, tags=None):
        # do something

436 - ERR_NICKCOLLISION
-----------------------

Format ``:{srv} 436 {nick} {nick} :Nickname collision KILL``

Match ``^:(?P<srv>\S+) 436 (?P<me>\S+) (?P<nick>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_NICKCOLLISION)
    def myevent(bot, srv=None, me=None, nick=None, data=None):
        # do something

433 - ERR_NICKNAMEINUSE
-----------------------

Format ``:{srv} 433 {nick} {nick} :Nickname is already in use``

Match ``^:(?P<srv>\S+) 433 (?P<me>\S+) (?P<nick>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_NICKNAMEINUSE)
    def myevent(bot, srv=None, me=None, nick=None, data=None):
        # do something

423 - ERR_NOADMININFO
---------------------

Format ``:{srv} 423 {nick} {server} :No administrative info available``

Match ``^:(?P<srv>\S+) 423 (?P<me>\S+) (?P<server>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_NOADMININFO)
    def myevent(bot, srv=None, me=None, server=None, data=None):
        # do something

444 - ERR_NOLOGIN
-----------------

Format ``:{srv} 444 {nick} {nick} :User not logged in``

Match ``^:(?P<srv>\S+) 444 (?P<me>\S+) (?P<nick>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_NOLOGIN)
    def myevent(bot, srv=None, me=None, nick=None, data=None):
        # do something

422 - ERR_NOMOTD
----------------

Format ``:{srv} 422 {nick} :MOTD File is missing``

Match ``^:(?P<srv>\S+) 422 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_NOMOTD)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

431 - ERR_NONICKNAMEGIVEN
-------------------------

Format ``:{srv} 431 {nick} :No nickname given``

Match ``^:(?P<srv>\S+) 431 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_NONICKNAMEGIVEN)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

491 - ERR_NOOPERHOST
--------------------

Format ``:{srv} 491 {nick} :No O-lines for your host``

Match ``^:(?P<srv>\S+) 491 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_NOOPERHOST)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

409 - ERR_NOORIGIN
------------------

Format ``:{srv} 409 {nick} :No origin specified``

Match ``^:(?P<srv>\S+) 409 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_NOORIGIN)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

463 - ERR_NOPERMFORHOST
-----------------------

Format ``:{srv} 463 {nick} :Your host isn't among the privileged``

Match ``^:(?P<srv>\S+) 463 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_NOPERMFORHOST)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

481 - ERR_NOPRIVILEGES
----------------------

Format ``:{srv} 481 {nick} :Permission Denied- You're not an IRC operator``

Match ``^:(?P<srv>\S+) 481 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_NOPRIVILEGES)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

411 - ERR_NORECIPIENT
---------------------

Format ``:{srv} 411 {nick} :No recipient given ({cmd})``

Match ``^:(?P<srv>\S+) 411 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_NORECIPIENT)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

403 - ERR_NOSUCHCHANNEL
-----------------------

Format ``:{srv} 403 {nick} {channel} :No such channel``

Match ``^:(?P<srv>\S+) 403 (?P<me>\S+) (?P<channel>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_NOSUCHCHANNEL)
    def myevent(bot, srv=None, me=None, channel=None, data=None):
        # do something

401 - ERR_NOSUCHNICK
--------------------

Format ``:{srv} 401 {nick} {nick} :No such nick/channel``

Match ``^:(?P<srv>\S+) 401 (?P<me>\S+) (?P<nick>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_NOSUCHNICK)
    def myevent(bot, srv=None, me=None, nick=None, data=None):
        # do something

402 - ERR_NOSUCHSERVER
----------------------

Format ``:{srv} 402 {nick} {server} :No such server``

Match ``^:(?P<srv>\S+) 402 (?P<me>\S+) (?P<server>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_NOSUCHSERVER)
    def myevent(bot, srv=None, me=None, server=None, data=None):
        # do something

412 - ERR_NOTEXTTOSEND
----------------------

Format ``:{srv} 412 {nick} :No text to send``

Match ``^:(?P<srv>\S+) 412 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_NOTEXTTOSEND)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

442 - ERR_NOTONCHANNEL
----------------------

Format ``:{srv} 442 {nick} {channel} :You're not on that channel``

Match ``^:(?P<srv>\S+) 442 (?P<me>\S+) (?P<channel>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_NOTONCHANNEL)
    def myevent(bot, srv=None, me=None, channel=None, data=None):
        # do something

413 - ERR_NOTOPLEVEL
--------------------

Format ``:{srv} 413 {nick} {mask} :No toplevel domain specified``

Match ``^:(?P<srv>\S+) 413 (?P<me>\S+) (?P<mask>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_NOTOPLEVEL)
    def myevent(bot, srv=None, me=None, mask=None, data=None):
        # do something

451 - ERR_NOTREGISTERED
-----------------------

Format ``:{srv} 451 {nick} :You have not registered``

Match ``^:(?P<srv>\S+) 451 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_NOTREGISTERED)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

464 - ERR_PASSWDMISMATCH
------------------------

Format ``:{srv} 464 {nick} :Password incorrect``

Match ``^:(?P<srv>\S+) 464 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_PASSWDMISMATCH)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

445 - ERR_SUMMONDISABLED
------------------------

Format ``:{srv} 445 {nick} :SUMMON has been disabled``

Match ``^:(?P<srv>\S+) 445 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_SUMMONDISABLED)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

405 - ERR_TOOMANYCHANNELS
-------------------------

Format ``:{srv} 405 {nick} {channel} :You have joined too many channels``

Match ``^:(?P<srv>\S+) 405 (?P<me>\S+) (?P<channel>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_TOOMANYCHANNELS)
    def myevent(bot, srv=None, me=None, channel=None, data=None):
        # do something

407 - ERR_TOOMANYTARGETS
------------------------

Format ``:{srv} 407 {nick} {target} :Duplicate recipients. No message delivered``

Match ``^:(?P<srv>\S+) 407 (?P<me>\S+) (?P<target>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_TOOMANYTARGETS)
    def myevent(bot, srv=None, me=None, target=None, data=None):
        # do something

501 - ERR_UMODEUNKNOWNFLAG
--------------------------

Format ``:{srv} 501 {nick} :Unknown MODE flag``

Match ``^:(?P<srv>\S+) 501 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_UMODEUNKNOWNFLAG)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

421 - ERR_UNKNOWNCOMMAND
------------------------

Format ``:{srv} 421 {nick} {cmd} :Unknown command``

Match ``^:(?P<srv>\S+) 421 (?P<me>\S+) (?P<cmd>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_UNKNOWNCOMMAND)
    def myevent(bot, srv=None, me=None, cmd=None, data=None):
        # do something

472 - ERR_UNKNOWNMODE
---------------------

Format ``:{srv} 472 {nick} {char} :is unknown mode char to me``

Match ``^:(?P<srv>\S+) 472 (?P<me>\S+) (?P<char>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_UNKNOWNMODE)
    def myevent(bot, srv=None, me=None, char=None, data=None):
        # do something

441 - ERR_USERNOTINCHANNEL
--------------------------

Format ``:{srv} 441 {nick} {nick} {channel} :They aren't on that channel``

Match ``^:(?P<srv>\S+) 441 (?P<me>\S+) (?P<nick>\S+) (?P<channel>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_USERNOTINCHANNEL)
    def myevent(bot, srv=None, me=None, nick=None, channel=None, data=None):
        # do something

443 - ERR_USERONCHANNEL
-----------------------

Format ``:{srv} 443 {nick} {nick} {channel} :is already on channel``

Match ``^:(?P<srv>\S+) 443 (?P<me>\S+) (?P<nick>\S+) (?P<channel>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_USERONCHANNEL)
    def myevent(bot, srv=None, me=None, nick=None, channel=None, data=None):
        # do something

446 - ERR_USERSDISABLED
-----------------------

Format ``:{srv} 446 {nick} :USERS has been disabled``

Match ``^:(?P<srv>\S+) 446 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_USERSDISABLED)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

502 - ERR_USERSDONTMATCH
------------------------

Format ``:{srv} 502 {nick} :Cant change mode for other users``

Match ``^:(?P<srv>\S+) 502 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_USERSDONTMATCH)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

406 - ERR_WASNOSUCHNICK
-----------------------

Format ``:{srv} 406 {nick} {nick} :There was no such nickname``

Match ``^:(?P<srv>\S+) 406 (?P<me>\S+) (?P<nick>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_WASNOSUCHNICK)
    def myevent(bot, srv=None, me=None, nick=None, data=None):
        # do something

414 - ERR_WILDTOPLEVEL
----------------------

Format ``:{srv} 414 {nick} {mask} :Wildcard in toplevel domain``

Match ``^:(?P<srv>\S+) 414 (?P<me>\S+) (?P<mask>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_WILDTOPLEVEL)
    def myevent(bot, srv=None, me=None, mask=None, data=None):
        # do something

465 - ERR_YOUREBANNEDCREEP
--------------------------

Format ``:{srv} 465 {nick} :You are banned from this server``

Match ``^:(?P<srv>\S+) 465 (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.ERR_YOUREBANNEDCREEP)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

Misc
====

CONNECTED
---------

Match ``^:(?P<srv>\S+) (376|422) (?P<me>\S+) :(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.CONNECTED)
    def myevent(bot, srv=None, me=None, data=None):
        # do something

CTCP
----

Match ``^(@(?P<tags>\S+) )?:(?P<mask>\S+!\S+@\S+) (?P<event>(PRIVMSG|NOTICE)) {nick} :(?P<ctcp>.*)$``

Example:

.. code-block:: python

    @irc3.event(rfc.CTCP)
    def myevent(bot, mask=None, event=None, ctcp=None, tags=None):
        # do something

Out Match ``^(?P<event>(PRIVMSG|NOTICE)) (?P<target>\S+) :(?P<ctcp>.*)$``

Example:

.. code-block:: python

    @irc3.event(rfc.CTCP, iotype="out")
    def myevent(bot, event=None, target=None, ctcp=None):
        # do something

INVITE
------

Match ``^(@(?P<tags>\S+) )?:(?P<mask>\S+!\S+@\S+) INVITE {nick} :?(?P<channel>\S+)$``

Example:

.. code-block:: python

    @irc3.event(rfc.INVITE)
    def myevent(bot, mask=None, channel=None, tags=None):
        # do something

JOIN
----

Match ``^(@(?P<tags>\S+) )?:(?P<mask>\S+) JOIN :?(?P<channel>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.JOIN)
    def myevent(bot, mask=None, channel=None, tags=None):
        # do something

Out Match ``^JOIN :?(?P<channel>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.JOIN, iotype="out")
    def myevent(bot, channel=None):
        # do something

JOIN_PART_QUIT
--------------

Match ``^(@(?P<tags>\S+) )?:(?P<mask>\S+) (?P<event>JOIN|PART|QUIT)\s*:*(?P<channel>\S*)(\s+:(?P<data>.*)|$)``

Example:

.. code-block:: python

    @irc3.event(rfc.JOIN_PART_QUIT)
    def myevent(bot, mask=None, event=None, channel=None, data=None, tags=None):
        # do something

Out Match ``^(?P<event>JOIN|PART|QUIT)\s*:*(?P<channel>\S*)(\s+:(?P<data>.*)|$)``

Example:

.. code-block:: python

    @irc3.event(rfc.JOIN_PART_QUIT, iotype="out")
    def myevent(bot, event=None, channel=None, data=None):
        # do something

KICK
----

Match ``^(@(?P<tags>\S+) )?:(?P<mask>\S+) (?P<event>KICK)\s+(?P<channel>\S+)\s*(?P<target>\S+)(\s+:(?P<data>.*)|$)``

Example:

.. code-block:: python

    @irc3.event(rfc.KICK)
    def myevent(bot, mask=None, event=None, channel=None, target=None, data=None, tags=None):
        # do something

Out Match ``^(?P<event>KICK)\s+(?P<channel>\S+)\s*(?P<target>\S+)(\s+:(?P<data>.*)|$)``

Example:

.. code-block:: python

    @irc3.event(rfc.KICK, iotype="out")
    def myevent(bot, event=None, channel=None, target=None, data=None):
        # do something

MODE
----

Match ``^(@(?P<tags>\S+) )?:(?P<mask>\S+) (?P<event>MODE)\s+(?P<target>\S+)\s+(?P<modes>\S+)(\s+(?P<data>.*)|$)``

Example:

.. code-block:: python

    @irc3.event(rfc.MODE)
    def myevent(bot, mask=None, event=None, target=None, modes=None, data=None, tags=None):
        # do something

Out Match ``^(?P<event>MODE)\s+(?P<target>\S+)\s+(?P<modes>\S+)(\s+(?P<data>.*)|$)``

Example:

.. code-block:: python

    @irc3.event(rfc.MODE, iotype="out")
    def myevent(bot, event=None, target=None, modes=None, data=None):
        # do something

MY_PRIVMSG
----------

Match ``^(@(?P<tags>\S+) )?:(?P<mask>\S+!\S+@\S+) (?P<event>(PRIVMSG|NOTICE)) (?P<target>(#\S+|{nick})) :{nick}[:,\s]\s*(?P<data>\S+.*)$``

Example:

.. code-block:: python

    @irc3.event(rfc.MY_PRIVMSG)
    def myevent(bot, mask=None, event=None, target=None, data=None, tags=None):
        # do something

Out Match ``^(?P<event>(PRIVMSG|NOTICE)) (?P<target>\S+) :(?P<data>.*)$``

Example:

.. code-block:: python

    @irc3.event(rfc.MY_PRIVMSG, iotype="out")
    def myevent(bot, event=None, target=None, data=None):
        # do something

NEW_NICK
--------

Match ``^(@(?P<tags>\S+) )?:(?P<nick>\S+) NICK :?(?P<new_nick>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.NEW_NICK)
    def myevent(bot, nick=None, new_nick=None, tags=None):
        # do something

Out Match ``^NICK :?(?P<new_nick>\S+)``

Example:

.. code-block:: python

    @irc3.event(rfc.NEW_NICK, iotype="out")
    def myevent(bot, new_nick=None):
        # do something

PART
----

Match ``^(@(?P<tags>\S+) )?:(?P<mask>\S+) PART (?P<channel>\S+)(\s+:(?P<data>.*)|$)``

Example:

.. code-block:: python

    @irc3.event(rfc.PART)
    def myevent(bot, mask=None, channel=None, data=None, tags=None):
        # do something

Out Match ``PART (?P<channel>\S+)(\s+:(?P<data>.*)|$)``

Example:

.. code-block:: python

    @irc3.event(rfc.PART, iotype="out")
    def myevent(bot, channel=None, data=None):
        # do something

PING
----

Match ``^PING :?(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.PING)
    def myevent(bot, data=None):
        # do something

PONG
----

Match ``^(@(?P<tags>\S+) )?:(?P<server>\S+) PONG (?P=server) :?(?P<data>.*)``

Example:

.. code-block:: python

    @irc3.event(rfc.PONG)
    def myevent(bot, server=None, data=None, tags=None):
        # do something

PRIVMSG
-------

Match ``^(@(?P<tags>\S+) )?:(?P<mask>\S+!\S+@\S+) (?P<event>(PRIVMSG|NOTICE)) (?P<target>\S+) :(?P<data>.*)$``

Example:

.. code-block:: python

    @irc3.event(rfc.PRIVMSG)
    def myevent(bot, mask=None, event=None, target=None, data=None, tags=None):
        # do something

Out Match ``^(?P<event>(PRIVMSG|NOTICE)) (?P<target>\S+) :(?P<data>.*)$``

Example:

.. code-block:: python

    @irc3.event(rfc.PRIVMSG, iotype="out")
    def myevent(bot, event=None, target=None, data=None):
        # do something

QUIT
----

Match ``^(@(?P<tags>\S+) )?:(?P<mask>\S+) QUIT(\s+:(?P<data>.*)|$)``

Example:

.. code-block:: python

    @irc3.event(rfc.QUIT)
    def myevent(bot, mask=None, data=None, tags=None):
        # do something

Out Match ``^QUIT(\s+:(?P<data>.*)|$)``

Example:

.. code-block:: python

    @irc3.event(rfc.QUIT, iotype="out")
    def myevent(bot, data=None):
        # do something

TOPIC
-----

Match ``^(@(?P<tags>\S+) )?:(?P<mask>\S+!\S+@\S+) TOPIC (?P<channel>\S+) :(?P<data>.*)$``

Example:

.. code-block:: python

    @irc3.event(rfc.TOPIC)
    def myevent(bot, mask=None, channel=None, data=None, tags=None):
        # do something

Out Match ``^TOPIC (?P<channel>\S+) :(?P<data>.*)$``

Example:

.. code-block:: python

    @irc3.event(rfc.TOPIC, iotype="out")
    def myevent(bot, channel=None, data=None):
        # do something



================================================
FILE: docs/utils.rst
================================================
========================
:mod:`irc3.utils` Utils
========================

.. automodule:: irc3.utils

.. autoclass:: IrcString
  :members:

.. autofunction:: as_list

.. autofunction:: as_channel

.. autofunction:: split_message

.. autoclass:: Logger
  :members:

.. autoclass:: Config

.. autofunction:: parse_config

.. autofunction:: extract_config

.. autofunction:: maybedotted



================================================
FILE: examples/async_command.py
================================================
# -*- coding: utf-8 -*-
from irc3.plugins.command import command
from irc3.compat import Queue
import irc3


@irc3.plugin
class AsyncCommands(object):
    """Async commands example. This is what it's look like on irc::

        <gawel> !get
        <gawel> !put item
        <irc3> items added to queue
        <irc3> item
    """

    def __init__(self, bot):
        self.bot = bot
        self.queue = Queue()

    @command
    def put(self, mask, target, args):
        """Put items in queue

            %%put <words>...
        """
        for w in args['<words>']:
            self.queue.put_nowait(w)
        yield 'items added to queue'

    @command
    async def get(self, mask, target, args):
        """Async get items from the queue

            %%get
        """
        messages = []
        message = await self.queue.get()
        messages.append(message)
        while not self.queue.empty():
            message = await self.queue.get()
            messages.append(message)
        return messages


================================================
FILE: examples/benches.ini
================================================
[bot]
nick = malkovitch
username = malkovitch
host = localhost
port = 6667
name = malkovitch
user = malkovitch
realname = I'm the real John Malkovitch
channel = head
includes =
    benches

[server]
servername = malkovitch
client_amount = 500
includes =
    irc3d.plugins.core

[opers]
gawel=passwd


================================================
FILE: examples/benches.py
================================================
# -*- coding: utf-8 -*-
import random
from irc3.compat import asyncio
from irc3d import IrcServer
import irc3


@irc3.plugin
class Plugin(object):

    def __init__(self, context):
        self.log = context.log
        self.context = context
        self.name = context.config.name
        self.channel = '#' + context.config.channel

    @irc3.event(irc3.rfc.CONNECTED)
    def connected(self, **kw):
        self.context.join(self.channel)

    def msg(self):
        s = ' '.join([self.name for i in range(random.randint(1, 10))])
        s += random.choice([' ?', '', ' !', ' #@!', ' '])
        self.context.privmsg(self.channel, s)
        self.context.loop.call_later(
            random.randint(3, 20), self.msg)

    @irc3.event(irc3.rfc.JOIN)
    def join(self, mask=None, **kw):
        if mask.nick == self.context.nick:
            self.context.loop.call_later(
                random.randint(3, 20), self.msg)


def main():
    loop = asyncio.get_event_loop()

    server = IrcServer.from_argv(loop=loop)
    bot = irc3.IrcBot.from_argv(loop=loop)

    def factory(i):
        irc3.IrcBot.from_argv(
            loop=loop, i=i,
            nick=bot.nick + str(i),
            realname=bot.config.realname + str(i),
        )

    for i in range(1, server.config.client_amount):
        loop.call_later(.1 * i, factory, i)

    loop.run_forever()


================================================
FILE: examples/bot.ini
================================================
[bot]
nick = irc3
username = irc3

host = irc.freenode.net
port = 7000
ssl = true

includes =
    irc3.plugins.core
    irc3.plugins.ctcp
    irc3.plugins.cron
    irc3.plugins.autojoins
    irc3.plugins.userlist
    irc3.plugins.command
    irc3.plugins.human
    irc3.plugins.search
    irc3.plugins.uptime
    irc3.plugins.feeds
    irc3.plugins.social
    irc3.plugins.fifo
    freenode_irc3
    nickserv

# channels to join
autojoins =
    irc3

[irc3.plugins.command]
# command plugin configuration

# set command char
cmd = !
# enable antiflood on commands
antiflood = true
# set guard policy
guard = irc3.plugins.command.mask_based_policy

[irc3.plugins.command.masks]
*!~gael@amandine.bearstech.com = all_permissions

[irc3.plugins.feeds]
# feeds plugin configuration
directory = ~/.irc3/feeds/
hook = freenode_irc3.FeedsHook
channels = irc3
delay = 5

github/irc3 = https://github.com/gawel/irc3/commits/master.atom
github/irc3.fmt = [{feed.name}] New commit by {entry.author}: {entry.title} - {entry.link}
github/irc3.delay = 5

travis/irc3 = https://api.travis-ci.org/repos/gawel/irc3/builds.atom
travis/irc3.fmt = [{feed.name}] {entry.title} - {entry.link}
travis/irc3.channels = irc3
travis/irc3.delay = 10

pypi/irc3 = https://pypi.python.org/pypi?:action=rss
pypi/irc3.fmt = {entry.title} is out! - {entry.link}
pypi/irc3.delay = 60

[irc3.plugins.fifo]
runpath = /tmp/run/irc3


================================================
FILE: examples/commands.rst
================================================
===============================================
Available Commands for irc3 at irc.freenode.net
===============================================

.. contents::

irc3.plugins.command
====================

help
----

Show help

    ``!help [<cmd>]``


ping
----

ping/pong

    ``!ping``

*Require admin permission.*
*Only available in private.*

irc3.plugins.search
===================

ddg
---

Search using https://duckduckgo.com/api

    ``!ddg <query>...``

*Require view permission.*

irc3.plugins.social
===================

retweet
-------

Retweet

    ``!retweet [--id=<id>] <url_or_id>``

*Require edit permission.*

tweet
-----

Post to social networks

    ``!tweet [--id=<id>] <message>...``

*Require edit permission.*

irc3.plugins.uptime
===================

uptime
------

Show uptimes

    ``!uptime``

*Require view permission.*



================================================
FILE: examples/config.ini
================================================
[bot]
nick = mybot
username = mybot

host = localhost
port = 6667

# uncomment this if you want ssl support
# ssl = true
# uncomment this if you don't want to check the certificate
# ssl_verify = CERT_NONE

# uncomment this if you want to use sasl authentication
# sasl_username = mybot
# sasl_password = yourpassword

includes =
    irc3.plugins.command
#    irc3.plugins.uptime
#    irc3.plugins.ctcp
    mybot_plugin

# the bot will join #mybot_channel
# ${#} is replaced by the # char
autojoins =
    ${#}mybot_channel

# Autojoin delay, disabled by default
# float or int value
# autojoin_delay = 3.1

# The maximum amount of lines irc3 sends at once.
# Default to 4, set to 0 to disable
# flood_burst = 10

# The number of lines per $flood_rate_delay seconds irc3 sends after reaching
# the $flood_burst limit.
# Default to 1
# flood_rate = 2

# The bot will send $flood_rate messages per $flood_rate_delay seconds
# Default to 1
# flood_rate_delay = 5

[irc3.plugins.command]
# command plugin configuration

# set command char
cmd = !

# set guard policy
guard = irc3.plugins.command.mask_based_policy

[irc3.plugins.command.masks]
# this section is used by the guard to secure the bot's command
# change your nickname and uncomment the line below
# mynick!*@* = all_permissions
* = view


================================================
FILE: examples/dcc_chat.py
================================================
# -*- coding: utf-8 -*-
from irc3.compat import asyncio
from irc3d import IrcServer
import irc3


@irc3.plugin
class Plugin(object):

    def __init__(self, context):
        self.log = context.log
        self.context = context

    @irc3.event(irc3.rfc.CONNECTED)
    def connected(self, **kw):
        self.context.join('#dcc')

    @irc3.event(irc3.rfc.JOIN)
    async def join(self, mask=None, **kw):
        if mask.nick != self.context.nick and mask.nick == 'receiver':
            # receiver joined the chan. offer a chat
            conn = await self.context.dcc_chat(mask)
            # wait for my buddy
            await conn.started
            # say hi
            conn.send_line('Hi!')
            await conn.closed
            self.context.log.info('chat with %s closed', mask.nick)

    @irc3.event(irc3.rfc.CTCP)
    async def on_ctcp(self, mask=None, **kwargs):
        # parse ctcp message
        print(kwargs)
        host, port = kwargs['ctcp'].split()[3:]
        self.context.log.info('%s is offering a chat', mask.nick)
        # open the chat
        conn = await self.context.dcc_chat(mask, host, port)
        conn.send_line('youhou')
        # end the loop after a few seconds
        self.context.loop.call_later(1,
                                     self.context.config.end_chat.set_result,
                                     True)
        await conn.closed
        self.context.log.info('chat with %s closed', mask.nick)

    @irc3.dcc_event(r'(?P<data>.*)')
    def on_dcc(self, client=None, data=None):
        """event to catch everything in dcc chats"""
        self.context.log.info('%r sent %s', client, data)


def main():
    loop = asyncio.get_event_loop()

    # run a test server
    server = IrcServer.from_config(dict(
        loop=loop,
        servername='test',
        includes=['irc3d.plugins.core'],
    ))
    server.run(forever=False)

    end_chat = asyncio.Future()

    cfg = dict(
        host='localhost',
        port=6667,
        nick='sender',
        includes=['irc3.plugins.dcc', __name__],
        loop=loop,
        end_chat=end_chat,
    )
    # this bot will send the file
    sender = irc3.IrcBot.from_config(cfg)
    sender.run(forever=False)

    def f():
        # this bot will receive the file
        receiver.run(forever=False)
    # assume receiver is created *after* sender
    receiver = irc3.IrcBot.from_config(cfg, nick='receiver')
    loop.call_later(.2, receiver.run, False)

    loop.run_until_complete(end_chat)


if __name__ == '__main__':
    main()


================================================
FILE: examples/dcc_send.py
================================================
# -*- coding: utf-8 -*-
import os
import string
import tempfile
import irc3
from irc3.plugins.command import command


@irc3.plugin
class DCC(object):

    filename = os.path.join(tempfile.gettempdir(), 'to_send')

    def __init__(self, bot):
        self.bot = bot
        if not os.path.isfile(self.filename):
            # create a file to send
            with open(self.filename, 'wb') as fd:
                for i in range(64 * 2048):
                    fd.write(string.ascii_letters.encode('utf8'))

    @command
    async def send(self, mask, target, args):
        """ DCC SEND command

            %%send
        """
        conn = await self.bot.dcc_send(mask, self.filename)
        self.bot.log.debug('%s ready', conn)


================================================
FILE: examples/dcc_send_and_get.py
================================================
# -*- coding: utf-8 -*-
from irc3.compat import asyncio
from irc3d import IrcServer
import irc3


@irc3.plugin
class Plugin(object):

    def __init__(self, context):
        self.log = context.log
        self.context = context

    @irc3.event(irc3.rfc.CONNECTED)
    def connected(self, **kw):
        self.context.join('#dcc')

    @irc3.event(irc3.rfc.JOIN)
    async def join(self, mask=None, **kw):
        if mask.nick != self.context.nick and mask.nick == 'receiver':
            # receiver joined the chan. offer a file
            conn = await self.context.dcc_send(mask, __file__)
            await conn.closed
            self.context.log.info('file sent to %s', mask.nick)

    @irc3.event(irc3.rfc.CTCP)
    async def on_ctcp(self, mask=None, **kwargs):
        # parse ctcp message
        name, host, port, size = kwargs['ctcp'].split()[2:]
        self.context.log.info('%s is offering %s', mask.nick, name)
        # get the file
        conn = await self.context.create_task(self.context.dcc_get(
            mask, host, port, '/tmp/sent.py', int(size)))
        await conn.closed
        self.context.log.info('file received from %s', mask.nick)

        # end loop by setting future's result
        self.context.config.file_received.set_result(True)


def main():
    loop = asyncio.get_event_loop()

    # run a test server
    server = IrcServer.from_config(dict(
        loop=loop,
        servername='test',
        includes=['irc3d.plugins.core'],
    ))
    server.run(forever=False)

    cfg = dict(
        host='localhost',
        port=6667,
        nick='sender',
        includes=[__name__],
        loop=loop,
    )
    # this bot will send the file
    sender = irc3.IrcBot.from_config(cfg)
    sender.run(forever=False)

    file_received = asyncio.Future()

    def f():
        # this bot will receive the file
        receiver.run(forever=False)
    # assume receiver is created *after* sender
    receiver = irc3.IrcBot.from_config(cfg,
                                       nick='receiver',
                                       file_received=file_received)
    loop.call_later(.2, receiver.run, False)

    loop.run_until_complete(file_received)


if __name__ == '__main__':
    main()


================================================
FILE: examples/dev.ini
================================================
[bot]
nick = irc3_dev
username = irc3
host = irc.freenode.net
port = 7000
ssl = true
includes =
    irc3.plugins.core
    irc3.plugins.userlist
    irc3.plugins.ctcp
    irc3.plugins.autojoins
    irc3.plugins.log
    irc3.plugins.command
    irc3.plugins.human
    irc3.plugins.search
    irc3.plugins.uptime
    irc3.plugins.cron
    irc3.plugins.social
    irc3.plugins.feeds
    irc3.plugins.fifo
    freenode_irc3
    paginate
    topic
    mybot
#    nickserv
cmd = .
autojoins = #irc3_dev

[irc3.plugins.command]
antiflood = true
guard = irc3.plugins.command.mask_based_policy

[irc3.plugins.command.masks]
gawel!*@*=all_permissions

[irc3.plugins.feeds]
delay = 1
directory = ~/.irc3/feeds/
hook = freenode_irc3.FeedsHook
channels = irc3_dev

github/irc3 = https://github.com/gawel/irc3/commits/master.atom
github/irc3.fmt = [{feed.name}] New commit by {entry.author}: {entry.title} - {entry.link}
github/irc3.delay = 1

travis/irc3 = https://api.travis-ci.org/repos/gawel/irc3/builds.atom
travis/irc3.fmt = [{feed.name}] {entry.title} - {entry.link}
travis/irc3.channels = #irc3-dev
travis/irc3.delay = 1

pypi/irc3 = https://pypi.python.org/pypi?:action=rss
pypi/irc3.fmt = {entry.title} is out! - {entry.link}
pypi/irc3.delay = 3

[irc3.plugins.fifo]
runpath = /tmp/run/irc3


================================================
FILE: examples/freenode_irc3.py
================================================
# -*- coding: utf-8 -*-
from irc3.plugins.cron import cron
import os


class FeedsHook(object):
    """Custom hook for irc3.plugins.feeds"""

    def __init__(self, bot):
        self.bot = bot
        self.packages = [
            'asyncio', 'irc3', 'panoramisk',
            'requests', 'trollius', 'webtest',
            'pyramid',
        ]

    def filter_travis(self, entry):
        """Only show the latest entry iif this entry is in a new state"""
        fstate = entry.filename + '.state'
        if os.path.isfile(fstate):
            with open(fstate) as fd:
                state = fd.read().strip()
        else:
            state = None
        if 'failed' in entry.summary:
            nstate = 'failed'
        else:
            nstate = 'success'
        with open(fstate, 'w') as fd:
            fd.write(nstate)
        if state != nstate:
            build = entry.title.split('#')[1]
            entry['title'] = 'Build #{0} {1}'.format(build, nstate)
            return True

    def filter_pypi(self, entry):
        """Show only usefull packages"""
        for package in self.packages:
            if entry.title.lower().startswith(package):
                return entry

    def __call__(self, entries):
        travis = {}
        for entry in entries:
            if entry.feed.name.startswith('travis/'):
                travis[entry.feed.name] = entry
            elif entry.feed.name.startswith('pypi/'):
                yield self.filter_pypi(entry)
            else:
                yield entry
        for entry in travis.values():
            if self.filter_travis(entry):
                yield entry


@cron('*/15 * * * *')
def auto_retweet(bot):
    """retweet author tweets about irc3 and pypi releases"""
    conn = bot.get_social_connection(id='twitter')
    dirname = os.path.expanduser('~/.irc3/twitter/{nick}'.format(**bot.config))

    if not os.path.isdir(dirname):
        os.makedirs(dirname)

    filename = os.path.join(dirname, 'retweeted')
    if os.path.isfile(filename):
        with open(filename) as fd:
            retweeted = [i.strip() for i in fd.readlines()]
    else:
        retweeted = []

    for user in ('pypi', 'gawel_'):
        results = conn.search.tweets(
            q=user + ' AND irc3',
            result_type='recent')
        for item in results.get('statuses', []):
            if item['user']['screen_name'] == user:
                if item['id_str'] not in retweeted:
                    res = conn(getattr(conn.statuses.retweet, item['id_str']))
                    if 'id' in res:
                        with open(filename, 'a+') as fd:
                            fd.write(item['id_str'] + '\n')


@cron('*/2 * * * *', venusian_category='irc3.debug')
def test_cron(bot):
    bot.log.info('Running test_cron')


@cron('*/3 * * * *', venusian_category='irc3.debug')
def test_cron_raise(bot):
    raise OSError('test_cron_raise')


================================================
FILE: examples/humans.py
================================================
# -*- coding: utf-8 -*-
import asyncio
import irc3


@irc3.event(irc3.rfc.JOIN)
def greetings(bot, mask=None, channel=None, **kw):
    if not mask.nick.startswith(bot.nick):
        bot.privmsg(channel, '%s: Hi dude!' % mask.nick)


def main():
    loop = asyncio.get_event_loop()

    config = dict(
        autojoins=['#irc3'],
        host='irc.freenode.net', port=7000, ssl=True,
        timeout=30,
        includes=[
            'irc3.plugins.core',
            'irc3.plugins.human',
            __name__,  # this register this module
        ],
        loop=loop)

    # instanciate two bot
    irc3.IrcBot(nick='bobirc', **config).run(forever=False)
    irc3.IrcBot(nick='jackyrc', **config).run(forever=False)

    loop.run_forever()


if __name__ == '__main__':
    main()


================================================
FILE: examples/mybot.py
================================================
# -*- coding: utf-8 -*-
from irc3.plugins.command import command
import irc3


@irc3.plugin
class MyPlugin:
    """A plugin is a class which take the IrcBot as argument
    """

    requires = [
        'irc3.plugins.core',
        'irc3.plugins.userlist',
        'irc3.plugins.command',
        'irc3.plugins.human',
    ]

    def __init__(self, bot):
        self.bot = bot
        self.log = self.bot.log

    def connection_made(self):
        """triggered when connection is up"""

    def server_ready(self):
        """triggered after the server sent the MOTD (require core plugin)"""

    def connection_lost(self):
        """triggered when connection is lost"""

    @irc3.event(irc3.rfc.JOIN)
    def welcome(self, mask, channel, **kw):
        """Welcome people who join a channel"""
        if mask.nick != self.bot.nick:
            self.bot.call_with_human_delay(
                self.bot.privmsg, channel, 'Welcome %s!' % mask.nick)
        else:
            self.bot.call_with_human_delay(
                self.bot.privmsg, channel, "Hi guys!")

    @command
    def echo(self, mask, target, args):
        """Echo command

            %%echo <words>...
        """
        self.bot.privmsg(mask.nick, ' '.join(args['<words>']))

    @command
    def stats(self, mask, target, args):
        """Show stats of the channel using the userlist plugin

            %%stats [<channel>]
        """
        if args['<channel>']:
            channel = args['<channel>']
            target = mask.nick
        else:
            channel = target
        if channel in self.bot.channels:
            channel = self.bot.channels[channel]
            message = '{0} users'.format(len(channel))
            for mode, nicknames in sorted(channel.modes.items()):
                message += ' - {0}({1})'.format(mode, len(nicknames))
            self.bot.privmsg(target, message)

    @irc3.extend
    def my_usefull_method(self):
        """The extend decorator will allow you to call::

            bot.my_usefull_method()

        """


def main():
    # instanciate a bot
    config = dict(
        nick='irc3', autojoins=['#irc3'],
        host='irc.undernet.org', port=6667, ssl=False,
        includes=[
            'irc3.plugins.core',
            'irc3.plugins.command',
            'irc3.plugins.human',
            __name__,  # this register MyPlugin
        ]
    )
    bot = irc3.IrcBot.from_config(config)
    bot.run(forever=True)


if __name__ == '__main__':
    main()


================================================
FILE: examples/mybot_plugin.py
================================================
# -*- coding: utf-8 -*-
from irc3.plugins.command import command
import irc3


@irc3.plugin
class Plugin:

    def __init__(self, bot):
        self.bot = bot

    @irc3.event(irc3.rfc.JOIN)
    def say_hi(self, mask, channel, **kw):
        """Say hi when someone join a channel"""
        if mask.nick != self.bot.nick:
            self.bot.privmsg(channel, 'Hi %s!' % mask.nick)
        else:
            self.bot.privmsg(channel, 'Hi!')

    @command(permission='view')
    def echo(self, mask, target, args):
        """Echo

            %%echo <message>...
        """
        yield ' '.join(args['<message>'])


================================================
FILE: examples/mycommands.py
================================================
# -*- coding: utf-8 -*-
from irc3.plugins.command import command


@command
def echo(bot, mask, target, args):
    """Echo command

        %%echo <words>...
    """
    yield ' '.join(args['<words>'])


@command(permission='admin', public=False)
def adduser(bot, mask, target, args):
    """Add a user

        %%adduser <name> <password>
    """
    bot.privmsg(mask.nick, 'User added')


@command(show_in_help_list=False)
def my_secret_operation(bot, mask, target, args):
    """Do something you don't want in !help all the time

        %%my_secret_operation
    """
    yield "I like turtles"


================================================
FILE: examples/mycrons.py
================================================
# -*- coding: utf-8 -*-
from irc3.plugins.cron import cron


@cron('30 8 * * *')
def wakeup(bot):
    bot.privmsg('#irc3', "It's time to wake up!")


@cron('0 */2 * * *')
def take_a_break(bot):
    bot.privmsg('#irc3', "It's time to take a break!")


================================================
FILE: examples/myextends.py
================================================
# -*- coding: utf-8 -*-
import irc3


@irc3.extend
def my_usefull_function(bot, *args):
    return 'my_usefull_function(*%s)' % (args,)


@irc3.plugin
class MyPlugin(object):

    def __init__(self, bot):
        self.bot = bot

    @irc3.extend
    def my_usefull_method(self, *args):
        return 'my_usefull_method(*%s)' % (args,)


================================================
FILE: examples/nickserv.py
================================================
# -*- coding: utf-8 -*-
import irc3


@irc3.event(r'(@(?P<tags>\S+) )?:(?P<ns>NickServ)!NickServ@services.'
            r' NOTICE (?P<nick>irc3) :This nickname is registered.*')
def register(bot, ns=None, nick=None, **kw):
    try:
        password = bot.config[bot.config.host][nick]
    except KeyError:
        pass
    else:
        bot.privmsg(ns, 'identify %s %s' % (nick, password))


================================================
FILE: examples/paginate.py
================================================
# -*- coding: utf-8 -*-
import irc3
import requests
from irc3.plugins.command import command


@irc3.plugin
class SendFile(object):

    requires = [
        'irc3.plugins.command',
        'irc3.plugins.pager',
    ]

    def __init__(self, bot):
        self.bot = bot

    @command
    def cat(self, mask, target, args):
        """Cat a file with pagination

            %%cat
        """
        fd = open(__file__)
        for msg in self.bot.paginate(mask, fd, lines_per_page=10):
            yield msg

    @command
    def url(self, mask, target, args):
        """Cat an url with pagination

            %%url <url>
        """
        def iterator(url):
            resp = requests.get(url)
            for chunk in resp.iter_content(255):
                yield chunk.decode('utf8')
        for msg in self.bot.paginate(mask, iterator(args['<url>'])):
            yield msg


================================================
FILE: examples/proxy.py
================================================
# -*- coding: utf-8 -*-
import socks
import irc3


def sock_factory(bot, host, port):
    sock = socks.socksocket()
    sock.set_proxy(socks.SOCKS5, "localhost", 6969)
    sock.connect((host, 6667))
    return sock


def main():
    bot = irc3.IrcBot.from_argv(sock_factory=sock_factory)
    bot.run()


if __name__ == '__main__':
    main()


================================================
FILE: examples/slack.ini
================================================
[bot]
nick = <nick>
host = chat.freenode.net
port = 6697
ssl = true
sasl_username = <username>
sasl_password = <password>
includes =
    irc3.plugins.slack
[irc3.plugins.slack]
token = <xoxb-slackbottoken>
[irc3.plugins.slack.channels]
<slackchannel1> =
    ${#}<ircchannel1>
    ${#}<ircchannel2>
<slackchannel2> =
    ${#}<ircchannel3>


================================================
FILE: examples/spy.ini
================================================
[bot]
nick = spyer
username = spyer
host = localhost
port = 6667
channel = gov
includes =
    spy

[bot_chater]
nick = chater
username = chater
channel = irc3

[server]
servername = spy



================================================
FILE: examples/spy.py
================================================
# -*- coding: utf-8 -*-
import irc3


@irc3.plugin
class Plugin(object):

    chater = None

    def __init__(self, context):
        self.log = context.log
        self.context = context
        self.channel = context.config.channel

    @irc3.event(irc3.rfc.CONNECTED)
    def connected(self, **kw):
        chater = self.context.config.botnet['bot_chater']
        if chater is self.context:
            self.chater = None
            self.log.info("I'm a chater")
        else:
            self.chater = chater
            self.log.info("I'm a spyer")
        self.context.join(self.channel)

    @irc3.event(irc3.rfc.PRIVMSG)
    def on_privmsg(self, mask=None, data=None, **kw):
        print(self.chater, mask, data)
        if self.chater:
            self.chater.privmsg(self.chater.config.channel,
                                '{0}: {1}'.format(mask.nick, data))


================================================
FILE: examples/topic.py
================================================
# -*- coding: utf-8 -*-
import irc3
from irc3.plugins.command import command
from irc3.plugins.cron import cron


@irc3.plugin
class TopicPlugin:

    requires = ['irc3.plugins.async']

    def __init__(self, bot):
        self.bot = bot

    @irc3.event(irc3.rfc.TOPIC)
    @irc3.event(irc3.rfc.RPL_TOPIC)
    def get_topic(self, channel=None, data=None, **kwargs):
        """check the topic on join or on user action"""
        self.bot.log.warn('Topic for %s is %s', channel, data)

    @cron('* * * * *')
    async def cron_topic(self):
        """check the topic each minute"""
        result = await self.bot.async_cmds.topic('#irc3_dev')
        self.bot.log.warn('Topic for #irc3_dev is %(topic)s', result)

    @command
    def topic(self, mask, target, args):
        """Set topic

        %%topic <topic>...
        """
        if target.is_channel:
            self.bot.topic(target, ' '.join(args['<topic>']))

    @command
    async def aiotopic(self, mask, target, args):
        """Set topic and get result the async way

        %%aiotopic [<topic>...]
        """
        if target.is_channel:
            result = await self.bot.async_cmds.topic(
                target, ' '.join(args['<topic>']))
            return result['topic']


================================================
FILE: examples/wsgiapp.py
================================================
# -*- coding: utf-8 -*-
import asyncio
from aiohttp_wsgi import wsgi
from irc3 import plugin
import json


@plugin
class Webapp:

    requires = ['irc3.plugins.userlist']

    def __init__(self, bot):
        def server():
            return wsgi.WSGIServerHttpProtocol(self.wsgi)
        self.bot = bot
        loop = asyncio.get_event_loop()
        self.bot.log.info('Starting webapp')
        asyncio.Task(loop.create_server(
            server, '127.0.0.1', 5000))

    def wsgi(self, environ, start_response):
        start_response('200 OK', [('Content-Type', 'application/json')])
        plugin = self.bot.get_plugin('userlist')
        data = json.dumps(list(plugin.channels.keys()))
        return [data.encode('utf8')]


================================================
FILE: irc3/__init__.py
================================================
# -*- coding: utf-8 -*-
from urllib.request import urlopen
from ipaddress import ip_address
from collections import deque
from .dcc import DCCManager
from .dcc import DCCChat
from .dec import dcc_event
from .dec import event
from .dec import extend
from .dec import plugin
from . import config
from . import utils
from . import rfc
from . import base
from .compat import asyncio
from .compat import Queue
import venusian
import time


class IrcConnection(asyncio.Protocol):
    """asyncio protocol to handle an irc connection"""

    def connection_made(self, transport):
        self.transport = transport
        self.closed = False
        self.queue = deque()

    def decode(self, data):
        """Decode data with bot's encoding"""
        encoding = getattr(self, 'encoding', 'ascii')
        return data.decode(encoding, 'ignore')

    def data_received(self, data):
        data = self.decode(data)
        if self.queue:
            data = self.queue.popleft() + data
        lines = data.split('\r\n')
        self.queue.append(lines.pop(-1))
        for line in lines:
            self.factory.dispatch(line)

    def write(self, data):
        if data is not None:
            data = data.encode(self.encoding)
            if not data.endswith(b'\r\n'):
                data = data + b'\r\n'
            self.transport.write(data)

    def connection_lost(self, exc):
        self.factory.log.critical('connection lost (%s): %r',
                                  id(self.transport),
                                  exc)
        self.factory.notify('connection_lost')
        if not self.closed:
            self.close()
            # wait a few before reconnect
            self.factory.loop.call_later(
                2, self.factory.create_connection)

    def close(self):
        if not self.closed:
            self.factory.log.critical('closing old transport (%r)',
                                      id(self.transport))
            try:
                self.transport.close()
            finally:
                self.closed = True


class IrcBot(base.IrcObject):
    """An IRC bot"""

    _pep8 = [dcc_event, event, extend, plugin, rfc, config]
    venusian = venusian
    venusian_categories = [
        'irc3',
        'irc3.dcc',
        'irc3.extend',
        'irc3.rfc1459',
        'irc3.plugins.cron',
        'irc3.plugins.command',
    ]

    logging_config = config.LOGGING

    defaults = dict(
        base.IrcObject.defaults,
        nick='irc3',
        username='irc3',
        realname='Irc bot based on irc3 http://irc3.readthedocs.io',
        host='localhost',
        mode=0,
        url='https://irc3.readthedocs.io/',
        passwords={},
        flood_burst=4,
        flood_rate=1,
        flood_rate_delay=1,
        ctcp=dict(
            version='irc3 {version} - {url}',
            userinfo='{realname}',
            time='{now:%c}',
        ),
        # freenode config as default for testing
        server_config=dict(
            STATUSMSG='+@',
            PREFIX='(ov)@+',
            CHANTYPES='#',
            CHANMODES='eIbq,k,flj,CFLMPQScgimnprstz',
        ),
        connection=IrcConnection,
    )

    def __init__(self, *ini, **config):
        update_config_needed = False
        if 'userinfo' in config or \
           ('realname' in config and 'username' not in config):
            update_config_needed = True  # pragma: no cover
        super(IrcBot, self).__init__(*ini, **config)
        if update_config_needed:  # pragma: no cover
            # Backward compat. Remove me in 2017
            self.log.fatal('realname has been renamed to username.')
            self.log.fatal('userinfo has been renamed to realname.')
            self.log.fatal('Please update your config with something like:.')
            if 'realname' in self.config:
                self.log.fatal('username = %(realname)s', self.config)
            if 'userinfo' in self.config:
                self.log.fatal('realname = %(userinfo)s', self.config)
            import sys
            sys.exit(-1)
        self.queue = None
        if self.config.asynchronous:
            self.queue = Queue(loop=self.loop)
            self.awaiting_queue = self.create_task(self.process_queue())
        self._ip = self._dcc = None
        # auto include the sasl plugin if needed
        if 'sasl_username' in self.config and \
           'irc3.plugins.sasl' not in self.registry.includes:
            self.include('irc3.plugins.sasl')
        # auto include the autojoins plugin if needed (for backward compat)
        if 'autojoins' in self.config and \
           'irc3.plugins.autojoins' not in self.registry.includes:
            self.include('irc3.plugins.autojoins')

    @property
    def server_config(self):
        """return server configuration (rfc rpl 005)::

            >>> bot = IrcBot()
            >>> print(bot.server_config['STATUSMSG'])
            +@

        The real values are only available after the server sent them.
        """
        return self.config.server_config

    def connection_made(self, f):  # pragma: no cover
        if getattr(self, 'protocol', None):
            self.protocol.close()
        try:
            transport, protocol = f.result()
        except Exception as e:
            self.log.exception(e)
            self.loop.call_later(3, self.create_connection)
        else:
            self.log.debug('Connected')
            self.protocol = protocol
            self.protocol.queue = deque()
            self.protocol.factory = self
            self.protocol.encoding = self.encoding
            if self.config.get('password'):
                self._send('PASS {password}'.format(**self.config))
            self.notify('connection_ready')
            self.send((
                'USER {username} {mode} * :{realname}\r\n'
                'NICK {nick}\r\n'
            ).format(**self.config))
            self.notify('connection_made')

    def send_line(self, data, nowait=False):
        """send a line to the server. replace CR by spaces"""
        data = data.replace('\n', ' ').replace('\r', ' ')
        f = self.loop.create_future()
        if self.queue is not None and nowait is False:
            self.queue.put_nowait((f, data))
        else:
            self.send(data.replace('\n', ' ').replace('\r', ' '))
            f.set_result(True)
        return f

    async def process_queue(self):
        flood_burst = self.config.flood_burst
        delay = float(self.config.flood_rate_delay)
        flood_rate = delay / float(self.config.flood_rate)
        while True:
            if flood_burst == 0:
                future, data = await self.queue.get()
                future.set_result(True)
                self.send(data)
                await asyncio.sleep(.001, loop=self.loop)
            else:
                lines = []
                for i in range(flood_burst):
                    future, data = await self.queue.get()
                    future.set_result(True)
                    lines.append(data)
                    if self.queue.empty():
                        break
                if lines:
                    self.send('\r\n'.join(lines))
                while not self.queue.empty():
                    await asyncio.sleep(flood_rate, loop=self.loop)
                    future, data = await self.queue.get()
                    future.set_result(True)
                    self.send(data)

    def send(self, data):
        """send data to the server"""
        self._send(data)

    def _send(self, data):
        self.protocol.write(data)
        self.dispatch(data, iotype='out')

    def privmsg(self, target, message, nowait=False):
        """send a privmsg to target"""
        if message:
            is_dcc = isinstance(target, DCCChat)
            prefix = '' if is_dcc else 'PRIVMSG %s :' % target
            messages = utils.split_message(
                message,
                self.config.max_length,
                self.encoding,
                prefix=prefix,
            )
            if is_dcc:
                for message in messages:
                    target.send_line(message)
            elif target:
                f = None
                for message in messages:
                    f = self.send_line(prefix + message,
                                       nowait=nowait)
                return f

    def action(self, target, message, nowait=False):
        return self.privmsg(target, '\x01ACTION %s\x01' % message,
                            nowait=nowait)

    def notice(self, target, message, nowait=False):
        """send a notice to target"""
        if message:
            is_dcc = isinstance(target, DCCChat)
            prefix = '' if is_dcc else 'NOTICE %s :' % target
            messages = utils.split_message(
                message,
                self.config.max_length,
                self.encoding,
                prefix=prefix,
            )
            if is_dcc:
                for message in messages:
                    target.send_line(message)
            elif target:
                f = None
                for message in messages:
                    f = self.send_line(prefix + message,
                                       nowait=nowait)
                return f

    def ctcp(self, target, message, nowait=False):
        """send a ctcp to target"""
        if target and message:
            messages = utils.split_message(
                message,
                self.config.max_length,
                self.encoding,
            )
            f = None
            for message in messages:
                f = self.send_line('PRIVMSG %s :\x01%s\x01' % (target,
                                                               message),
                                   nowait=nowait)
            return f

    def ctcp_reply(self, target, message, nowait=False):
        """send a ctcp reply to target"""
        if target and message:
            messages = utils.split_message(
                message,
                self.config.max_length,
                self.encoding,
            )
            f = None
            for message in messages:
                f = self.send_line('NOTICE %s :\x01%s\x01' % (target, message),
                                   nowait=nowait)
            return f

    def mode(self, target, *data):
        """set user or channel mode"""
        self.send_line('MODE %s %s' % (target, ' '.join(data)), nowait=True)

    def join(self, target):
        """join a channel"""
        password = self.config.passwords.get(
            target.strip(self.server_config['CHANTYPES']))
        if password:
            target += ' ' + password
        self.send_line('JOIN %s' % target)

    def part(self, target, reason=None):
        """quit a channel"""
        if reason:
            target += ' :' + reason
        self.send_line('PART %s' % target)

    def kick(self, channel, target, reason=None):
        """kick target from channel"""
        if reason:
            target += ' :' + reason
        self.send_line('KICK %s %s' % (channel, target), nowait=True)

    def invite(self, target, channel):
        """invite target to a channel"""
        self.send_line('INVITE %s %s' % (target, channel))

    def topic(self, channel, topic=None):
        """change or request the topic of a channel"""
        if topic:
            channel += ' :' + topic
        self.send_line('TOPIC %s' % channel)

    def away(self, message=None):
        """mark ourself as away"""
        cmd = 'AWAY'
        if message:
            cmd += ' :' + message
        self.send_line(cmd)

    def unaway(self):
        """mask ourself as no longer away"""
        self.away()

    def quit(self, reason=None):
        """disconnect"""
        if not reason:
            reason = 'bye'
        else:
            reason = reason
        self.send_line('QUIT :%s' % reason)

    def get_nick(self):
        return self.config.nick

    def set_nick(self, nick):
        self.send_line('NICK ' + nick, nowait=True)

    nick = property(get_nick, set_nick, doc='nickname get/set')

    @property
    def ip(self):
        """return bot's ip as an ``ip_address`` object"""
        if not self._ip:
            if 'ip' in self.config:
                ip = self.config['ip']
            else:
                ip = self.protocol.transport.get_extra_info('sockname')[0]
            ip = ip_address(ip)
            if ip.version == 4:
                self._ip = ip
            else:  # pragma: no cover
                response = urlopen('http://ipv4.icanhazip.com/')
                ip = response.read().strip().decode()
                ip = ip_address(ip)
                self._ip = ip
        return self._ip

    @property
    def dcc(self):
        """return the :class:`~irc3.dcc.DCCManager`"""
        if self._dcc is None:
            self._dcc = DCCManager(self)
        return self._dcc

    async def dcc_chat(self, mask, host=None, port=None):
        """Open a DCC CHAT whith mask. If host/port are specified then connect
        to a server. Else create a server"""
        conn = self.dcc.create(
            'chat', mask, host=host, port=port)
        await conn.ready
        return conn

    async def dcc_get(self, mask, host, port, filepath, filesize=None):
        """DCC GET a file from mask. filepath must be an absolute path with an
        existing directory. filesize is the expected file size."""
        conn = self.dcc.create(
            'get', mask, filepath=filepath, filesize=filesize,
            host=host, port=port)
        await conn.ready
        return conn

    async def dcc_send(self, mask, filepath):
        """DCC SEND a file to mask. filepath must be an absolute path to
        existing file"""
        conn = self.dcc.create('send', mask, filepath=filepath)
        await conn.ready
        return conn

    async def dcc_accept(self, mask, filepath, port, pos):
        """accept a DCC RESUME for an axisting DCC SEND. filepath is the
        filename to sent.  port is the port opened on the server.
        pos is the expected offset"""
        return self.dcc.resume(mask, filepath, port, pos)

    def SIGHUP(self):
        self.reload()

    def SIGINT(self):
        self.notify('SIGINT')
        if getattr(self, 'protocol', None):
            self.quit('INT')
            time.sleep(1)
        self.loop.stop()


def run(argv=None):
    bots = {}
    bot = IrcBot.from_argv(argv, botnet=bots)
    bots['bot'] = bot
    for section in list(bot.config):
        if section.startswith('bot_'):
            config = bot.config.pop(section)
            bots[section] = IrcBot.from_argv(argv, botnet=bots, **config)
    bot.loop.run_forever()
    return bots


================================================
FILE: irc3/__main__.py
================================================
from irc3 import run

if __name__ == '__main__':
    run()


================================================
FILE: irc3/_gen_doc.py
================================================
# -*- coding: utf-8 -*-
from . import rfc
from . import template
import os


def render_attrs(title, attrs, out):
    out.write(title + '\n')
    out.write(len(title) * '=' + '\n')
    out.write('\n')
    for attr in attrs:
        name = attr.name
        title = name
        if isinstance(attr, int):
            title = '%s - %s' % (attr, title)
        out.write(title + '\n')
        out.write(len(title) * '-' + '\n\n')
        if hasattr(attr, 'tpl'):
            out.write('Format ``%s``\n\n' % attr.tpl.replace('{c.', '{'))
        out.write('Match ``%s``\n\n' % attr.re)
        out.write('Example:\n\n')
        out.write('.. code-block:: python\n\n')
        out.write('    @irc3.event(rfc.%s)\n' % name)
        params = getattr(attr, 'params', [])
        if params:
            params = '=None, '.join(params)
            out.write('    def myevent(bot, %s=None):\n' % params)
        else:
            out.write('    def myevent(bot):\n' % params)
        out.write('        # do something\n')
        out.write('\n')
        re_out = getattr(attr, 're_out', None)
        if re_out is not None:
            out.write('Out Match ``%s``\n\n' % re_out.re)
            out.write('Example:\n\n')
            out.write('.. code-block:: python\n\n')
            out.write('    @irc3.event(rfc.%s, iotype="out")\n' % name)
            params = getattr(re_out, 'params', [])
            if params:
                params = '=None, '.join(params)
                out.write('    def myevent(bot, %s=None):\n' % params)
            else:
                raise RuntimeError('regexp %s as no params' % re_out)
            out.write('        # do something\n')
            out.write('\n')


def main():
    print('Generate docs...')

    attrs = [getattr(rfc, attr) for attr in dir(rfc)
             if attr.isupper() and attr not in ('RETCODES',)]
    repls = [attr for attr in attrs if attr.name.startswith('RPL_')]
    errs = [attr for attr in attrs if attr.name.startswith('ERR_')]
    misc = [attr for attr in attrs
            if not attr.name.startswith(('ERR_', 'RPL_'))]
    out = open('docs/rfc.rst', 'w')
    out.write('========================\n')
    out.write(':mod:`irc3.rfc` RFC1459\n')
    out.write('========================\n\n')
    render_attrs('Replies (REPL)', repls, out)
    render_attrs('Errors (ERR)', errs, out)
    render_attrs('Misc', misc, out)

    try:
        os.makedirs('docs/plugins')
    except OSError:
        pass

    for filename in os.listdir('irc3/plugins'):
        if filename.startswith('_'):
            continue
        if not filename.endswith('.py'):
            continue
        filename = filename.replace('.py', '')
        modname = 'irc3.plugins.%s' % filename
        out = open('docs/plugins/' + filename + '.rst', 'w')
        out.write('.. automodule:: ' + modname + '\n')
        out.write('\n')

    template.main(nick='mybot',
                  dest=os.path.join(os.getcwd(), 'examples'))


if __name__ == '__main__':
    main()


================================================
FILE: irc3/_parse_rfc.py
================================================
# -*- coding: utf-8 -*-
from collections import defaultdict
import pprint
import re

_re_num = re.compile(r'\s(?P<num>\d+)\s+(?P<name>(RPL|ERR)_\w+)\s*(?P<_>.*)')
_re_mask = re.compile(r'^\s{24,25}(?P<_>("(<|:).*|\S.*"$))')


def main():
    print('Parsing rfc file...')
    item = None
    items = []

    out = open('irc3/_rfc.py', 'w')

    with open('irc3/rfc1459.txt') as fd:
        for line in fd:
            line = line.replace('<host> * <host>', '<host> * <host1>')
            line = line.replace('<# visible>', '<visible>')
            line = line.replace('<H|G>[*][@|+]', '<modes>')
            line = line.replace('<nick!user|*!*>@<host|server>', '<mask>')

            match = _re_num.search(line)
            if match is not None:
                if item:
                    items.append((int(item['num']), item))
                item = defaultdict(list)
                match = match.groupdict()
                if '_' in match:
                    match.pop('_')
                item.update(match)
            match = _re_mask.search(line)
            if match is not None:
                item['mask'].append(match.groupdict()['_'])

    _re_sub = re.compile('(?P<m><[^>]+>)')

    out.write('''
class retcode(int):
    name = None
    re = None

'''.lstrip())

    valids = set()
    for i, item in sorted(items):
        mask = item['mask']
        if mask:
            num = item['num']
            valids.add(i)
            out.write('\n')
            out.write('%(name)s = retcode(%(num)s)\n' % item)
            out.write('%(name)s.name = "%(name)s"\n' % item)
            mask = [s.strip('"\\ ') for s in mask]
            omask = ' '.join(mask)

            params = []

            def repl(v):
                v = v.lower()
                v = v.replace('nickname', 'nick')
                v = v.replace('nicks', 'nicknames')
                for c in '!@*':
                    v = v.replace(c, '')
                for c in '| ':
                    v = v.replace(c, '_')
                v = v.strip(' _')
                if v.endswith('_name'):
                    v = v[:-5]
                if v == 'client_ip_address_in_dot_form':
                    v = 'clientip'
                if v == 'integer':
                    for k in 'xyz':
                        if k not in params:
                            v = k
                            break
                if v == 'command':
                    v = 'cmd'
                if v == 'real':
                    v = 'realname'
                if v == 'name' and 'nick' not in params:
                    v = 'nick'
                if v == 'user':
                    if 'nick' not in params and num not in ('352',):
                        v = 'nick'
                    else:
                        v = 'username'
                return v

            def tsub(m):
                v = m.groupdict()['m'].strip('<>')
                v = repl(v)
                params.append(v)
                return '{%s}' % v

            if item['num'] == '303':
                omask = ':<nicknames>'
            elif item['num'] == '311':
                omask = omask.replace('*', '<m>')
            elif item['num'] == '319':
                omask = ':<channels>'
            elif item['num'] == '353':
                omask = '<m> <channel> :<nicknames>'

            tpl = _re_sub.sub(tsub, omask)
            for v in ((' %d ', '{days}'),
                      ('%d:%02d:%02d', '{hours}'),
                      (':%-8s %-9s %-8s', '{x} {y} {z}')):
                tpl = tpl.replace(*v)
            tpl_ = [':{c.srv} ' + item['num'] + ' {c.nick} ']
            if len(tpl) > 60:
                tpl_.extend([':' + s for s in tpl.split(':', 1)])
            else:
                tpl_.append(tpl)
            tpl = '\n    '.join([repr(v) for v in tpl_])

            params = []

            def msub(m):
                v = m.groupdict()['m'].strip('<>')
                v = repl(v)
                params.append(v)
                return r'(?P<%s>\S+)' % v

            mask = _re_sub.sub(msub, omask)
            if '???? ' in mask:
                mask = mask.replace('???? ', r'\S+ ')
            if ' * ' in mask:
                mask = mask.replace(' * ', r' . ')
            if ':' in mask:
                mask = mask.split(':', 1)[0]
                mask += ':(?P<data>.*)'
            mask = r'(?P<srv>\S+) ' + str(i) + ' (?P<me>\\S+) "\n    r"' + mask
            mask = mask.replace(
                r' (?P<server>\S+)',
                ' "\n    r"(?P<server>\\S+)')
            mask = mask.replace(
                r' (?P<sent_messages>\S+)',
                ' "\n    r"(?P<sent_messages>\\S+)')
            item['mask'] = mask
            params = [p for p in params if '<%s>' % p in mask]
            if '<data>' in mask and 'data' not in params:
                params.append('data')
            out.write('%(name)s.re = (\n    r"^:%(mask)s")\n' % item)
            params = pprint.pformat(
                ['srv', 'me'] + params, width=60, indent=4)
            if len(params) > 60:
                params = params.replace('[', '[\n ')
            out.write('%(name)s.tpl = (\n' % dict(item))
            out.write('    %s)\n' % tpl)
            out.write('%(name)s.params = %(p)s\n' % dict(item, p=params))

    out.write('\n')
    out.write('RETCODES = {\n')
    for i, item in sorted(items):
        if i in valids:
            out.write('    %(num)s: %(name)s,\n' % item)
    out.write('}\n')
    out.close()


if __name__ == '__main__':
    main()


================================================
FILE: irc3/_rfc.py
================================================
class retcode(int):
    name = None
    re = None


RPL_TRACELINK = retcode(200)
RPL_TRACELINK.name = "RPL_TRACELINK"
RPL_TRACELINK.re = (
    r"^:(?P<srv>\S+) 200 (?P<me>\S+) "
    r"(?P<next_server>\S+)")
RPL_TRACELINK.tpl = (
    ':{c.srv} 200 {c.nick} '
    '{next_server}')
RPL_TRACELINK.params = ['srv', 'me', 'next_server']

RPL_TRACECONNECTING = retcode(201)
RPL_TRACECONNECTING.name = "RPL_TRACECONNECTING"
RPL_TRACECONNECTING.re = (
    r"^:(?P<srv>\S+) 201 (?P<me>\S+) "
    r"Try. (?P<class>\S+) "
    r"(?P<server>\S+)")
RPL_TRACECONNECTING.tpl = (
    ':{c.srv} 201 {c.nick} '
    'Try. {class} {server}')
RPL_TRACECONNECTING.params = ['srv', 'me', 'class', 'server']

RPL_TRACEHANDSHAKE = retcode(202)
RPL_TRACEHANDSHAKE.name = "RPL_TRACEHANDSHAKE"
RPL_TRACEHANDSHAKE.re = (
    r"^:(?P<srv>\S+) 202 (?P<me>\S+) "
    r"H.S. (?P<class>\S+) "
    r"(?P<server>\S+)")
RPL_TRACEHANDSHAKE.tpl = (
    ':{c.srv} 202 {c.nick} '
    'H.S. {class} {server}')
RPL_TRACEHANDSHAKE.params = ['srv', 'me', 'class', 'server']

RPL_TRACEUNKNOWN = retcode(203)
RPL_TRACEUNKNOWN.name = "RPL_TRACEUNKNOWN"
RPL_TRACEUNKNOWN.re = (
    r"^:(?P<srv>\S+) 203 (?P<me>\S+) "
    r"\S+ (?P<class>\S+) [(?P<clientip>\S+)]")
RPL_TRACEUNKNOWN.tpl = (
    ':{c.srv} 203 {c.nick} '
    '???? {class} [{clientip}]')
RPL_TRACEUNKNOWN.params = ['srv', 'me', 'class', 'clientip']

RPL_TRACEOPERATOR = retcode(204)
RPL_TRACEOPERATOR.name = "RPL_TRACEOPERATOR"
RPL_TRACEOPERATOR.re = (
    r"^:(?P<srv>\S+) 204 (?P<me>\S+) "
    r"Oper (?P<class>\S+) (?P<nick>\S+)")
RPL_TRACEOPERATOR.tpl = (
    ':{c.srv} 204 {c.nick} '
    'Oper {class} {nick}')
RPL_TRACEOPERATOR.params = ['srv', 'me', 'class', 'nick']

RPL_TRACEUSER = retcode(205)
RPL_TRACEUSER.name = "RPL_TRACEUSER"
RPL_TRACEUSER.re = (
    r"^:(?P<srv>\S+) 205 (?P<me>\S+) "
    r"User (?P<class>\S+) (?P<nick>\S+)")
RPL_TRACEUSER.tpl = (
    ':{c.srv} 205 {c.nick} '
    'User {class} {nick}')
RPL_TRACEUSER.params = ['srv', 'me', 'class', 'nick']

RPL_TRACESERVER = retcode(206)
RPL_TRACESERVER.name = "RPL_TRACESERVER"
RPL_TRACESERVER.re = (
    r"^:(?P<srv>\S+) 206 (?P<me>\S+) "
    r"(?P<mask>\S+)")
RPL_TRACESERVER.tpl = (
    ':{c.srv} 206 {c.nick} '
    '{mask}')
RPL_TRACESERVER.params = ['srv', 'me', 'mask']

RPL_TRACENEWTYPE = retcode(208)
RPL_TRACENEWTYPE.name = "RPL_TRACENEWTYPE"
RPL_TRACENEWTYPE.re = (
    r"^:(?P<srv>\S+) 208 (?P<me>\S+) "
    r"(?P<newtype>\S+) 0 (?P<client>\S+)")
RPL_TRACENEWTYPE.tpl = (
    ':{c.srv} 208 {c.nick} '
    '{newtype} 0 {client}')
RPL_TRACENEWTYPE.params = ['srv', 'me', 'newtype', 'client']

RPL_STATSLINKINFO = retcode(211)
RPL_STATSLINKINFO.name = "RPL_STATSLINKINFO"
RPL_STATSLINKINFO.re = (
    r"^:(?P<srv>\S+) 211 (?P<me>\S+) "
    r"(?P<linkname>\S+) (?P<sendq>\S+) "
    r"(?P<sent_messages>\S+) (?P<received_bytes>\S+) (?P<time_open>\S+)")
RPL_STATSLINKINFO.tpl = (
    ':{c.srv} 211 {c.nick} '
    ':{linkname} {sendq} {sent_messages} {received_bytes} {time_open}')
RPL_STATSLINKINFO.params = [
    'srv',
    'me',
    'linkname',
    'sendq',
    'sent_messages',
    'received_bytes',
    'time_open']

RPL_STATSCOMMANDS = retcode(212)
RPL_STATSCOMMANDS.name = "RPL_STATSCOMMANDS"
RPL_STATSCOMMANDS.re = (
    r"^:(?P<srv>\S+) 212 (?P<me>\S+) "
    r"(?P<cmd>\S+) (?P<count>\S+)")
RPL_STATSCOMMANDS.tpl = (
    ':{c.srv} 212 {c.nick} '
    '{cmd} {count}')
RPL_STATSCOMMANDS.params = ['srv', 'me', 'cmd', 'count']

RPL_STATSCLINE = retcode(213)
RPL_STATSCLINE.name = "RPL_STATSCLINE"
RPL_STATSCLINE.re = (
    r"^:(?P<srv>\S+) 213 (?P<me>\S+) "
    r"C (?P<host>\S+) . (?P<nick>\S+) (?P<port>\S+) (?P<class>\S+)")
RPL_STATSCLINE.tpl = (
    ':{c.srv} 213 {c.nick} '
    'C {host} * {nick} {port} {class}')
RPL_STATSCLINE.params = ['srv', 'me', 'host', 'nick', 'port', 'class']

RPL_STATSNLINE = retcode(214)
RPL_STATSNLINE.name = "RPL_STATSNLINE"
RPL_STATSNLINE.re = (
    r"^:(?P<srv>\S+) 214 (?P<me>\S+) "
    r"N (?P<host>\S+) . (?P<nick>\S+) (?P<port>\S+) (?P<class>\S+)")
RPL_STATSNLINE.tpl = (
    ':{c.srv} 214 {c.nick} '
    'N {host} * {nick} {port} {class}')
RPL_STATSNLINE.params = ['srv', 'me', 'host', 'nick', 'port', 'class']

RPL_STATSILINE = retcode(215)
RPL_STATSILINE.name = "RPL_STATSILINE"
RPL_STATSILINE.re = (
    r"^:(?P<srv>\S+) 215 (?P<me>\S+) "
    r"I (?P<host>\S+) . (?P<host1>\S+) (?P<port>\S+) (?P<class>\S+)")
RPL_STATSILINE.tpl = (
    ':{c.srv} 215 {c.nick} '
    'I {host} * {host1} {port} {class}')
RPL_STATSILINE.params = ['srv', 'me', 'host', 'host1', 'port', 'class']

RPL_STATSKLINE = retcode(216)
RPL_STATSKLINE.name = "RPL_STATSKLINE"
RPL_STATSKLINE.re = (
    r"^:(?P<srv>\S+) 216 (?P<me>\S+) "
    r"K (?P<host>\S+) . (?P<username>\S+) (?P<port>\S+) (?P<class>\S+)")
RPL_STATSKLINE.tpl = (
    ':{c.srv} 216 {c.nick} '
    'K {host} * {username} {port} {class}')
RPL_STATSKLINE.params = ['srv', 'me', 'host', 'username', 'port', 'class']

RPL_STATSYLINE = retcode(218)
RPL_STATSYLINE.name = "RPL_STATSYLINE"
RPL_STATSYLINE.re = (
    r"^:(?P<srv>\S+) 218 (?P<me>\S+) "
    r"frequency> (?P<max_sendq>\S+)")
RPL_STATSYLINE.tpl = (
    ':{c.srv} 218 {c.nick} '
    'frequency> {max_sendq}')
RPL_STATSYLINE.params = ['srv', 'me', 'max_sendq']

RPL_ENDOFSTATS = retcode(219)
RPL_ENDOFSTATS.name = "RPL_ENDOFSTATS"
RPL_ENDOFSTATS.re = (
    r"^:(?P<srv>\S+) 219 (?P<me>\S+) "
    r"(?P<stats_letter>\S+) :(?P<data>.*)")
RPL_ENDOFSTATS.tpl = (
    ':{c.srv} 219 {c.nick} '
    '{stats_letter} :End of /STATS report')
RPL_ENDOFSTATS.params = ['srv', 'me', 'stats_letter', 'data']

RPL_UMODEIS = retcode(221)
RPL_UMODEIS.name = "RPL_UMODEIS"
RPL_UMODEIS.re = (
    r"^:(?P<srv>\S+) 221 (?P<me>\S+) "
    r"(?P<user_mode_string>\S+)")
RPL_UMODEIS.tpl = (
    ':{c.srv} 221 {c.nick} '
    '{user_mode_string}')
RPL_UMODEIS.params = ['srv', 'me', 'user_mode_string']

RPL_STATSLLINE = retcode(241)
RPL_STATSLLINE.name = "RPL_STATSLLINE"
RPL_STATSLLINE.re = (
    r"^:(?P<srv>\S+) 241 (?P<me>\S+) "
    r"L (?P<hostmask>\S+) . (?P<servername>\S+) (?P<maxdepth>\S+)")
RPL_STATSLLINE.tpl = (
    ':{c.srv} 241 {c.nick} '
    'L {hostmask} * {servername} {maxdepth}')
RPL_STATSLLINE.params = ['srv', 'me', 'hostmask', 'servername', 'maxdepth']

RPL_STATSUPTIME = retcode(242)
RPL_STATSUPTIME.name = "RPL_STATSUPTIME"
RPL_STATSUPTIME.re = (
    r"^:(?P<srv>\S+) 242 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_STATSUPTIME.tpl = (
    ':{c.srv} 242 {c.nick} '
    ':Server Up{days}days {hours}')
RPL_STATSUPTIME.params = ['srv', 'me', 'data']

RPL_STATSOLINE = retcode(243)
RPL_STATSOLINE.name = "RPL_STATSOLINE"
RPL_STATSOLINE.re = (
    r"^:(?P<srv>\S+) 243 (?P<me>\S+) "
    r"O (?P<hostmask>\S+) . (?P<nick>\S+)")
RPL_STATSOLINE.tpl = (
    ':{c.srv} 243 {c.nick} '
    'O {hostmask} * {nick}')
RPL_STATSOLINE.params = ['srv', 'me', 'hostmask', 'nick']

RPL_STATSHLINE = retcode(244)
RPL_STATSHLINE.name = "RPL_STATSHLINE"
RPL_STATSHLINE.re = (
    r"^:(?P<srv>\S+) 244 (?P<me>\S+) "
    r"H (?P<hostmask>\S+) . (?P<servername>\S+)")
RPL_STATSHLINE.tpl = (
    ':{c.srv} 244 {c.nick} '
    'H {hostmask} * {servername}')
RPL_STATSHLINE.params = ['srv', 'me', 'hostmask', 'servername']

RPL_LUSERCLIENT = retcode(251)
RPL_LUSERCLIENT.name = "RPL_LUSERCLIENT"
RPL_LUSERCLIENT.re = (
    r"^:(?P<srv>\S+) 251 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_LUSERCLIENT.tpl = (
    ':{c.srv} 251 {c.nick} '
    ':There are {x} users and {y} invisible on {z} servers')
RPL_LUSERCLIENT.params = ['srv', 'me', 'data']

RPL_LUSEROP = retcode(252)
RPL_LUSEROP.name = "RPL_LUSEROP"
RPL_LUSEROP.re = (
    r"^:(?P<srv>\S+) 252 (?P<me>\S+) "
    r"(?P<x>\S+) :(?P<data>.*)")
RPL_LUSEROP.tpl = (
    ':{c.srv} 252 {c.nick} '
    '{x} :operator(s) online')
RPL_LUSEROP.params = ['srv', 'me', 'x', 'data']

RPL_LUSERUNKNOWN = retcode(253)
RPL_LUSERUNKNOWN.name = "RPL_LUSERUNKNOWN"
RPL_LUSERUNKNOWN.re = (
    r"^:(?P<srv>\S+) 253 (?P<me>\S+) "
    r"(?P<x>\S+) :(?P<data>.*)")
RPL_LUSERUNKNOWN.tpl = (
    ':{c.srv} 253 {c.nick} '
    '{x} :unknown connection(s)')
RPL_LUSERUNKNOWN.params = ['srv', 'me', 'x', 'data']

RPL_LUSERCHANNELS = retcode(254)
RPL_LUSERCHANNELS.name = "RPL_LUSERCHANNELS"
RPL_LUSERCHANNELS.re = (
    r"^:(?P<srv>\S+) 254 (?P<me>\S+) "
    r"(?P<x>\S+) :(?P<data>.*)")
RPL_LUSERCHANNELS.tpl = (
    ':{c.srv} 254 {c.nick} '
    '{x} :channels formed')
RPL_LUSERCHANNELS.params = ['srv', 'me', 'x', 'data']

RPL_LUSERME = retcode(255)
RPL_LUSERME.name = "RPL_LUSERME"
RPL_LUSERME.re = (
    r"^:(?P<srv>\S+) 255 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_LUSERME.tpl = (
    ':{c.srv} 255 {c.nick} '
    ':I have {x} clients and {y}')
RPL_LUSERME.params = ['srv', 'me', 'data']

RPL_ADMINME = retcode(256)
RPL_ADMINME.name = "RPL_ADMINME"
RPL_ADMINME.re = (
    r"^:(?P<srv>\S+) 256 (?P<me>\S+) "
    r"(?P<server>\S+) :(?P<data>.*)")
RPL_ADMINME.tpl = (
    ':{c.srv} 256 {c.nick} '
    '{server} :Administrative info')
RPL_ADMINME.params = ['srv', 'me', 'server', 'data']

RPL_ADMINLOC1 = retcode(257)
RPL_ADMINLOC1.name = "RPL_ADMINLOC1"
RPL_ADMINLOC1.re = (
    r"^:(?P<srv>\S+) 257 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_ADMINLOC1.tpl = (
    ':{c.srv} 257 {c.nick} '
    ':{admin_info}')
RPL_ADMINLOC1.params = ['srv', 'me', 'data']

RPL_ADMINLOC2 = retcode(258)
RPL_ADMINLOC2.name = "RPL_ADMINLOC2"
RPL_ADMINLOC2.re = (
    r"^:(?P<srv>\S+) 258 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_ADMINLOC2.tpl = (
    ':{c.srv} 258 {c.nick} '
    ':{admin_info}')
RPL_ADMINLOC2.params = ['srv', 'me', 'data']

RPL_ADMINEMAIL = retcode(259)
RPL_ADMINEMAIL.name = "RPL_ADMINEMAIL"
RPL_ADMINEMAIL.re = (
    r"^:(?P<srv>\S+) 259 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_ADMINEMAIL.tpl = (
    ':{c.srv} 259 {c.nick} '
    ':{admin_info}')
RPL_ADMINEMAIL.params = ['srv', 'me', 'data']

RPL_TRACELOG = retcode(261)
RPL_TRACELOG.name = "RPL_TRACELOG"
RPL_TRACELOG.re = (
    r"^:(?P<srv>\S+) 261 (?P<me>\S+) "
    r"File (?P<logfile>\S+) (?P<debug_level>\S+)")
RPL_TRACELOG.tpl = (
    ':{c.srv} 261 {c.nick} '
    'File {logfile} {debug_level}')
RPL_TRACELOG.params = ['srv', 'me', 'logfile', 'debug_level']

RPL_AWAY = retcode(301)
RPL_AWAY.name = "RPL_AWAY"
RPL_AWAY.re = (
    r"^:(?P<srv>\S+) 301 (?P<me>\S+) "
    r"(?P<nick>\S+) :(?P<data>.*)")
RPL_AWAY.tpl = (
    ':{c.srv} 301 {c.nick} '
    '{nick} :{away_message}')
RPL_AWAY.params = ['srv', 'me', 'nick', 'data']

RPL_USERHOST = retcode(302)
RPL_USERHOST.name = "RPL_USERHOST"
RPL_USERHOST.re = (
    r"^:(?P<srv>\S+) 302 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_USERHOST.tpl = (
    ':{c.srv} 302 {c.nick} '
    ':[{reply}{{space}{reply}}]')
RPL_USERHOST.params = ['srv', 'me', 'data']

RPL_ISON = retcode(303)
RPL_ISON.name = "RPL_ISON"
RPL_ISON.re = (
    r"^:(?P<srv>\S+) 303 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_ISON.tpl = (
    ':{c.srv} 303 {c.nick} '
    ':{nicknames}')
RPL_ISON.params = ['srv', 'me', 'data']

RPL_UNAWAY = retcode(305)
RPL_UNAWAY.name = "RPL_UNAWAY"
RPL_UNAWAY.re = (
    r"^:(?P<srv>\S+) 305 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_UNAWAY.tpl = (
    ':{c.srv} 305 {c.nick} '
    ':You are no longer marked as being away')
RPL_UNAWAY.params = ['srv', 'me', 'data']

RPL_NOWAWAY = retcode(306)
RPL_NOWAWAY.name = "RPL_NOWAWAY"
RPL_NOWAWAY.re = (
    r"^:(?P<srv>\S+) 306 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_NOWAWAY.tpl = (
    ':{c.srv} 306 {c.nick} '
    ':You have been marked as being away')
RPL_NOWAWAY.params = ['srv', 'me', 'data']

RPL_WHOISUSER = retcode(311)
RPL_WHOISUSER.name = "RPL_WHOISUSER"
RPL_WHOISUSER.re = (
    r"^:(?P<srv>\S+) 311 (?P<me>\S+) "
    r"(?P<nick>\S+) (?P<username>\S+) (?P<host>\S+) (?P<m>\S+) :(?P<data>.*)")
RPL_WHOISUSER.tpl = (
    ':{c.srv} 311 {c.nick} '
    '{nick} {username} {host} {m} :{realname}')
RPL_WHOISUSER.params = ['srv', 'me', 'nick', 'username', 'host', 'm', 'data']

RPL_WHOISSERVER = retcode(312)
RPL_WHOISSERVER.name = "RPL_WHOISSERVER"
RPL_WHOISSERVER.re = (
    r"^:(?P<srv>\S+) 312 (?P<me>\S+) "
    r"(?P<nick>\S+) "
    r"(?P<server>\S+) :(?P<data>.*)")
RPL_WHOISSERVER.tpl = (
    ':{c.srv} 312 {c.nick} '
    '{nick} {server} :{server_info}')
RPL_WHOISSERVER.params = ['srv', 'me', 'nick', 'server', 'data']

RPL_WHOISOPERATOR = retcode(313)
RPL_WHOISOPERATOR.name = "RPL_WHOISOPERATOR"
RPL_WHOISOPERATOR.re = (
    r"^:(?P<srv>\S+) 313 (?P<me>\S+) "
    r"(?P<nick>\S+) :(?P<data>.*)")
RPL_WHOISOPERATOR.tpl = (
    ':{c.srv} 313 {c.nick} '
    '{nick} :is an IRC operator')
RPL_WHOISOPERATOR.params = ['srv', 'me', 'nick', 'data']

RPL_WHOWASUSER = retcode(314)
RPL_WHOWASUSER.name = "RPL_WHOWASUSER"
RPL_WHOWASUSER.re = (
    r"^:(?P<srv>\S+) 314 (?P<me>\S+) "
    r"(?P<nick>\S+) (?P<username>\S+) (?P<host>\S+) . :(?P<data>.*)")
RPL_WHOWASUSER.tpl = (
    ':{c.srv} 314 {c.nick} '
    '{nick} {username} {host} * :{realname}')
RPL_WHOWASUSER.params = ['srv', 'me', 'nick', 'username', 'host', 'data']

RPL_ENDOFWHO = retcode(315)
RPL_ENDOFWHO.name = "RPL_ENDOFWHO"
RPL_ENDOFWHO.re = (
    r"^:(?P<srv>\S+) 315 (?P<me>\S+) "
    r"(?P<nick>\S+) :(?P<data>.*)")
RPL_ENDOFWHO.tpl = (
    ':{c.srv} 315 {c.nick} '
    '{nick} :End of /WHO list')
RPL_ENDOFWHO.params = ['srv', 'me', 'nick', 'data']

RPL_WHOISIDLE = retcode(317)
RPL_WHOISIDLE.name = "RPL_WHOISIDLE"
RPL_WHOISIDLE.re = (
    r"^:(?P<srv>\S+) 317 (?P<me>\S+) "
    r"(?P<nick>\S+) (?P<x>\S+) :(?P<data>.*)")
RPL_WHOISIDLE.tpl = (
    ':{c.srv} 317 {c.nick} '
    '{nick} {x} :seconds idle')
RPL_WHOISIDLE.params = ['srv', 'me', 'nick', 'x', 'data']

RPL_ENDOFWHOIS = retcode(318)
RPL_ENDOFWHOIS.name = "RPL_ENDOFWHOIS"
RPL_ENDOFWHOIS.re = (
    r"^:(?P<srv>\S+) 318 (?P<me>\S+) "
    r"(?P<nick>\S+) :(?P<data>.*)")
RPL_ENDOFWHOIS.tpl = (
    ':{c.srv} 318 {c.nick} '
    '{nick} :End of /WHOIS list')
RPL_ENDOFWHOIS.params = ['srv', 'me', 'nick', 'data']

RPL_WHOISCHANNELS = retcode(319)
RPL_WHOISCHANNELS.name = "RPL_WHOISCHANNELS"
RPL_WHOISCHANNELS.re = (
    r"^:(?P<srv>\S+) 319 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_WHOISCHANNELS.tpl = (
    ':{c.srv} 319 {c.nick} '
    ':{channels}')
RPL_WHOISCHANNELS.params = ['srv', 'me', 'data']

RPL_LISTSTART = retcode(321)
RPL_LISTSTART.name = "RPL_LISTSTART"
RPL_LISTSTART.re = (
    r"^:(?P<srv>\S+) 321 (?P<me>\S+) "
    r"Channel :(?P<data>.*)")
RPL_LISTSTART.tpl = (
    ':{c.srv} 321 {c.nick} '
    'Channel :Users  Name')
RPL_LISTSTART.params = ['srv', 'me', 'data']

RPL_LIST = retcode(322)
RPL_LIST.name = "RPL_LIST"
RPL_LIST.re = (
    r"^:(?P<srv>\S+) 322 (?P<me>\S+) "
    r"(?P<channel>\S+) (?P<visible>\S+) :(?P<data>.*)")
RPL_LIST.tpl = (
    ':{c.srv} 322 {c.nick} '
    '{channel} {visible} :{topic}')
RPL_LIST.params = ['srv', 'me', 'channel', 'visible', 'data']

RPL_LISTEND = retcode(323)
RPL_LISTEND.name = "RPL_LISTEND"
RPL_LISTEND.re = (
    r"^:(?P<srv>\S+) 323 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_LISTEND.tpl = (
    ':{c.srv} 323 {c.nick} '
    ':End of /LIST')
RPL_LISTEND.params = ['srv', 'me', 'data']

RPL_CHANNELMODEIS = retcode(324)
RPL_CHANNELMODEIS.name = "RPL_CHANNELMODEIS"
RPL_CHANNELMODEIS.re = (
    r"^:(?P<srv>\S+) 324 (?P<me>\S+) "
    r"(?P<channel>\S+) (?P<mode>\S+) (?P<mode_params>\S+)")
RPL_CHANNELMODEIS.tpl = (
    ':{c.srv} 324 {c.nick} '
    '{channel} {mode} {mode_params}')
RPL_CHANNELMODEIS.params = ['srv', 'me', 'channel', 'mode', 'mode_params']

RPL_NOTOPIC = retcode(331)
RPL_NOTOPIC.name = "RPL_NOTOPIC"
RPL_NOTOPIC.re = (
    r"^:(?P<srv>\S+) 331 (?P<me>\S+) "
    r"(?P<channel>\S+) :(?P<data>.*)")
RPL_NOTOPIC.tpl = (
    ':{c.srv} 331 {c.nick} '
    '{channel} :No topic is set')
RPL_NOTOPIC.params = ['srv', 'me', 'channel', 'data']

RPL_TOPIC = retcode(332)
RPL_TOPIC.name = "RPL_TOPIC"
RPL_TOPIC.re = (
    r"^:(?P<srv>\S+) 332 (?P<me>\S+) "
    r"(?P<channel>\S+) :(?P<data>.*)")
RPL_TOPIC.tpl = (
    ':{c.srv} 332 {c.nick} '
    '{channel} :{topic}')
RPL_TOPIC.params = ['srv', 'me', 'channel', 'data']

RPL_INVITING = retcode(341)
RPL_INVITING.name = "RPL_INVITING"
RPL_INVITING.re = (
    r"^:(?P<srv>\S+) 341 (?P<me>\S+) "
    r"(?P<channel>\S+) (?P<nick>\S+)")
RPL_INVITING.tpl = (
    ':{c.srv} 341 {c.nick} '
    '{channel} {nick}')
RPL_INVITING.params = ['srv', 'me', 'channel', 'nick']

RPL_SUMMONING = retcode(342)
RPL_SUMMONING.name = "RPL_SUMMONING"
RPL_SUMMONING.re = (
    r"^:(?P<srv>\S+) 342 (?P<me>\S+) "
    r"(?P<nick>\S+) :(?P<data>.*)")
RPL_SUMMONING.tpl = (
    ':{c.srv} 342 {c.nick} '
    '{nick} :Summoning user to IRC')
RPL_SUMMONING.params = ['srv', 'me', 'nick', 'data']

RPL_VERSION = retcode(351)
RPL_VERSION.name = "RPL_VERSION"
RPL_VERSION.re = (
    r"^:(?P<srv>\S+) 351 (?P<me>\S+) "
    r"(?P<version>\S+).(?P<debuglevel>\S+) "
    r"(?P<server>\S+) :(?P<data>.*)")
RPL_VERSION.tpl = (
    ':{c.srv} 351 {c.nick} '
    '{version}.{debuglevel} {server} :{comments}')
RPL_VERSION.params = ['srv', 'me', 'version', 'debuglevel', 'server', 'data']

RPL_WHOREPLY = retcode(352)
RPL_WHOREPLY.name = "RPL_WHOREPLY"
RPL_WHOREPLY.re = (
    r"^:(?P<srv>\S+) 352 (?P<me>\S+) "
    r"(?P<channel>\S+) (?P<username>\S+) (?P<host>\S+) "
    r"(?P<server>\S+) (?P<nick>\S+) (?P<modes>\S+) :(?P<data>.*)")
RPL_WHOREPLY.tpl = (
    ':{c.srv} 352 {c.nick} '
    ':{channel} {username} {host} {server} {nick} {modes} '
    ':{hopcount} {realname}')
RPL_WHOREPLY.params = [
    'srv',
    'me',
    'channel',
    'username',
    'host',
    'server',
    'nick',
    'modes',
    'data']

RPL_NAMREPLY = retcode(353)
RPL_NAMREPLY.name = "RPL_NAMREPLY"
RPL_NAMREPLY.re = (
    r"^:(?P<srv>\S+) 353 (?P<me>\S+) "
    r"(?P<m>\S+) (?P<channel>\S+) :(?P<data>.*)")
RPL_NAMREPLY.tpl = (
    ':{c.srv} 353 {c.nick} '
    '{m} {channel} :{nicknames}')
RPL_NAMREPLY.params = ['srv', 'me', 'm', 'channel', 'data']

RPL_LINKS = retcode(364)
RPL_LINKS.name = "RPL_LINKS"
RPL_LINKS.re = (
    r"^:(?P<srv>\S+) 364 (?P<me>\S+) "
    r"(?P<mask>\S+) "
    r"(?P<server>\S+) :(?P<data>.*)")
RPL_LINKS.tpl = (
    ':{c.srv} 364 {c.nick} '
    '{mask} {server} :{hopcount} {server_info}')
RPL_LINKS.params = ['srv', 'me', 'mask', 'server', 'data']

RPL_ENDOFLINKS = retcode(365)
RPL_ENDOFLINKS.name = "RPL_ENDOFLINKS"
RPL_ENDOFLINKS.re = (
    r"^:(?P<srv>\S+) 365 (?P<me>\S+) "
    r"(?P<mask>\S+) :(?P<data>.*)")
RPL_ENDOFLINKS.tpl = (
    ':{c.srv} 365 {c.nick} '
    '{mask} :End of /LINKS list')
RPL_ENDOFLINKS.params = ['srv', 'me', 'mask', 'data']

RPL_ENDOFNAMES = retcode(366)
RPL_ENDOFNAMES.name = "RPL_ENDOFNAMES"
RPL_ENDOFNAMES.re = (
    r"^:(?P<srv>\S+) 366 (?P<me>\S+) "
    r"(?P<channel>\S+) :(?P<data>.*)")
RPL_ENDOFNAMES.tpl = (
    ':{c.srv} 366 {c.nick} '
    '{channel} :End of /NAMES list')
RPL_ENDOFNAMES.params = ['srv', 'me', 'channel', 'data']

RPL_BANLIST = retcode(367)
RPL_BANLIST.name = "RPL_BANLIST"
RPL_BANLIST.re = (
    r"^:(?P<srv>\S+) 367 (?P<me>\S+) "
    r"(?P<channel>\S+) (?P<banid>\S+)")
RPL_BANLIST.tpl = (
    ':{c.srv} 367 {c.nick} '
    '{channel} {banid}')
RPL_BANLIST.params = ['srv', 'me', 'channel', 'banid']

RPL_ENDOFBANLIST = retcode(368)
RPL_ENDOFBANLIST.name = "RPL_ENDOFBANLIST"
RPL_ENDOFBANLIST.re = (
    r"^:(?P<srv>\S+) 368 (?P<me>\S+) "
    r"(?P<channel>\S+) :(?P<data>.*)")
RPL_ENDOFBANLIST.tpl = (
    ':{c.srv} 368 {c.nick} '
    '{channel} :End of channel ban list')
RPL_ENDOFBANLIST.params = ['srv', 'me', 'channel', 'data']

RPL_ENDOFWHOWAS = retcode(369)
RPL_ENDOFWHOWAS.name = "RPL_ENDOFWHOWAS"
RPL_ENDOFWHOWAS.re = (
    r"^:(?P<srv>\S+) 369 (?P<me>\S+) "
    r"(?P<nick>\S+) :(?P<data>.*)")
RPL_ENDOFWHOWAS.tpl = (
    ':{c.srv} 369 {c.nick} '
    '{nick} :End of WHOWAS')
RPL_ENDOFWHOWAS.params = ['srv', 'me', 'nick', 'data']

RPL_INFO = retcode(371)
RPL_INFO.name = "RPL_INFO"
RPL_INFO.re = (
    r"^:(?P<srv>\S+) 371 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_INFO.tpl = (
    ':{c.srv} 371 {c.nick} '
    ':{string}')
RPL_INFO.params = ['srv', 'me', 'data']

RPL_MOTD = retcode(372)
RPL_MOTD.name = "RPL_MOTD"
RPL_MOTD.re = (
    r"^:(?P<srv>\S+) 372 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_MOTD.tpl = (
    ':{c.srv} 372 {c.nick} '
    ':- {text}')
RPL_MOTD.params = ['srv', 'me', 'data']

RPL_ENDOFINFO = retcode(374)
RPL_ENDOFINFO.name = "RPL_ENDOFINFO"
RPL_ENDOFINFO.re = (
    r"^:(?P<srv>\S+) 374 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_ENDOFINFO.tpl = (
    ':{c.srv} 374 {c.nick} '
    ':End of /INFO list')
RPL_ENDOFINFO.params = ['srv', 'me', 'data']

RPL_MOTDSTART = retcode(375)
RPL_MOTDSTART.name = "RPL_MOTDSTART"
RPL_MOTDSTART.re = (
    r"^:(?P<srv>\S+) 375 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_MOTDSTART.tpl = (
    ':{c.srv} 375 {c.nick} '
    ':- {server} Message of the day -')
RPL_MOTDSTART.params = ['srv', 'me', 'data']

RPL_ENDOFMOTD = retcode(376)
RPL_ENDOFMOTD.name = "RPL_ENDOFMOTD"
RPL_ENDOFMOTD.re = (
    r"^:(?P<srv>\S+) 376 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_ENDOFMOTD.tpl = (
    ':{c.srv} 376 {c.nick} '
    ':End of /MOTD command')
RPL_ENDOFMOTD.params = ['srv', 'me', 'data']

RPL_YOUREOPER = retcode(381)
RPL_YOUREOPER.name = "RPL_YOUREOPER"
RPL_YOUREOPER.re = (
    r"^:(?P<srv>\S+) 381 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_YOUREOPER.tpl = (
    ':{c.srv} 381 {c.nick} '
    ':You are now an IRC operator')
RPL_YOUREOPER.params = ['srv', 'me', 'data']

RPL_REHASHING = retcode(382)
RPL_REHASHING.name = "RPL_REHASHING"
RPL_REHASHING.re = (
    r"^:(?P<srv>\S+) 382 (?P<me>\S+) "
    r"(?P<config_file>\S+) :(?P<data>.*)")
RPL_REHASHING.tpl = (
    ':{c.srv} 382 {c.nick} '
    '{config_file} :Rehashing')
RPL_REHASHING.params = ['srv', 'me', 'config_file', 'data']

RPL_TIME = retcode(391)
RPL_TIME.name = "RPL_TIME"
RPL_TIME.re = (
    r"^:(?P<srv>\S+) 391 (?P<me>\S+) "
    r"(?P<server>\S+) :(?P<data>.*)")
RPL_TIME.tpl = (
    ':{c.srv} 391 {c.nick} '
    "{server} :{string_showing_server's_local_time}")
RPL_TIME.params = ['srv', 'me', 'server', 'data']

RPL_USERSSTART = retcode(392)
RPL_USERSSTART.name = "RPL_USERSSTART"
RPL_USERSSTART.re = (
    r"^:(?P<srv>\S+) 392 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_USERSSTART.tpl = (
    ':{c.srv} 392 {c.nick} '
    ':UserID   Terminal  Host')
RPL_USERSSTART.params = ['srv', 'me', 'data']

RPL_USERS = retcode(393)
RPL_USERS.name = "RPL_USERS"
RPL_USERS.re = (
    r"^:(?P<srv>\S+) 393 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_USERS.tpl = (
    ':{c.srv} 393 {c.nick} '
    '{x} {y} {z}')
RPL_USERS.params = ['srv', 'me', 'data']

RPL_ENDOFUSERS = retcode(394)
RPL_ENDOFUSERS.name = "RPL_ENDOFUSERS"
RPL_ENDOFUSERS.re = (
    r"^:(?P<srv>\S+) 394 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_ENDOFUSERS.tpl = (
    ':{c.srv} 394 {c.nick} '
    ':End of users')
RPL_ENDOFUSERS.params = ['srv', 'me', 'data']

RPL_NOUSERS = retcode(395)
RPL_NOUSERS.name = "RPL_NOUSERS"
RPL_NOUSERS.re = (
    r"^:(?P<srv>\S+) 395 (?P<me>\S+) "
    r":(?P<data>.*)")
RPL_NOUSERS.tpl = (
    ':{c.srv} 395 {c.nick} '
    ':Nobody logged in')
RPL_NOUSERS.params = ['srv', 'me', 'data']

ERR_NOSUCHNICK = retcode(401)
ERR_NOSUCHNICK.name = "ERR_NOSUCHNICK"
ERR_NOSUCHNICK.re = (
    r"^:(?P<srv>\S+) 401 (?P<me>\S+) "
    r"(?P<nick>\S+) :(?P<data>.*)")
ERR_NOSUCHNICK.tpl = (
    ':{c.srv} 401 {c.nick} '
    '{nick} :No such nick/channel')
ERR_NOSUCHNICK.params = ['srv', 'me', 'nick', 'data']

ERR_NOSUCHSERVER = retcode(402)
ERR_NOSUCHSERVER.name = "ERR_NOSUCHSERVER"
ERR_NOSUCHSERVER.re = (
    r"^:(?P<srv>\S+) 402 (?P<me>\S+) "
    r"(?P<server>\S+) :(?P<data>.*)")
ERR_NOSUCHSERVER.tpl = (
    ':{c.srv} 402 {c.nick} '
    '{server} :No such server')
ERR_NOSUCHSERVER.params = ['srv', 'me', 'server', 'data']

ERR_NOSUCHCHANNEL = retcode(403)
ERR_NOSUCHCHANNEL.name = "ERR_NOSUCHCHANNEL"
ERR_NOSUCHCHANNEL.re = (
    r"^:(?P<srv>\S+) 403 (?P<me>\S+) "
    r"(?P<channel>\S+) :(?P<data>.*)")
ERR_NOSUCHCHANNEL.tpl = (
    ':{c.srv} 403 {c.nick} '
    '{channel} :No such channel')
ERR_NOSUCHCHANNEL.params = ['srv', 'me', 'channel', 'data']

ERR_CANNOTSENDTOCHAN = retcode(404)
ERR_CANNOTSENDTOCHAN.name = "ERR_CANNOTSENDTOCHAN"
ERR_CANNOTSENDTOCHAN.re = (
    r"^:(?P<srv>\S+) 404 (?P<me>\S+) "
    r"(?P<channel>\S+) :(?P<data>.*)")
ERR_CANNOTSENDTOCHAN.tpl = (
    ':{c.srv} 404 {c.nick} '
    '{channel} :Cannot send to channel')
ERR_CANNOTSENDTOCHAN.params = ['srv', 'me', 'channel', 'data']

ERR_TOOMANYCHANNELS = retcode(405)
ERR_TOOMANYCHANNELS.name = "ERR_TOOMANYCHANNELS"
ERR_TOOMANYCHANNELS.re = (
    r"^:(?P<srv>\S+) 405 (?P<me>\S+) "
    r"(?P<channel>\S+) :(?P<data>.*)")
ERR_TOOMANYCHANNELS.tpl = (
    ':{c.srv} 405 {c.nick} '
    '{channel} :You have joined too many channels')
ERR_TOOMANYCHANNELS.params = ['srv', 'me', 'channel', 'data']

ERR_WASNOSUCHNICK = retcode(406)
ERR_WASNOSUCHNICK.name = "ERR_WASNOSUCHNICK"
ERR_WASNOSUCHNICK.re = (
    r"^:(?P<srv>\S+) 406 (?P<me>\S+) "
    r"(?P<nick>\S+) :(?P<data>.*)")
ERR_WASNOSUCHNICK.tpl = (
    ':{c.srv} 406 {c.nick} '
    '{nick} :There was no such nickname')
ERR_WASNOSUCHNICK.params = ['srv', 'me', 'nick', 'data']

ERR_TOOMANYTARGETS = retcode(407)
ERR_TOOMANYTARGETS.name = "ERR_TOOMANYTARGETS"
ERR_TOOMANYTARGETS.re = (
    r"^:(?P<srv>\S+) 407 (?P<me>\S+) "
    r"(?P<target>\S+) :(?P<data>.*)")
ERR_TOOMANYTARGETS.tpl = (
    ':{c.srv} 407 {c.nick} '
    '{target} :Duplicate recipients. No message delivered')
ERR_TOOMANYTARGETS.params = ['srv', 'me', 'target', 'data']

ERR_NOORIGIN = retcode(409)
ERR_NOORIGIN.name = "ERR_NOORIGIN"
ERR_NOORIGIN.re = (
    r"^:(?P<srv>\S+) 409 (?P<me>\S+) "
    r":(?P<data>.*)")
ERR_NOORIGIN.tpl = (
    ':{c.srv} 409 {c.nick} '
    ':No origin specified')
ERR_NOORIGIN.params = ['srv', 'me', 'data']

ERR_NORECIPIENT = retcode(411)
ERR_NORECIPIENT.name = "ERR_NORECIPIENT"
ERR_NORECIPIENT.re = (
    r"^:(?P<srv>\S+) 411 (?P<me>\S+) "
    r":(?P<data>.*)")
ERR_NORECIPIENT.tpl = (
    ':{c.srv} 411 {c.nick} '
    ':No recipient given ({cmd})')
ERR_NORECIPIENT.params = ['srv', 'me', 'data']

ERR_NOTEXTTOSEND = retcode(412)
ERR_NOTEXTTOSEND.name = "ERR_NOTEXTTOSEND"
ERR_NOTEXTTOSEND.re = (
    r"^:(?P<srv>\S+) 412 (?P<me>\S+) "
    r":(?P<data>.*)")
ERR_NOTEXTTOSEND.tpl = (
    ':{c.srv} 412 {c.nick} '
    ':No text to send')
ERR_NOTEXTTOSEND.params = ['srv', 'me', 'data']

ERR_NOTOPLEVEL = retcode(413)
ERR_NOTOPLEVEL.name = "ERR_NOTOPLEVEL"
ERR_NOTOPLEVEL.re = (
    r"^:(?P<srv>\S+) 413 (?P<me>\S+) "
    r"(?P<mask>\S+) :(?P<data>.*)")
ERR_NOTOPLEVEL.tpl = (
    ':{c.srv} 413 {c.nick} '
    '{mask} :No toplevel domain specified')
ERR_NOTOPLEVEL.params = ['srv', 'me', 'mask', 'data']

ERR_WILDTOPLEVEL = retcode(414)
ERR_WILDTOPLEVEL.name = "ERR_WILDTOPLEVEL"
ERR_WILDTOPLEVEL.re = (
    r"^:(?P<srv>\S+) 414 (?P<me>\S+) "
    r"(?P<mask>\S+) :(?P<data>.*)")
ERR_WILDTOPLEVEL.tpl = (
    ':{c.srv} 414 {c.nick} '
    '{mask} :Wildcard in toplevel domain')
ERR_WILDTOPLEVEL.params = ['srv', 'me', 'mask', 'data']

ERR_UNKNOWNCOMMAND = retcode(421)
ERR_UNKNOWNCOMMAND.name = "ERR_UNKNOWNCOMMAND"
ERR_UNKNOWNCOMMAND.re = (
    r"^:(?P<srv>\S+) 421 (?P<me>\S+) "
    r"(?P<cmd>\S+) :(?P<data>.*)")
ERR_UNKNOWNCOMMAND.tpl = (
    ':{c.srv} 421 {c.nick} '
    '{cmd} :Unknown command')
ERR_UNKNOWNCOMMAND.params = ['srv', 'me', 'cmd', 'data']

ERR_NOMOTD = retcode(422)
ERR_NOMOTD.name = "ERR_NOMOTD"
ERR_NOMOTD.re = (
    r"^:(?P<srv>\S+) 422 (?P<me>\S+) "
    r":(?P<data>.*)")
ERR_NOMOTD.tpl = (
    ':{c.srv} 422 {c.nick} '
    ':MOTD File is missing')
ERR_NOMOTD.params = ['srv', 'me', 'data']

ERR_NOADMININFO = retcode(423)
ERR_NOADMININFO.name = "ERR_NOADMININFO"
ERR_NOADMININFO.re = (
    r"^:(?P<srv>\S+) 423 (?P<me>\S+) "
    r"(?P<server>\S+) :(?P<data>.*)")
ERR_NOADMININFO.tpl = (
    ':{c.srv} 423 {c.nick} '
    '{server} :No administrative info available')
ERR_NOADMININFO.params = ['srv', 'me', 'server', 'data']

ERR_NONICKNAMEGIVEN = retcode(431)
ERR_NONICKNAMEGIVEN.name = "ERR_NONICKNAMEGIVEN"
ERR_NONICKNAMEGIVEN.re = (
    r"^:(?P<srv>\S+) 431 (?P<me>\S+) "
    r":(?P<data>.*)")
ERR_NONICKNAMEGIVEN.tpl = (
    ':{c.srv} 431 {c.nick} '
    ':No nickname given')
ERR_NONICKNAMEGIVEN.params = ['srv', 'me', 'data']

ERR_ERRONEUSNICKNAME = retcode(432)
ERR_ERRONEUSNICKNAME.name = "ERR_ERRONEUSNICKNAME"
ERR_ERRONEUSNICKNAME.re = (
    r"^:(?P<srv>\S+) 432 (?P<me>\S+) "
    r"(?P<nick>\S+) :(?P<data>.*)")
ERR_ERRONEUSNICKNAME.tpl = (
    ':{c.srv} 432 {c.nick} '
    '{nick} :Erroneus nickname')
ERR_ERRONEUSNICKNAME.params = ['srv', 'me', 'nick', 'data']

ERR_NICKNAMEINUSE = retcode(433)
ERR_NICKNAMEINUSE.name = "ERR_NICKNAMEINUSE"
ERR_NICKNAMEINUSE.re = (
    r"^:(?P<srv>\S+) 433 (?P<me>\S+) "
    r"(?P<nick>\S+) :(?P<data>.*)")
ERR_NICKNAMEINUSE.tpl = (
    ':{c.srv} 433 {c.nick} '
    '{nick} :Nickname is already in use')
ERR_NICKNAMEINUSE.params = ['srv', 'me', 'nick', 'data']

ERR_NICKCOLLISION = retcode(436)
ERR_NICKCOLLISION.name = "ERR_NICKCOLLISION"
ERR_NICKCOLLISION.re = (
    r"^:(?P<srv>\S+) 436 (?P<me>\S+) "
    r"(?P<nick>\S+) :(?P<data>.*)")
ERR_NICKCOLLISION.tpl = (
    ':{c.srv} 436 {c.nick} '
    '{nick} :Nickname collision KILL')
ERR_NICKCOLLISION.params = ['srv', 'me', 'nick', 'data']

ERR_USERNOTINCHANNEL = retcode(441)
ERR_USERNOTINCHANNEL.name = "ERR_USERNOTINCHANNEL"
ERR_USERNOTINCHANNEL.re = (
    r"^:(?P<srv>\S+) 441 (?P<me>\S+) "
    r"(?P<nick>\S+) (?P<channel>\S+) :(?P<data>.*)")
ERR_USERNOTINCHANNEL.tpl = (
    ':{c.srv} 441 {c.nick} '
    "{nick} {channel} :They aren't on that channel")
ERR_USERNOTINCHANNEL.params = ['srv', 'me', 'nick', 'channel', 'data']

ERR_NOTONCHANNEL = retcode(442)
ERR_NOTONCHANNEL.name = "ERR_NOTONCHANNEL"
ERR_NOTONCHANNEL.re = (
    r"^:(?P<srv>\S+) 442 (?P<me>\S+) "
    r"(?P<channel>\S+) :(?P<data>.*)")
ERR_NOTONCHANNEL.tpl = (
    ':{c.srv} 442 {c.nick} '
    "{channel} :You're not on that channel")
ERR_NOTONCHANNEL.params = ['srv', 'me', 'channel', 'data']

ERR_USERONCHANNEL = retcode(443)
ERR_USERONCHANNEL.name = "ERR_USERONCHANNEL"
ERR_USERONCHANNEL.re = (
    r"^:(?P<srv>\S+) 443 (?P<me>\S+) "
    r"(?P<nick>\S+) (?P<channel>\S+) :(?P<data>.*)")
ERR_USERONCHANNEL.tpl = (
    ':{c.srv} 443 {c.nick} '
    '{nick} {channel} :is already on channel')
ERR_USERONCHANNEL.params = ['srv', 'me', 'nick', 'channel', 'data']

ERR_NOLOGIN = retcode(444)
ERR_NOLOGIN.name = "ERR_NOLOGIN"
ERR_NOLOGIN.re = (
    r"^:(?P<srv>\S+) 444 (?P<me>\S+) "
    r"(?P<nick>\S+) :(?P<data>.*)")
ERR_NOLOGIN.tpl = (
    ':{c.srv} 444 {c.nick} '
    '{nick} :User not logged in')
ERR_NOLOGIN.params = ['srv', 'me', 'nick', 'data']

ERR_SUMMONDISABLED = retcode(445)
ERR_SUMMONDISABLED.name = "ERR_SUMMONDISABLED"
ERR_SUMMONDISABLED.re = (
    r"^:(?P<srv>\S+) 445 (?P<me>\S+) "
    r":(?P<data>.*)")
ERR_SUMMONDISABLED.tpl = (
    ':{c.srv} 445 {c.nick} '
    ':SUMMON has been disabled')
ERR_SUMMONDISABLED.params = ['srv', 'me', 'data']

ERR_USERSDISABLED = retcode(446)
ERR_USERSDISABLED.name = "ERR_USERSDISABLED"
ERR_USERSDISABLED.re = (
    r"^:(?P<srv>\S+) 446 (?P<me>\S+) "
    r":(?P<data>.*)")
ERR_USERSDISABLED.tpl = (
    ':{c.srv} 446 {c.nick} '
    ':USERS has been disabled')
ERR_USERSDISABLED.params = ['srv', 'me', 'data']

ERR_NOTREGISTERED = retcode(451)
ERR_NOTREGISTERED.name = "ERR_NOTREGISTERED"
ERR_NOTREGISTERED.re = (
    r"^:(?P<srv>\S+) 451 (?P<me>\S+) "
    r":(?P<data>.*)")
ERR_NOTREGISTERED.tpl = (
    ':{c.srv} 451 {c.nick} '
    ':You have not registered')
ERR_NOTREGISTERED.params = ['srv', 'me', 'data']

ERR_NEEDMOREPARAMS = retcode(461)
ERR_NEEDMOREPARAMS.name = "ERR_NEEDMOREPARAMS"
ERR_NEEDMOREPARAMS.re = (
    r"^:(?P<srv>\S+) 461 (?P<me>\S+) "
    r"(?P<cmd>\S+) :(?P<data>.*)")
ERR_NEEDMOREPARAMS.tpl = (
    ':{c.srv} 461 {c.nick} '
    '{cmd} :Not enough parameters')
ERR_NEEDMOREPARAMS.params = ['srv', 'me', 'cmd', 'data']

ERR_ALREADYREGISTRED = retcode(462)
ERR_ALREADYREGISTRED.name = "ERR_ALREADYREGISTRED"
ERR_ALREADYREGISTRED.re = (
    r"^:(?P<srv>\S+) 462 (?P<me>\S+) "
    r":(?P<data>.*)")
ERR_ALREADYREGISTRED.tpl = (
    ':{c.srv} 462 {c.nick} '
    ':You may not reregister')
ERR_ALREADYREGISTRED.params = ['srv', 'me', 'data']

ERR_NOPERMFORHOST = retcode(463)
ERR_NOPERMFORHOST.name = "ERR_NOPERMFORHOST"
ERR_NOPERMFORHOST.re = (
    r"^:(?P<srv>\S+) 463 (?P<me>\S+) "
    r":(?P<data>.*)")
ERR_NOPERMFORHOST.tpl = (
    ':{c.srv} 463 {c.nick} '
    ":Your host isn't among the privileged")
ERR_NOPERMFORHOST.params = ['srv', 'me', 'data']

ERR_PASSWDMISMATCH = retcode(464)
ERR_PASSWDMISMATCH.name = "ERR_PASSWDMISMATCH"
ERR_PASSWDMISMATCH.re = (
    r"^:(?P<srv>\S+) 464 (?P<me>\S+) "
    r":(?P<data>.*)")
ERR_PASSWDMISMATCH.tpl = (
    ':{c.srv} 464 {c.nick} '
    ':Password incorrect')
ERR_PASSWDMISMATCH.params = ['srv', 'me', 'data']

ERR_YOUREBANNEDCREEP = retcode(465)
ERR_YOUREBANNEDCREEP.name = "ERR_YOUREBANNEDCREEP"
ERR_YOUREBANNEDCREEP.re = (
    r"^:(?P<srv>\S+) 465 (?P<me>\S+) "
    r":(?P<data>.*)")
ERR_YOUREBANNEDCREEP.tpl = (
    ':{c.srv} 465 {c.nick} '
    ':You are banned from this server')
ERR_YOUREBANNEDCREEP.params = ['srv', 'me', 'data']

ERR_KEYSET = retcode(467)
ERR_KEYSET.name = "ERR_KEYSET"
ERR_KEYSET.re = (
    r"^:(?P<srv>\S+) 467 (?P<me>\S+) "
    r"(?P<channel>\S+) :(?P<data>.*)")
ERR_KEYSET.tpl = (
    ':{c.srv} 467 {c.nick} '
    '{channel} :Channel key already set')
ERR_KEYSET.params = ['srv', 'me', 'channel', 'data']

ERR_CHANNELISFULL = retcode(471)
ERR_CHANNELISFULL.name = "ERR_CHANNELISFULL"
ERR_CHANNELISFULL.re = (
    r"^:(?P<srv>\S+) 471 (?P<me>\S+) "
    r"(?P<channel>\S+) :(?P<data>.*)")
ERR_CHANNELISFULL.tpl = (
    ':{c.srv} 471 {c.nick} '
    '{channel} :Cannot join channel (+l)')
ERR_CHANNELISFULL.params = ['srv', 'me', 'channel', 'data']

ERR_UNKNOWNMODE = retcode(472)
ERR_UNKNOWNMODE.name = "ERR_UNKNOWNMODE"
ERR_UNKNOWNMODE.re = (
    r"^:(?P<srv>\S+) 472 (?P<me>\S+) "
    r"(?P<char>\S+) :(?P<data>.*)")
ERR_UNKNOWNMODE.tpl = (
    ':{c.srv} 472 {c.nick} '
    '{char} :is unknown mode char to me')
ERR_UNKNOWNMODE.params = ['srv', 'me', 'char', 'data']

ERR_INVITEONLYCHAN = retcode(473)
ERR_INVITEONLYCHAN.name = "ERR_INVITEONLYCHAN"
ERR_INVITEONLYCHAN.re = (
    r"^:(?P<srv>\S+) 473 (?P<me>\S+) "
    r"(?P<channel>\S+) :(?P<data>.*)")
ERR_INVITEONLYCHAN.tpl = (
    ':{c.srv} 473 {c.nick} '
    '{channel} :Cannot join channel (+i)')
ERR_INVITEONLYCHAN.params = ['srv', 'me', 'channel', 'data']

ERR_BANNEDFROMCHAN = retcode(474)
ERR_BANNEDFROMCHAN.name = "ERR_BANNEDFROMCHAN"
ERR_BANNEDFROMCHAN.re = (
    r"^:(?P<srv>\S+) 474 (?P<me>\S+) "
    r"(?P<channel>\S+) :(?P<data>.*)")
ERR_BANNEDFROMCHAN.tpl = (
    ':{c.srv} 474 {c.nick} '
    '{channel} :Cannot join channel (+b)')
ERR_BANNEDFROMCHAN.params = ['srv', 'me', 'channel', 'data']

ERR_BADCHANNELKEY = retcode(475)
ERR_BADCHANNELKEY.name = "ERR_BADCHANNELKEY"
ERR_BADCHANNELKEY.re = (
    r"^:(?P<srv>\S+) 475 (?P<me>\S+) "
    r"(?P<channel>\S+) :(?P<data>.*)")
ERR_BADCHANNELKEY.tpl = (
    ':{c.srv} 475 {c.nick} '
    '{channel} :Cannot join channel (+k)')
ERR_BADCHANNELKEY.params = ['srv', 'me', 'channel', 'data']

ERR_NOPRIVILEGES = retcode(481)
ERR_NOPRIVILEGES.name = "ERR_NOPRIVILEGES"
ERR_NOPRIVILEGES.re = (
    r"^:(?P<srv>\S+) 481 (?P<me>\S+) "
    r":(?P<data>.*)")
ERR_NOPRIVILEGES.tpl = (
    ':{c.srv} 481 {c.nick} '
    ":Permission Denied- You're not an IRC operator")
ERR_NOPRIVILEGES.params = ['srv', 'me', 'data']

ERR_CHANOPRIVSNEEDED = retcode(482)
ERR_CHANOPRIVSNEEDED.name = "ERR_CHANOPRIVSNEEDED"
ERR_CHANOPRIVSNEEDED.re = (
    r"^:(?P<srv>\S+) 482 (?P<me>\S+) "
    r"(?P<channel>\S+) :(?P<data>.*)")
ERR_CHANOPRIVSNEEDED.tpl = (
    ':{c.srv} 482 {c.nick} '
    "{channel} :You're not channel operator")
ERR_CHANOPRIVSNEEDED.params = ['srv', 'me', 'channel', 'data']

ERR_CANTKILLSERVER = retcode(483)
ERR_CANTKILLSERVER.name = "ERR_CANTKILLSERVER"
ERR_CANTKILLSERVER.re = (
    r"^:(?P<srv>\S+) 483 (?P<me>\S+) "
    r":(?P<data>.*)")
ERR_CANTKILLSERVER.tpl = (
    ':{c.srv} 483 {c.nick} '
    ':You cant kill a server!')
ERR_CANTKILLSERVER.params = ['srv', 'me', 'data']

ERR_NOOPERHOST = retcode(491)
ERR_NOOPERHOST.name = "ERR_NOOPERHOST"
ERR_NOOPERHOST.re = (
    r"^:(?P<srv>\S+) 491 (?P<me>\S+) "
    r":(?P<data>.*)")
ERR_NOOPERHOST.tpl = (
    ':{c.srv} 491 {c.nick} '
    ':No O-lines for your host')
ERR_NOOPERHOST.params = ['srv', 'me', 'data']

ERR_UMODEUNKNOWNFLAG = retcode(501)
ERR_UMODEUNKNOWNFLAG.name = "ERR_UMODEUNKNOWNFLAG"
ERR_UMODEUNKNOWNFLAG.re = (
    r"^:(?P<srv>\S+) 501 (?P<me>\S+) "
    r":(?P<data>.*)")
ERR_UMODEUNKNOWNFLAG.tpl = (
    ':{c.srv} 501 {c.nick} '
    ':Unknown MODE flag')
ERR_UMODEUNKNOWNFLAG.params = ['srv', 'me', 'data']

ERR_USERSDONTMATCH = retcode(502)
ERR_USERSDONTMATCH.name = "ERR_USERSDONTMATCH"
ERR_USERSDONTMATCH.re = (
    r"^:(?P<srv>\S+) 502 (?P<me>\S+) "
    r":(?P<data>.*)")
ERR_USERSDONTMATCH.tpl = (
    ':{c.srv} 502 {c.nick} '
    ':Cant change mode for other users')
ERR_USERSDONTMATCH.params = ['srv', 'me', 'data']

RETCODES = {
    200: RPL_TRACELINK,
    201: RPL_TRACECONNECTING,
    202: RPL_TRACEHANDSHAKE,
    203: RPL_TRACEUNKNOWN,
    204: RPL_TRACEOPERATOR,
    205: RPL_TRACEUSER,
    206: RPL_TRACESERVER,
    208: RPL_TRACENEWTYPE,
    211: RPL_STATSLINKINFO,
    212: RPL_STATSCOMMANDS,
    213: RPL_STATSCLINE,
    214: RPL_STATSNLINE,
    215: RPL_STATSILINE,
    216: RPL_STATSKLINE,
    218: RPL_STATSYLINE,
    219: RPL_ENDOFSTATS,
    221: RPL_UMODEIS,
    241: RPL_STATSLLINE,
    242: RPL_STATSUPTIME,
    243: RPL_STATSOLINE,
    244: RPL_STATSHLINE,
    251: RPL_LUSERCLIENT,
    252: RPL_LUSEROP,
    253: RPL_LUSERUNKNOWN,
    254: RPL_LUSERCHANNELS,
    255: RPL_LUSERME,
    256: RPL_ADMINME,
    257: RPL_ADMINLOC1,
    258: RPL_ADMINLOC2,
    259: RPL_ADMINEMAIL,
    261: RPL_TRACELOG,
    301: RPL_AWAY,
    302: RPL_USERHOST,
    303: RPL_ISON,
    305: RPL_UNAWAY,
    306: RPL_NOWAWAY,
    311: RPL_WHOISUSER,
    312: RPL_WHOISSERVER,
    313: RPL_WHOISOPERATOR,
    314: RPL_WHOWASUSER,
    315: RPL_ENDOFWHO,
    317: RPL_WHOISIDLE,
    318: RPL_ENDOFWHOIS,
    319: RPL_WHOISCHANNELS,
    321: RPL_LISTSTART,
    322: RPL_LIST,
    323: RPL_LISTEND,
    324: RPL_CHANNELMODEIS,
    331: RPL_NOTOPIC,
    332: RPL_TOPIC,
    341: RPL_INVITING,
    342: RPL_SUMMONING,
    351: RPL_VERSION,
    352: RPL_WHOREPLY,
    353: RPL_NAMREPLY,
    364: RPL_LINKS,
    365: RPL_ENDOFLINKS,
    366: RPL_ENDOFNAMES,
    367: RPL_BANLIST,
    368: RPL_ENDOFBANLIST,
    369: RPL_ENDOFWHOWAS,
    371: RPL_INFO,
    372: RPL_MOTD,
    374: RPL_ENDOFINFO,
    375: RPL_MOTDSTART,
    376: RPL_ENDOFMOTD,
    381: RPL_YOUREOPER,
    382: RPL_REHASHING,
    391: RPL_TIME,
    392: RPL_USERSSTART,
    393: RPL_USERS,
    394: RPL_ENDOFUSERS,
    395: RPL_NOUSERS,
    401: ERR_NOSUCHNICK,
    402: ERR_NOSUCHSERVER,
    403: ERR_NOSUCHCHANNEL,
    404: ERR_CANNOTSENDTOCHAN,
    405: ERR_TOOMANYCHANNELS,
    406: ERR_WASNOSUCHNICK,
    407: ERR_TOOMANYTARGETS,
    409: ERR_NOORIGIN,
    411: ERR_NORECIPIENT,
    412: ERR_NOTEXTTOSEND,
    413: ERR_NOTOPLEVEL,
    414: ERR_WILDTOPLEVEL,
    421: ERR_UNKNOWNCOMMAND,
    422: ERR_NOMOTD,
    423: ERR_NOADMININFO,
    431: ERR_NONICKNAMEGIVEN,
    432: ERR_ERRONEUSNICKNAME,
    433: ERR_NICKNAMEINUSE,
    436: ERR_NICKCOLLISION,
    441: ERR_USERNOTINCHANNEL,
    442: ERR_NOTONCHANNEL,
    443: ERR_USERONCHANNEL,
    444: ERR_NOLOGIN,
    445: ERR_SUMMONDISABLED,
    446: ERR_USERSDISABLED,
    451: ERR_NOTREGISTERED,
    461: ERR_NEEDMOREPARAMS,
    462: ERR_ALREADYREGISTRED,
    463: ERR_NOPERMFORHOST,
    464: ERR_PASSWDMISMATCH,
    465: ERR_YOUREBANNEDCREEP,
    467: ERR_KEYSET,
    471: ERR_CHANNELISFULL,
    472: ERR_UNKNOWNMODE,
    473: ERR_INVITEONLYCHAN,
    474: ERR_BANNEDFROMCHAN,
    475: ERR_BADCHANNELKEY,
    481: ERR_NOPRIVILEGES,
    482: ERR_CHANOPRIVSNEEDED,
    483: ERR_CANTKILLSERVER,
    491: ERR_NOOPERHOST,
    501: ERR_UMODEUNKNOWNFLAG,
    502: ERR_USERSDONTMATCH,
}


================================================
FILE: irc3/asynchronous.py
================================================
# -*- coding: utf-8 -*-
from .compat import asyncio
import re


class event:

    iotype = 'in'
    iscoroutine = True

    def __init__(self, **kwargs):
        # kwargs get interpolated into the regex.
        # Any kwargs not ending in _re get escaped
        self.meta = kwargs.get('meta')
        regexp = self.meta['match'].format(**{
            k: v if k.endswith('_re') else re.escape(v)
            for (k, v) in kwargs.items()
            if k != 'meta'
        })
        self.regexp = regexp
        regexp = getattr(self.regexp, 're', self.regexp)
        self.cregexp = re.compile(regexp).match

    def compile(self, *args, **kwargs):
        return self.cregexp

    def __repr__(self):
        s = getattr(self.regexp, 'name', self.regexp)
        name = self.__class__.__name__
        return '<temp_event {0} {1}>'.format(name, s)

    def __call__(self, callback):
        async def wrapper(*args, **kwargs):
            return await callback(self, *args, **kwargs)
        self.callback = wrapper
        return self


def default_result_processor(self, results=None, **value):  # pragma: no cover
    value['results'] = results
    if len(results) == 1:
        value.update(results[0])
    return value


def async_events(context, events, send_line=None,
                 process_results=default_result_processor,
                 timeout=30, **params):

    loop = context.loop
    task = loop.create_future()  # async result
    results = []  # store events results
    events_ = []  # reference registered events

    # async timeout
    timeout = asyncio.ensure_future(
        asyncio.sleep(timeout, loop=loop), loop=loop)

    def end(t=None):
        """t can be a future (timeout done) or False (result success)"""
        if not task.done():
            # cancel timeout if needed
            if t is False:
                timeout.cancel()
            # detach events
            context.detach_events(*events_)
            # clean refs
            events_[:] = []
            # set results
            task.set_result(process_results(results=results, timeout=bool(t)))

    # end on timeout
    timeout.add_done_callback(end)

    async def callback(e, **kw):
        """common callback for all events"""
        results.append(kw)
        if e.meta.get('multi') is not True:
            context.detach_events(e)
            events_.remove(e)
        if e.meta.get('final') is True:
            # end on success
            end(False)

    events_.extend([event(meta=kw, **params)(callback) for kw in events])

    context.attach_events(*events_, insert=True)

    if send_line:
        context.send_line(send_line.format(**params))

    return task


class AsyncEvents:
    """Asynchronious events"""

    timeout = 30
    send_line = None
    events = []

    def __init__(self, context):
        self.context = context

    def process_results(self, results=None, **value):  # pragma: no cover
        """Process results.
        results is a list of dict catched during event.
        value is a dict containing some metadata (like timeout=(True/False).
        """
        return default_result_processor(results=results, **value)

    def __call__(self, **kwargs):
        """Register events; and callbacks then return a `asyncio.Future`.
        Events regexp are compiled with `params`"""
        kwargs.setdefault('timeout', self.timeout)
        kwargs.setdefault('send_line', self.send_line)
        kwargs['process_results'] = self.process_results
        return async_events(self.context, self.events, **kwargs)


================================================
FILE: irc3/base.py
================================================
# -*- coding: utf-8 -*-
import os
import sys
import ssl
import signal
import logging
import logging.config
from importlib import metadata
from . import utils
from . import config
from .compat import asyncio
from .compat import reload_module
from collections import defaultdict


version = metadata.version('irc3')


class Registry:
    """Store (and hide from api) plugins events and stuff"""

    def __init__(self):
        self.reset(reloading=False)

    def reset(self, reloading=True):
        self.events_re = {
            'in': [], 'out': [],
            'dcc_in': [], 'dcc_out': [],
        }
        self.events = {
            'in': defaultdict(list),
            'out': defaultdict(list),
            'dcc_in': defaultdict(list),
            'dcc_out': defaultdict(list),
        }

        self.scanned = []
        self.includes = set()

        if reloading:
            self.reloading = self.plugins.copy()
        else:
            self.reloading = {}
            self.plugins = {}

    def get_event_matches(self, data, iotype='in'):
        events = self.events[iotype]
        for regexp, cregexp in self.events_re[iotype]:
            match = cregexp(data)
            if match is not None:
                yield match, events[regexp]


class IrcObject:

    nick = None
    server = False
    plugin_category = '__irc3_plugin__'
    logging_config = config.LOGGING

    defaults = dict(
        port=6667,
        timeout=320,
        max_lag=60,
        asynchronous=True,
        max_length=512,
        testing=False,
        ssl=False,
        ssl_verify=False,
        encoding='utf8',
        loop=None,
    )

    def __init__(self, *ini, **config):
        config['version'] = version
        self.config = utils.Config(dict(self.defaults, *ini, **config))
        logging.config.dictConfig(self.logging_config)
        if self.server:
            self.log = logging.getLogger('irc3d')
        else:
            self.log = logging.getLogger('irc3.' + (self.nick or 'd'))
        self.original_nick = self.nick
        if config.get('verbose') or config.get('debug'):
            logging.getLogger('irc3').setLevel(logging.DEBUG)
            logging.getLogger('irc3d').setLevel(logging.DEBUG)
        else:
            level = config.get('level')
            if level is not None:
                level = getattr(logging, str(level), level)
                self.log.setLevel(level)
        self.encoding = self.config['encoding']

        self.loop = self.config.loop
        if self.loop is None:
            try:
                self.loop = asyncio.get_event_loop()
            except RuntimeError:
                self.loop = asyncio.new_event_loop()
                asyncio.set_event_loop(self.loop)

        self.create_task = self.loop.create_task

        self.registry = Registry()

        self.include(*self.config.get('includes', []))

    def get_plugin(self, ob):
        plugins = self.registry.plugins
        includes = self.registry.includes
        reloading = self.registry.reloading

        if isinstance(ob, str):
            ob_name = ob
            ob = utils.maybedotted(ob_name)
            if ob_name not in plugins:
                names = list(plugins)
                raise LookupError(
                    'Plugin %s not found in %s' % (ob_name, names))
        else:
            ob_name = ob.__module__ + '.' + ob.__name__
        if ob_name not in plugins:
            self.log.debug("Register plugin '%s'", ob_name)
            for dotted in getattr(ob, 'requires', []):
                if dotted not in includes:
                    self.include(dotted)
            plugins[ob_name] = ob(self)
        elif ob_name in reloading and hasattr(ob, 'reload'):
            instance = reloading.pop(ob_name)
            if instance.__class__ is not ob:
                self.log.debug("Reloading plugin '%s'", ob_name)
                plugins[ob_name] = ob.reload(instance)
        return plugins[ob_name]

    def recompile(self):
        events_re = self.registry.events_re
        for iotype in ('in', 'out'):
            events = self.registry.events[iotype]
            for i, (regexp, cregexp) in enumerate(events_re[iotype]):
                e = events[regexp][0]
                events_re[i] = (regexp, e.compile(self.config))

    def attach_events(self, *events, **kwargs):
        """Attach one or more events to the bot instance"""
        reg = self.registry
        insert = 'insert' in kwargs
        for e in events:
            cregexp = e.compile(self.config)
            regexp = getattr(e.regexp, 're', e.regexp)
            if regexp not in reg.events[e.iotype]:
                if insert:
                    reg.events_re[e.iotype].insert(0, (regexp, cregexp))
                else:
                    reg.events_re[e.iotype].append((regexp, cregexp))
            if insert:
                reg.events[e.iotype][regexp].insert(0, e)
            else:
                reg.events[e.iotype][regexp].append(e)

    def detach_events(self, *events):
        """Detach one or more events from the bot instance"""
        reg = self.registry
        delete = defaultdict(list)

        # remove from self.events
        all_events = reg.events
        for e in events:
            regexp = getattr(e.regexp, 're', e.regexp)
            iotype = e.iotype
            if e in all_events[iotype].get(regexp, []):
                all_events[iotype][regexp].remove(e)
                if not all_events[iotype][regexp]:
                    del all_events[iotype][regexp]
                    # need to delete from self.events_re
                    delete[iotype].append(regexp)

        # delete from events_re
        for iotype, regexps in delete.items():
            reg.events_re[iotype] = [r for r in reg.events_re[iotype]
                                     if r[0] not in regexps]

    def include(self, *modules, **kwargs):
        reg = self.registry
        categories = kwargs.get('venusian_categories',
                                self.venusian_categories)
        scanner = self.venusian.Scanner(context=self)
        for module in modules:
            if module in reg.includes:
                self.log.warning('%s included twice', module)
            else:
                reg.includes.add(module)
                try:
                    module = utils.maybedotted(module)
                except LookupError as exc:
                    try:
                        (module,) = metadata.entry_points(group='irc3.loader',
                                                          name=module)
                        module = module.load()
                    except (ImportError, ValueError):
                        raise exc
                # we have to manualy check for plugins. venusian no longer
                # support to attach both a class and methods
                for klass in list(module.__dict__.values()):
                    if not isinstance(klass, type):
                        continue
                    if klass.__module__ == module.__name__:
                        if getattr(klass, self.plugin_category, False) is True:
                            self.get_plugin(klass)
                reg.scanned.append((module.__name__, categories))
                scanner.scan(module, categories=categories)

    def reload(self, *modules):
        """Reload one or more plugins"""
        self.notify('before_reload')

        if 'configfiles' in self.config:
            # reload configfiles
            self.log.info('Reloading configuration...')
            cfg = utils.parse_config(
                self.server and 'server' or 'bot', *self.config['configfiles'])
            self.config.update(cfg)

        self.log.info('Reloading python code...')
        if not modules:
            modules = self.registry.includes
        scanned = list(reversed(self.registry.scanned))

        # reset includes and events
        self.registry.reset()

        to_scan = []
        for module_name, categories in scanned:
            if module_name in modules:
                module = utils.maybedotted(module_name)
                reload_module(module)
            to_scan.append((module_name, categories))

        # rescan all modules
        for module_name, categories in to_scan:
            self.include(module_name, venusian_categories=categories)

        self.registry.reloading = {}

        self.notify('after_reload')

    def notify(self, event, exc=None, client=None):
        for p in self.registry.plugins.values():
            meth = getattr(p, event, None)
            if meth is not None:
                if client is not None:
                    meth(client=client)
                else:
                    meth()

    def dispatch(self, data, iotype='in', client=None):
        str = utils.IrcString
        create_task = self.create_task
        call_soon = self.loop.call_soon
        for match, events in self.registry.get_event_matches(data, iotype):
            match = match.groupdict()
            for key, value in match.items():
                if value is not None:
                    match[key] = str(value)
            # backwards compatibility fix for IRCv3.2 tag support:
            # If no tags (None-value), exclude from dictionary
            if match.get("tags", True) is None:
                del match["tags"]
            if client is not None:
                # server / dcc chat
                match['client'] = client
            for e in events:
                if e.iscoroutine is True:
                    create_task(e.callback(**match))
                else:
                    call_soon(e.async_callback, match)

    def call_many(self, callback, args):
        """callback is run with each arg but run a call per second"""
        if isinstance(callback, str):
            callback = getattr(self, callback)
        f = None
        for arg in args:
            f = callback(*arg)
        return f

    def get_ssl_context(self):
        if self.config.ssl:  # pragma: no cover
            try:
                create_default_context = ssl.create_default_context
            except AttributeError:  # py < 2.7.9
                return True
            else:
                if self.server:
                    context = create_default_context(ssl.Purpose.CLIENT_AUTH)
                else:
                    context = create_default_context(ssl.Purpose.SERVER_AUTH)
                verify_mode = self.config.ssl_verify
                if verify_mode is not False:
                    if not isinstance(verify_mode, int):
                        # CERT_NONE / CERT_OPTIONAL / CERT_REQUIRED
                        verify_mode = getattr(ssl, verify_mode.upper())
                    if verify_mode == ssl.CERT_NONE:
                        context.check_hostname = False
                    context.verify_mode = verify_mode
                return context
        return None

    def create_connection(self):
        protocol = utils.maybedotted(self.config.connection)
        protocol = type(protocol.__name__, (protocol,), {'factory': self})
        if self.server:  # pragma: no cover
            self.log.debug('Starting {servername}...'.format(**self.config))
            factory = self.loop.create_server
        else:
            self.log.debug('Starting {nick}...'.format(**self.config))
            factory = self.loop.create_connection
        if self.config.get('sock_factory'):
            sock_factory = utils.maybedotted(self.config.sock_factory)
            args = dict(
                sock=sock_factory(self, self.config.host, self.config.port),
                ssl=self.get_ssl_context(),
            )
            if args.get('ssl'):
                args["server_hostname"] = self.config.host
        else:
            args = dict(
                host=self.config.host,
                port=self.config.port,
                ssl=self.get_ssl_context()
            )
            if self.config.get('vhost'):
                args["local_addr"] = (self.config.vhost, 0)
        t = asyncio.Task(factory(protocol, **args), loop=self.loop)
        t.add_done_callback(self.connection_made)
        return self.loop

    def add_signal_handlers(self):
        """Register handlers for UNIX signals (SIGHUP/SIGINT)"""
        try:
            self.loop.add_signal_handler(signal.SIGHUP, self.SIGHUP)
        except (RuntimeError, AttributeError):  # pragma: no cover
            # windows
            pass
        try:
            self.loop.add_signal_handler(signal.SIGINT, self.SIGINT)
        except (RuntimeError, NotImplementedError):  # pragma: no cover
            # annaconda
            pass

    def run(self, forever=True):
        """start the bot"""
        loop = self.create_connection()
        self.add_signal_handlers()
        if forever:
            loop.run_forever()

    @classmethod
    def from_config(cls, cfg, **kwargs):
        """return an instance configured with the ``cfg`` dict"""
        cfg = dict(cfg, **kwargs)
        pythonpath = cfg.get('pythonpath', [])
        if 'here' in cfg:
            pythonpath.append(cfg['here'])
        for path in pythonpath:
            sys.path.append(os.path.expanduser(path))
        prog = cls.server and 'irc3d' or 'irc3'
        if cfg.get('debug'):
            cls.venusian_categories.append(prog + '.debug')
        if cfg.get('interactive'):  # pragma: no cover
            import irc3.testing
            context = getattr(irc3.testing, cls.__name__)(**cfg)
        else:
            context = cls(**cfg)
        if cfg.get('raw'):
            context.include('irc3.plugins.log',
                            venusian_categories=[prog + '.debug'])
        return context

    @classmethod
    def from_argv(cls, argv=None, **kwargs):
        prog = cls.server and 'irc3d' or 'irc3'
        doc = """
        Run an {prog} instance from a config file

        Usage: {prog} [options] <config>...

        Options:

        -h, --help          Display this help and exit
        --version           Output version information and exit
        --logdir DIRECTORY  Log directory to use instead of stderr
        --logdate           Show datetimes in console output
        --host HOST         Server name or ip
        --port PORT         Server port
        -v,--verbose        Increase verbosity
        -r,--raw            Show raw irc log on the console
        -d,--debug          Add some debug commands/utils
        -i,--interactive    Load a ipython console with a bot instance
        """.format(prog=prog)
        if not cls.server:
            doc += """
            --help-page         Output a reST page containing commands help
            """.strip()
        import os
        import docopt
        import textwrap
        args = argv or sys.argv[1:]
        args = docopt.docopt(textwrap.dedent(doc), args, version=version)
        cfg = utils.parse_config(
            cls.server and 'server' or 'bot', *args['<config>'])
        cfg.update(
            verbose=args['--verbose'],
            debug=args['--debug'],
        )
        cfg.update(kwargs)
        if args['--host']:  # pragma: no cover
            host = args['--host']
            cfg['host'] = host
            if host in ('127.0.0.1', 'localhost'):
                cfg['ssl'] = False
        if args['--port']:  # pragma: no cover
            cfg['port'] = args['--port']
        if args['--logdir'] or 'logdir' in cfg:
            logdir = os.path.expanduser(args['--logdir'] or cfg.get('logdir'))
            cls.logging_config = config.get_file_config(logdir)
        if args['--logdate']:  # pragma: no cover
            fmt = cls.logging_config['formatters']['console']
            fmt['format'] = config.TIMESTAMPED_FMT
        if args.get('--help-page'):  # pragma: no cover
            for v in cls.logging_config['handlers'].values():
                v['level'] = 'ERROR'
        if args['--raw']:
            cfg['raw'] = True
        context = cls.from_config(cfg)
        if args.get('--help-page'):  # pragma: no cover
            context.print_help_page()
        elif args['--interactive']:  # pragma: no cover
            import IPython
            IPython.embed()
            sys.exit(0)
        else:
            context.run(forever=not bool(kwargs))
        if kwargs or argv:
            return context


================================================
FILE: irc3/compat.py
================================================
# -*- coding: utf-8 -*-
import sys
import types

PY37 = bool(sys.version_info[0:2] >= (3, 7))


try:  # pragma: no cover
    from importlib import reload as reload_module
except ImportError:  # pragma: no cover
    from imp import reload as reload_module  # NOQA

import asyncio
from asyncio.queues import Queue as BaseQueue
from asyncio.queues import QueueFull  # NOQA
from asyncio import sleep as _original_sleep
from asyncio import wait as _original_wait


def __sleep(*args, **kwargs):
    if PY37 and "loop" in kwargs:
        del kwargs["loop"]
    return _original_sleep(*args, **kwargs)


def __wait(*args, **kwargs):
    if PY37 and "loop" in kwargs:
        del kwargs["loop"]
    return _original_wait(*args, **kwargs)


asyncio.sleep = __sleep
asyncio.wait = __wait

class Queue(BaseQueue):
    def __init__(self, *args, **kwargs):
        if PY37 and "loop" in kwargs:
            del kwargs["loop"]

        super().__init__(*args, **kwargs)


================================================
FILE: ir
Download .txt
gitextract_t3elpfhu/

├── .coveragerc
├── .github/
│   └── workflows/
│       └── tox.yml
├── .gitignore
├── CHANGES.rst
├── CONTRIBUTING.rst
├── LICENSE
├── MANIFEST.in
├── Makefile
├── README.rst
├── conftest.py
├── docker/
│   ├── Dockerfile
│   └── Makefile
├── docs/
│   ├── Makefile
│   ├── conf.py
│   ├── dcc.rst
│   ├── dec.rst
│   ├── hack.rst
│   ├── index.rst
│   ├── irc3.rst
│   ├── plugins/
│   │   ├── asynchronious.rst
│   │   ├── autocommand.rst
│   │   ├── autojoins.rst
│   │   ├── casefold.rst
│   │   ├── command.rst
│   │   ├── core.rst
│   │   ├── cron.rst
│   │   ├── ctcp.rst
│   │   ├── dcc.rst
│   │   ├── feeds.rst
│   │   ├── fifo.rst
│   │   ├── human.rst
│   │   ├── log.rst
│   │   ├── logger.rst
│   │   ├── pager.rst
│   │   ├── quakenet.rst
│   │   ├── sasl.rst
│   │   ├── search.rst
│   │   ├── shell_command.rst
│   │   ├── slack.rst
│   │   ├── social.rst
│   │   ├── storage.rst
│   │   ├── uptime.rst
│   │   ├── userlist.rst
│   │   └── web.rst
│   ├── reloadable.rst
│   ├── rfc.rst
│   └── utils.rst
├── examples/
│   ├── async_command.py
│   ├── benches.ini
│   ├── benches.py
│   ├── bot.ini
│   ├── commands.rst
│   ├── config.ini
│   ├── dcc_chat.py
│   ├── dcc_send.py
│   ├── dcc_send_and_get.py
│   ├── dev.ini
│   ├── freenode_irc3.py
│   ├── humans.py
│   ├── mybot.py
│   ├── mybot_plugin.py
│   ├── mycommands.py
│   ├── mycrons.py
│   ├── myextends.py
│   ├── nickserv.py
│   ├── paginate.py
│   ├── proxy.py
│   ├── slack.ini
│   ├── spy.ini
│   ├── spy.py
│   ├── topic.py
│   └── wsgiapp.py
├── irc3/
│   ├── __init__.py
│   ├── __main__.py
│   ├── _gen_doc.py
│   ├── _parse_rfc.py
│   ├── _rfc.py
│   ├── asynchronous.py
│   ├── base.py
│   ├── compat.py
│   ├── config.py
│   ├── dcc/
│   │   ├── __init__.py
│   │   ├── client.py
│   │   └── manager.py
│   ├── dec.py
│   ├── plugins/
│   │   ├── __init__.py
│   │   ├── asynchronious.py
│   │   ├── autocommand.py
│   │   ├── autojoins.py
│   │   ├── casefold.py
│   │   ├── command.py
│   │   ├── core.py
│   │   ├── cron.py
│   │   ├── ctcp.py
│   │   ├── dcc.py
│   │   ├── feeds.py
│   │   ├── fifo.py
│   │   ├── human.py
│   │   ├── log.py
│   │   ├── logger.py
│   │   ├── pager.py
│   │   ├── quakenet.py
│   │   ├── sasl.py
│   │   ├── search.py
│   │   ├── shell_command.py
│   │   ├── slack.py
│   │   ├── social.py
│   │   ├── storage.py
│   │   ├── uptime.py
│   │   ├── userlist.py
│   │   └── web.py
│   ├── rfc.py
│   ├── rfc1459.txt
│   ├── rfc2812.txt
│   ├── tags.py
│   ├── template/
│   │   ├── __init__.py
│   │   ├── __main__.py
│   │   ├── config.ini
│   │   └── plugin.py
│   ├── testing.py
│   └── utils.py
├── irc3d/
│   ├── __init__.py
│   ├── __main__.py
│   ├── dec.py
│   ├── motd.txt
│   └── plugins/
│       ├── __init__.py
│       ├── command.py
│       ├── core.py
│       └── userlist.py
├── pyproject.toml
├── tests/
│   ├── __init__.py
│   ├── feed.atom
│   ├── test.ini
│   ├── test_async.py
│   ├── test_autocommand.py
│   ├── test_autojoins.py
│   ├── test_bot.py
│   ├── test_casefold.py
│   ├── test_commands.py
│   ├── test_cron.py
│   ├── test_ctcp.py
│   ├── test_dcc.py
│   ├── test_dec.py
│   ├── test_events.py
│   ├── test_feeds.py
│   ├── test_fifo.py
│   ├── test_irc3d.py
│   ├── test_irc3d_commands.py
│   ├── test_irc3d_userlist.py
│   ├── test_logger.py
│   ├── test_paginate.py
│   ├── test_protocol.py
│   ├── test_quakenet.py
│   ├── test_reconn.py
│   ├── test_reload.py
│   ├── test_run.py
│   ├── test_sasl.py
│   ├── test_search.py
│   ├── test_slack.py
│   ├── test_social.py
│   ├── test_template.py
│   ├── test_uptime.py
│   ├── test_userlist.py
│   ├── test_utils.py
│   └── test_web.py
└── tox.ini
Download .txt
SYMBOL INDEX (873 symbols across 99 files)

FILE: conftest.py
  function pytest_runtest_setup (line 15) | def pytest_runtest_setup(item):
  function cls_event_loop (line 25) | def cls_event_loop(request, event_loop):
  function irc3_bot_factory (line 33) | def irc3_bot_factory(request, event_loop):

FILE: examples/async_command.py
  class AsyncCommands (line 8) | class AsyncCommands(object):
    method __init__ (line 17) | def __init__(self, bot):
    method put (line 22) | def put(self, mask, target, args):
    method get (line 32) | async def get(self, mask, target, args):

FILE: examples/benches.py
  class Plugin (line 9) | class Plugin(object):
    method __init__ (line 11) | def __init__(self, context):
    method connected (line 18) | def connected(self, **kw):
    method msg (line 21) | def msg(self):
    method join (line 29) | def join(self, mask=None, **kw):
  function main (line 35) | def main():

FILE: examples/dcc_chat.py
  class Plugin (line 8) | class Plugin(object):
    method __init__ (line 10) | def __init__(self, context):
    method connected (line 15) | def connected(self, **kw):
    method join (line 19) | async def join(self, mask=None, **kw):
    method on_ctcp (line 31) | async def on_ctcp(self, mask=None, **kwargs):
    method on_dcc (line 47) | def on_dcc(self, client=None, data=None):
  function main (line 52) | def main():

FILE: examples/dcc_send.py
  class DCC (line 10) | class DCC(object):
    method __init__ (line 14) | def __init__(self, bot):
    method send (line 23) | async def send(self, mask, target, args):

FILE: examples/dcc_send_and_get.py
  class Plugin (line 8) | class Plugin(object):
    method __init__ (line 10) | def __init__(self, context):
    method connected (line 15) | def connected(self, **kw):
    method join (line 19) | async def join(self, mask=None, **kw):
    method on_ctcp (line 27) | async def on_ctcp(self, mask=None, **kwargs):
  function main (line 41) | def main():

FILE: examples/freenode_irc3.py
  class FeedsHook (line 6) | class FeedsHook(object):
    method __init__ (line 9) | def __init__(self, bot):
    method filter_travis (line 17) | def filter_travis(self, entry):
    method filter_pypi (line 36) | def filter_pypi(self, entry):
    method __call__ (line 42) | def __call__(self, entries):
  function auto_retweet (line 57) | def auto_retweet(bot):
  function test_cron (line 86) | def test_cron(bot):
  function test_cron_raise (line 91) | def test_cron_raise(bot):

FILE: examples/humans.py
  function greetings (line 7) | def greetings(bot, mask=None, channel=None, **kw):
  function main (line 12) | def main():

FILE: examples/mybot.py
  class MyPlugin (line 7) | class MyPlugin:
    method __init__ (line 18) | def __init__(self, bot):
    method connection_made (line 22) | def connection_made(self):
    method server_ready (line 25) | def server_ready(self):
    method connection_lost (line 28) | def connection_lost(self):
    method welcome (line 32) | def welcome(self, mask, channel, **kw):
    method echo (line 42) | def echo(self, mask, target, args):
    method stats (line 50) | def stats(self, mask, target, args):
    method my_usefull_method (line 68) | def my_usefull_method(self):
  function main (line 76) | def main():

FILE: examples/mybot_plugin.py
  class Plugin (line 7) | class Plugin:
    method __init__ (line 9) | def __init__(self, bot):
    method say_hi (line 13) | def say_hi(self, mask, channel, **kw):
    method echo (line 21) | def echo(self, mask, target, args):

FILE: examples/mycommands.py
  function echo (line 6) | def echo(bot, mask, target, args):
  function adduser (line 15) | def adduser(bot, mask, target, args):
  function my_secret_operation (line 24) | def my_secret_operation(bot, mask, target, args):

FILE: examples/mycrons.py
  function wakeup (line 6) | def wakeup(bot):
  function take_a_break (line 11) | def take_a_break(bot):

FILE: examples/myextends.py
  function my_usefull_function (line 6) | def my_usefull_function(bot, *args):
  class MyPlugin (line 11) | class MyPlugin(object):
    method __init__ (line 13) | def __init__(self, bot):
    method my_usefull_method (line 17) | def my_usefull_method(self, *args):

FILE: examples/nickserv.py
  function register (line 7) | def register(bot, ns=None, nick=None, **kw):

FILE: examples/paginate.py
  class SendFile (line 8) | class SendFile(object):
    method __init__ (line 15) | def __init__(self, bot):
    method cat (line 19) | def cat(self, mask, target, args):
    method url (line 29) | def url(self, mask, target, args):

FILE: examples/proxy.py
  function sock_factory (line 6) | def sock_factory(bot, host, port):
  function main (line 13) | def main():

FILE: examples/spy.py
  class Plugin (line 6) | class Plugin(object):
    method __init__ (line 10) | def __init__(self, context):
    method connected (line 16) | def connected(self, **kw):
    method on_privmsg (line 27) | def on_privmsg(self, mask=None, data=None, **kw):

FILE: examples/topic.py
  class TopicPlugin (line 8) | class TopicPlugin:
    method __init__ (line 12) | def __init__(self, bot):
    method get_topic (line 17) | def get_topic(self, channel=None, data=None, **kwargs):
    method cron_topic (line 22) | async def cron_topic(self):
    method topic (line 28) | def topic(self, mask, target, args):
    method aiotopic (line 37) | async def aiotopic(self, mask, target, args):

FILE: examples/wsgiapp.py
  class Webapp (line 9) | class Webapp:
    method __init__ (line 13) | def __init__(self, bot):
    method wsgi (line 22) | def wsgi(self, environ, start_response):

FILE: irc3/__init__.py
  class IrcConnection (line 21) | class IrcConnection(asyncio.Protocol):
    method connection_made (line 24) | def connection_made(self, transport):
    method decode (line 29) | def decode(self, data):
    method data_received (line 34) | def data_received(self, data):
    method write (line 43) | def write(self, data):
    method connection_lost (line 50) | def connection_lost(self, exc):
    method close (line 61) | def close(self):
  class IrcBot (line 71) | class IrcBot(base.IrcObject):
    method __init__ (line 114) | def __init__(self, *ini, **config):
    method server_config (line 146) | def server_config(self):
    method connection_made (line 157) | def connection_made(self, f):  # pragma: no cover
    method send_line (line 180) | def send_line(self, data, nowait=False):
    method process_queue (line 191) | async def process_queue(self):
    method send (line 217) | def send(self, data):
    method _send (line 221) | def _send(self, data):
    method privmsg (line 225) | def privmsg(self, target, message, nowait=False):
    method action (line 246) | def action(self, target, message, nowait=False):
    method notice (line 250) | def notice(self, target, message, nowait=False):
    method ctcp (line 271) | def ctcp(self, target, message, nowait=False):
    method ctcp_reply (line 286) | def ctcp_reply(self, target, message, nowait=False):
    method mode (line 300) | def mode(self, target, *data):
    method join (line 304) | def join(self, target):
    method part (line 312) | def part(self, target, reason=None):
    method kick (line 318) | def kick(self, channel, target, reason=None):
    method invite (line 324) | def invite(self, target, channel):
    method topic (line 328) | def topic(self, channel, topic=None):
    method away (line 334) | def away(self, message=None):
    method unaway (line 341) | def unaway(self):
    method quit (line 345) | def quit(self, reason=None):
    method get_nick (line 353) | def get_nick(self):
    method set_nick (line 356) | def set_nick(self, nick):
    method ip (line 362) | def ip(self):
    method dcc (line 380) | def dcc(self):
    method dcc_chat (line 386) | async def dcc_chat(self, mask, host=None, port=None):
    method dcc_get (line 394) | async def dcc_get(self, mask, host, port, filepath, filesize=None):
    method dcc_send (line 403) | async def dcc_send(self, mask, filepath):
    method dcc_accept (line 410) | async def dcc_accept(self, mask, filepath, port, pos):
    method SIGHUP (line 416) | def SIGHUP(self):
    method SIGINT (line 419) | def SIGINT(self):
  function run (line 427) | def run(argv=None):

FILE: irc3/_gen_doc.py
  function render_attrs (line 7) | def render_attrs(title, attrs, out):
  function main (line 48) | def main():

FILE: irc3/_parse_rfc.py
  function main (line 10) | def main():

FILE: irc3/_rfc.py
  class retcode (line 1) | class retcode(int):

FILE: irc3/asynchronous.py
  class event (line 6) | class event:
    method __init__ (line 11) | def __init__(self, **kwargs):
    method compile (line 24) | def compile(self, *args, **kwargs):
    method __repr__ (line 27) | def __repr__(self):
    method __call__ (line 32) | def __call__(self, callback):
  function default_result_processor (line 39) | def default_result_processor(self, results=None, **value):  # pragma: no...
  function async_events (line 46) | def async_events(context, events, send_line=None,
  class AsyncEvents (line 95) | class AsyncEvents:
    method __init__ (line 102) | def __init__(self, context):
    method process_results (line 105) | def process_results(self, results=None, **value):  # pragma: no cover
    method __call__ (line 112) | def __call__(self, **kwargs):

FILE: irc3/base.py
  class Registry (line 19) | class Registry:
    method __init__ (line 22) | def __init__(self):
    method reset (line 25) | def reset(self, reloading=True):
    method get_event_matches (line 46) | def get_event_matches(self, data, iotype='in'):
  class IrcObject (line 54) | class IrcObject:
    method __init__ (line 74) | def __init__(self, *ini, **config):
    method get_plugin (line 107) | def get_plugin(self, ob):
    method recompile (line 134) | def recompile(self):
    method attach_events (line 142) | def attach_events(self, *events, **kwargs):
    method detach_events (line 159) | def detach_events(self, *events):
    method include (line 181) | def include(self, *modules, **kwargs):
    method reload (line 211) | def reload(self, *modules):
    method notify (line 245) | def notify(self, event, exc=None, client=None):
    method dispatch (line 254) | def dispatch(self, data, iotype='in', client=None):
    method call_many (line 276) | def call_many(self, callback, args):
    method get_ssl_context (line 285) | def get_ssl_context(self):
    method create_connection (line 307) | def create_connection(self):
    method add_signal_handlers (line 336) | def add_signal_handlers(self):
    method run (line 349) | def run(self, forever=True):
    method from_config (line 357) | def from_config(cls, cfg, **kwargs):
    method from_argv (line 379) | def from_argv(cls, argv=None, **kwargs):

FILE: irc3/compat.py
  function __sleep (line 20) | def __sleep(*args, **kwargs):
  function __wait (line 26) | def __wait(*args, **kwargs):
  class Queue (line 35) | class Queue(BaseQueue):
    method __init__ (line 36) | def __init__(self, *args, **kwargs):

FILE: irc3/config.py
  function get_file_config (line 84) | def get_file_config(logdir='~/.irc3/logs'):

FILE: irc3/dcc/client.py
  class DCCBase (line 9) | class DCCBase(asyncio.Protocol):
    method __init__ (line 15) | def __init__(self, **kwargs):
    method factory (line 23) | def factory(self):
    method connection_made (line 26) | def connection_made(self, transport):
    method connection_lost (line 30) | def connection_lost(self, exc):
    method close (line 33) | def close(self, result=None):
    method set_timeout (line 46) | def set_timeout(self):
    method idle_timeout_reached (line 53) | def idle_timeout_reached(self, *args):
    method __str__ (line 59) | def __str__(self):
    method __repr__ (line 62) | def __repr__(self):
  class DCCChat (line 66) | class DCCChat(DCCBase):
    method connection_made (line 72) | def connection_made(self, transport):
    method decode (line 78) | def decode(self, data):
    method data_received (line 82) | def data_received(self, data):
    method write (line 93) | def write(self, data):
    method send_line (line 100) | def send_line(self, message):
    method send (line 104) | def send(self, *messages):
    method action (line 108) | def action(self, message):
    method actions (line 112) | def actions(self, *messages):
  class DCCGet (line 117) | class DCCGet(DCCBase):
    method connection_made (line 122) | def connection_made(self, transport):
    method data_received (line 130) | def data_received(self, data):
    method close (line 136) | def close(self, *args, **kwargs):
  class DCCSend (line 143) | class DCCSend(DCCBase):
    method connection_made (line 152) | def connection_made(self, transport):
    method write (line 173) | def write(self, *args):  # pragma: no cover
    method send_chunk (line 176) | def send_chunk(self):
    method next_chunk (line 181) | def next_chunk(self):
    method data_received (line 198) | def data_received(self, data):
    method close (line 207) | def close(self, *args, **kwargs):

FILE: irc3/dcc/manager.py
  class DCCManager (line 14) | class DCCManager:
    method __init__ (line 17) | def __init__(self, bot):
    method created (line 40) | def created(self, protocol, future):
    method create (line 59) | def create(self, name_or_class, mask, filepath=None, **kwargs):
    method resume (line 106) | def resume(self, mask, filename, port, pos):
    method is_allowed (line 112) | def is_allowed(self, name_or_class, mask):  # pragma: no cover

FILE: irc3/dec.py
  function plugin (line 8) | def plugin(wrapped):
  class event (line 15) | class event:
    method __init__ (line 39) | def __init__(self, regexp, callback=None, iotype='in',
    method async_callback (line 57) | def async_callback(self, kwargs):  # pragma: no cover
    method compile (line 60) | def compile(self, config):
    method __call__ (line 66) | def __call__(self, func):
    method __repr__ (line 83) | def __repr__(self):
  function dcc_event (line 89) | def dcc_event(regexp, callback=None, iotype='in',
  function extend (line 96) | def extend(func):

FILE: irc3/plugins/asynchronious.py
  class Whois (line 67) | class Whois(AsyncEvents):
    method process_results (line 94) | def process_results(self, results=None, **value):
  class WhoChannel (line 105) | class WhoChannel(AsyncEvents):
    method process_results (line 118) | def process_results(self, results=None, **value):
  class WhoChannelFlags (line 132) | class WhoChannelFlags(AsyncEvents):
    method process_results (line 151) | def process_results(self, results=None, **value):
  class WhoNick (line 166) | class WhoNick(AsyncEvents):
    method process_results (line 178) | def process_results(self, results=None, **value):
  class IsOn (line 188) | class IsOn(AsyncEvents):
    method process_results (line 195) | def process_results(self, results=None, **value):
  class Topic (line 203) | class Topic(AsyncEvents):
    method process_results (line 213) | def process_results(self, results=None, **value):
  class Names (line 223) | class Names(AsyncEvents):
    method process_results (line 234) | def process_results(self, results=None, **value):
  class ChannelBans (line 243) | class ChannelBans(AsyncEvents):
    method process_results (line 255) | def process_results(self, results=None, **value):
  class CTCP (line 267) | class CTCP(AsyncEvents):
    method process_results (line 279) | def process_results(self, results=None, **value):
  class Async (line 290) | class Async:
    method __init__ (line 296) | def __init__(self, context):
    method async_who_channel_flags (line 308) | def async_who_channel_flags(self, channel, flags, timeout):
    method whois (line 330) | def whois(self, nick, timeout=20):
    method who (line 340) | def who(self, target, flags=None, timeout=20):
    method topic (line 361) | def topic(self, channel, topic=None, timeout=20):
    method ison (line 369) | def ison(self, *nicknames, **kwargs):
    method names (line 383) | def names(self, channel, timeout=20):
    method channel_bans (line 393) | def channel_bans(self, channel, timeout=20):
    method ctcp_async (line 402) | def ctcp_async(self, nick, ctcp, timeout=20):

FILE: irc3/plugins/autocommand.py
  class SimpleCommand (line 53) | class SimpleCommand:
    method __init__ (line 55) | def __init__(self, cmd):
    method execute (line 58) | async def execute(self, bot):
  class SleepCommand (line 63) | class SleepCommand:
    method __init__ (line 68) | def __init__(self, time):
    method is_match (line 75) | def is_match(cls, test_str):
    method parse (line 79) | def parse(cls, cmd_str):
    method execute (line 91) | async def execute(self, bot):
  class AutoCommand (line 96) | class AutoCommand:
    method __init__ (line 102) | def __init__(self, bot):
    method parse_command (line 108) | def parse_command(command):
    method server_ready (line 120) | def server_ready(self):
    method execute_commands (line 123) | async def execute_commands(self):

FILE: irc3/plugins/autojoins.py
  class AutoJoins (line 23) | class AutoJoins:
    method __init__ (line 29) | def __init__(self, bot):
    method reload (line 42) | def reload(cls, old):
    method before_reload (line 62) | def before_reload(self):  # pragma: no cover
    method stop_tasks (line 65) | def stop_tasks(self):  # pragma: no cover
    method connection_lost (line 74) | def connection_lost(self):  # pragma: no cover
    method server_ready (line 77) | def server_ready(self):
    method join (line 84) | def join(self, channel=None):
    method part (line 100) | def part(self, channel):
    method on_kick (line 108) | def on_kick(self, mask, channel, target, **kwargs):
    method on_err_join (line 118) | def on_err_join(self, channel, **kwargs):

FILE: irc3/plugins/casefold.py
  class Casefold (line 40) | class Casefold:
    method __init__ (line 42) | def __init__(self, bot):
    method recalculate_casemaps (line 49) | def recalculate_casemaps(self):
    method casefold (line 70) | def casefold(self, in_str):

FILE: irc3/plugins/command.py
  class free_policy (line 168) | class free_policy:
    method __init__ (line 170) | def __init__(self, bot):
    method __call__ (line 173) | def __call__(self, predicates, meth, client, target, args, **kwargs):
  class mask_based_policy (line 177) | class mask_based_policy:
    method __init__ (line 182) | def __init__(self, bot):
    method masks (line 188) | def masks(self):
    method has_permission (line 201) | def has_permission(self, mask, permission):
    method __call__ (line 213) | def __call__(self, predicates, meth, client, target, args, **kwargs):
  function attach_command (line 222) | def attach_command(func, depth=2, **predicates):
  function command (line 251) | def command(*func, **predicates):
  class Commands (line 264) | class Commands(dict):
    method __init__ (line 274) | def __init__(self, context):
    method split_command (line 302) | def split_command(self, data, use_shlex=None):
    method on_command (line 309) | def on_command(self, cmd, mask=None, target=None, client=None, **kw):
    method do_command (line 322) | def do_command(self, predicates, meth, client, target, data=None, **kw):
    method command_callback (line 387) | def command_callback(self, uid, to, msgs):
    method help (line 401) | def help(self, mask, target, args):
    method __repr__ (line 457) | def __repr__(self):
  class Done (line 461) | class Done:
    method done (line 463) | def done(self):
  function ping (line 468) | def ping(bot, mask, target, args):
  function quote (line 477) | def quote(bot, mask, target, args):
  function reconnect (line 488) | def reconnect(bot, mask, target, args):
  function print_help_page (line 498) | def print_help_page(bot, file=sys.stdout):

FILE: irc3/plugins/core.py
  class Core (line 24) | class Core:
    method __init__ (line 26) | def __init__(self, bot):
    method connection_made (line 39) | def connection_made(self, client=None):
    method connected (line 50) | def connected(self, **kwargs):
    method reconnect (line 64) | def reconnect(self):  # pragma: no cover
    method pong (line 74) | def pong(self, event='PONG', data='', **kw):  # pragma: no cover
    method ping (line 88) | def ping(self, data):
    method recompile (line 94) | def recompile(self, nick=None, new_nick=None, **kw):
    method badnick (line 101) | def badnick(self, me=None, nick=None, **kw):
    method set_config (line 109) | def set_config(self, data=None, **kwargs):

FILE: irc3/plugins/cron.py
  class Crons (line 34) | class Crons(list):
    method __init__ (line 36) | def __init__(self, context):
    method connection_made (line 43) | def connection_made(self):
    method before_reload (line 47) | def before_reload(self):
    method after_reload (line 51) | def after_reload(self):
    method add_cron (line 55) | def add_cron(self, cronline, callback, uuid=None):
    method remove_cron (line 64) | def remove_cron(self, cron=None):
    method start (line 68) | def start(self):
    method stop (line 73) | def stop(self):
    method __repr__ (line 79) | def __repr__(self):
  function cron (line 83) | def cron(cronline, venusian_category='irc3.plugins.cron'):

FILE: irc3/plugins/ctcp.py
  class CTCP (line 36) | class CTCP:
    method __init__ (line 39) | def __init__(self, bot):
    method clear_queue (line 47) | def clear_queue(self):
    method handle_flood (line 53) | def handle_flood(self):
    method on_ctcp (line 60) | def on_ctcp(self, mask=None, target=None, ctcp=None, **kw):

FILE: irc3/plugins/dcc.py
  function dcc_command (line 39) | def dcc_command(*func, **predicates):
  class Commands (line 54) | class Commands(command.Commands):
    method on_command (line 61) | def on_command(self, cmd, client=None, **kw):
    method help (line 67) | def help(self, *args):
    method chat (line 75) | def chat(self, mask, *args):

FILE: irc3/plugins/feeds.py
  function default_hook (line 73) | def default_hook(entries):
  function default_dispatcher (line 78) | def default_dispatcher(bot):  # pragma: no cover
  function fetch (line 85) | def fetch(args):
  function parse (line 103) | def parse(feedparser, args):
  class Feeds (line 146) | class Feeds:
    method __init__ (line 151) | def __init__(self, bot):
    method connection_made (line 208) | def connection_made(self):
    method imports (line 212) | def imports(self):
    method parse (line 228) | def parse(self, *args):
    method update_time (line 245) | def update_time(self, future):
    method update (line 251) | def update(self):

FILE: irc3/plugins/fifo.py
  class Fifo (line 50) | class Fifo:
    method __init__ (line 55) | def __init__(self, context):
    method read_fd (line 70) | def read_fd(cls, fd):  # pragma: no cover
    method handle_line (line 81) | def handle_line(self, line, channel):
    method data_received (line 94) | def data_received(self, data, channel):
    method watch_fd (line 117) | def watch_fd(self, fd, channel):
    method create_fifo (line 125) | def create_fifo(self, channel):
    method join (line 149) | def join(self, mask=None, channel=None, **kwargs):

FILE: irc3/plugins/human.py
  class Human (line 42) | class Human:
    method __init__ (line 48) | def __init__(self, bot):
    method initialize (line 60) | def initialize(self, amount):  # pragma: no cover
    method on_message (line 77) | def on_message(self, mask=None, event=None, target=None, data=None, **...
    method call_with_human_delay (line 98) | def call_with_human_delay(self, func, *args, **kwargs):

FILE: irc3/plugins/log.py
  class RawLog (line 22) | class RawLog:
    method __init__ (line 24) | def __init__(self, context):
    method debug_input (line 35) | def debug_input(self, raw=None, client=None, iotype='in', **kwargs):
    method debug_output (line 43) | def debug_output(self, raw=None, client=None, iotype='out', **kwargs):
    method log (line 46) | def log(self, raw, client=None, iotype=None):

FILE: irc3/plugins/logger.py
  class file_handler (line 33) | class file_handler:
    method __init__ (line 45) | def __init__(self, bot):
    method __call__ (line 57) | def __call__(self, event):
  class Logger (line 70) | class Logger:
    method __init__ (line 74) | def __init__(self, bot):
    method process (line 82) | def process(self, **kwargs):
    method on_input (line 89) | def on_input(self, mask, event, target=None, data=None, **kwargs):
    method on_output (line 96) | def on_output(self, event, target=None, data=None, **kwargs):
    method on_quit (line 102) | def on_quit(self, mask, event, channel=None, data=None, **kwargs):
    method on_topic (line 113) | def on_topic(self, srv=None, **kwargs):

FILE: irc3/plugins/pager.py
  class Page (line 24) | class Page:
    method __init__ (line 26) | def __init__(self, mask, iterator, first_page=4, lines_per_page=10):
    method get (line 35) | def get(self):
    method close (line 54) | def close(self):
  class Paginate (line 62) | class Paginate:
    method __init__ (line 67) | def __init__(self, context):
    method clean_old_pages (line 73) | async def clean_old_pages(self):  # pragma: no cover
    method paginate (line 87) | def paginate(self, mask, iterator, first_page=None, lines_per_page=10):
    method more (line 99) | def more(self, mask, target, args):

FILE: irc3/plugins/quakenet.py
  function get_digest (line 43) | def get_digest(digest):
  function challenge_auth (line 54) | def challenge_auth(username, password, challenge, lower, digest='sha256'):
  class QuakeNet (line 76) | class QuakeNet(object):
    method __init__ (line 83) | def __init__(self, bot):
    method server_ready (line 93) | def server_ready(self):
    method auth (line 96) | def auth(self):
    method after_auth (line 108) | def after_auth(self):
    method get_challenge (line 113) | def get_challenge(self, nick, challenge, **kwargs):

FILE: irc3/plugins/sasl.py
  class Sasl (line 29) | class Sasl:
    method __init__ (line 31) | def __init__(self, bot):
    method connection_ready (line 41) | def connection_ready(self, *args, **kwargs):
    method cap_ls (line 45) | def cap_ls(self, data=None, **kwargs):
    method cap_ack (line 51) | def cap_ack(self, **kwargs):
    method authenticate (line 54) | def authenticate(self, **kwargs):
    method cap_end (line 62) | def cap_end(self, **kwargs):

FILE: irc3/plugins/search.py
  class Search (line 14) | class Search:
    method __init__ (line 26) | def __init__(self, bot):
    method ddg (line 36) | def ddg(self, mask, target, args):

FILE: irc3/plugins/shell_command.py
  class Shell (line 69) | class Shell:
    method __init__ (line 73) | def __init__(self, context):
    method register_command (line 92) | def register_command(self, k, v, skey=None):
    method shell_command (line 108) | async def shell_command(self, command, mask, target, args, **kwargs):

FILE: irc3/plugins/slack.py
  class Slack (line 107) | class Slack:
    method __init__ (line 109) | def __init__(self, bot):
    method get_channel_by_id (line 150) | def get_channel_by_id(self, matchobj):
    method get_user_by_id (line 162) | def get_user_by_id(self, matchobj):
    method get_emoji (line 174) | def get_emoji(self, matchobj):
    method clean_channels (line 178) | def clean_channels(self):
    method api_call (line 182) | async def api_call(self, method, data=None):
    method server_ready (line 202) | def server_ready(self):
    method start (line 205) | async def start(self):
    method notify_restart (line 220) | async def notify_restart(self):
    method parse_text (line 235) | async def parse_text(self, message):
    method ping (line 242) | async def ping(self):
    method producer (line 259) | async def producer(self, put):
    method consumer (line 273) | async def consumer(self, get):
    method _handle_default (line 308) | async def _handle_default(self, msg):
    method _handle_me_message (line 318) | async def _handle_me_message(self, msg):
    method on_message (line 332) | async def on_message(self, target=None, nick=None, data=None, **kwargs):

FILE: irc3/plugins/social.py
  class TwitterAdapter (line 35) | class TwitterAdapter:
    method __init__ (line 37) | def __init__(self, bot, conn):
    method __getattr__ (line 42) | def __getattr__(self, attr):
    method format (line 45) | def format(self, item):
    method __call__ (line 49) | def __call__(self, meth, *args, **kwargs):
    method __repr__ (line 74) | def __repr__(self):
  class Social (line 79) | class Social:
    method __init__ (line 109) | def __init__(self, bot):
    method twitter_factory (line 119) | def twitter_factory(self, name, config):
    method get_social_connection (line 136) | def get_social_connection(self, id=None):
    method tweet (line 148) | def tweet(self, mask, target, args):
    method send_tweet (line 163) | def send_tweet(self, message, id=None):
    method retweet (line 180) | def retweet(self, mask, target, args):
    method search_tweets (line 204) | def search_tweets(self, q=None, **kwargs):

FILE: irc3/plugins/storage.py
  class Shelve (line 182) | class Shelve:
    method __init__ (line 184) | def __init__(self, uri=None, **kwargs):
    method set (line 188) | def set(self, key, value):
    method get (line 192) | def get(self, key):
    method delete (line 195) | def delete(self, key):
    method contains (line 199) | def contains(self, key):
    method sync (line 202) | def sync(self):
    method close (line 205) | def close(self):
  class JSON (line 209) | class JSON:
    method __init__ (line 211) | def __init__(self, uri=None, **kwargs):
    method set (line 219) | def set(self, key, value):
    method get (line 223) | def get(self, key):
    method delete (line 226) | def delete(self, key):
    method contains (line 230) | def contains(self, key):
    method sync (line 233) | def sync(self):
    method close (line 237) | def close(self):
  class Redis (line 241) | class Redis:
    method __init__ (line 243) | def __init__(self, uri=None, **kwargs):
    method set (line 250) | def set(self, key, value):
    method get (line 253) | def get(self, key):
    method delete (line 263) | def delete(self, key):
    method contains (line 266) | def contains(self, key):
    method flushdb (line 269) | def flushdb(self):
    method sync (line 272) | def sync(self):
    method close (line 275) | def close(self):
  class SQLite (line 279) | class SQLite:
    method __init__ (line 293) | def __init__(self, uri=None, **kwargs):
    method set (line 302) | def set(self, key, value):
    method get (line 310) | def get(self, key):
    method delete (line 324) | def delete(self, key):
    method contains (line 332) | def contains(self, key):
    method flushdb (line 343) | def flushdb(self):
    method sync (line 352) | def sync(self):
    method close (line 355) | def close(self):
  class Storage (line 360) | class Storage:
    method __init__ (line 371) | def __init__(self, context):
    method connection_ready (line 382) | async def connection_ready(self):
    method setdefault (line 387) | def setdefault(self, key_, **kwargs):
    method get (line 402) | def get(self, key_, default=None):
    method getlist (line 409) | def getlist(self, key_, default=None):
    method set (line 418) | def set(self, key_, **kwargs):
    method setlist (line 429) | def setlist(self, key_, value):
    method __setitem__ (line 436) | def __setitem__(self, key, value):
    method __getitem__ (line 447) | def __getitem__(self, key):
    method __delitem__ (line 458) | def __delitem__(self, key):
    method __contains__ (line 467) | def __contains__(self, key):
    method SIGINT (line 476) | def SIGINT(self):

FILE: irc3/plugins/uptime.py
  class Uptime (line 19) | class Uptime:
    method __init__ (line 25) | def __init__(self, bot):
    method connection_made (line 36) | def connection_made(self):
    method delta (line 39) | def delta(self, value):
    method uptime (line 48) | def uptime(self, mask, target, args):

FILE: irc3/plugins/userlist.py
  class Channel (line 42) | class Channel(set):
    method __init__ (line 61) | def __init__(self):
    method add (line 66) | def add(self, item, modes=''):
    method remove (line 71) | def remove(self, item):
    method __repr__ (line 80) | def __repr__(self):
  class Userlist (line 85) | class Userlist:
    method __init__ (line 87) | def __init__(self, context):
    method connection_lost (line 91) | def connection_lost(self, client=None):
    method broadcast (line 97) | def broadcast(self, *args, **kwargs):
    method on_join_part_quit (line 102) | def on_join_part_quit(self, mask=None, event=None, **kwargs):
    method on_kick (line 106) | def on_kick(self, mask=None, event=None, target=None, **kwargs):
    method join (line 109) | def join(self, nick, mask, client=None, **kwargs):
    method part (line 117) | def part(self, nick, mask=None, channel=None, client=None, **kwargs):
    method quit (line 128) | def quit(self, nick, mask, channel=None, client=None, **kwargs):
    method new_nick (line 141) | def new_nick(self, nick=None, new_nick=None, client=None, **kwargs):
    method names (line 159) | def names(self, channel=None, data=None, **kwargs):
    method who (line 170) | def who(self, channel=None, nick=None, username=None, server=None, **kw):
    method mode (line 177) | def mode(self, target=None, modes=None, data=None, client=None, **kw):
    method topic (line 208) | def topic(self, channel=None, data=None, client=None, **kwargs):

FILE: irc3/plugins/web.py
  class Web (line 42) | class Web:
    method __init__ (line 44) | def __init__(self, context):
    method server_ready (line 55) | def server_ready(self):
    method join (line 66) | def join(self, mask=None, channel=None, **kwargs):
    method handler (line 72) | async def handler(self, req):

FILE: irc3/rfc.py
  function _extract_params (line 8) | def _extract_params(regexp):
  class raw (line 17) | class raw(str):
    method new (line 24) | def new(cls, name, regexp, regexp_out=None):

FILE: irc3/tags.py
  function _unescape (line 41) | def _unescape(string):
  function _escape (line 47) | def _escape(string):
  function encode (line 53) | def encode(tags):
  function decode (line 87) | def decode(tagstring):

FILE: irc3/template/__init__.py
  function get_template (line 11) | def get_template(filename, **kwargs):
  function main (line 18) | def main(nick=None, user=None, dest=None):

FILE: irc3/template/plugin.py
  class Plugin (line 7) | class Plugin:
    method __init__ (line 9) | def __init__(self, bot):
    method say_hi (line 13) | def say_hi(self, mask, channel, **kw):
    method echo (line 21) | def echo(self, mask, target, args):

FILE: irc3/testing.py
  function ini2config (line 32) | def ini2config(data, type='bot', env=None):
  function call_later (line 43) | def call_later(i, func, *args):
  function call_soon (line 49) | def call_soon(func, *args):
  class IrcBot (line 54) | class IrcBot(irc3.IrcBot):
    method __init__ (line 56) | def __init__(self, **config):
    method check_required (line 75) | def check_required(self):  # pragma: no cover
    method test (line 84) | def test(self, data, show=True):
    method sent (line 91) | def sent(self):
  class IrcTestCase (line 97) | class IrcTestCase(TestCase):
    method patch_requests (line 101) | def patch_requests(self, **kwargs):
    method patch_asyncio (line 123) | def patch_asyncio(self):
  class BotTestCase (line 132) | class BotTestCase(IrcTestCase):
    method callFTU (line 136) | def callFTU(self, **config):
    method assertSent (line 142) | def assertSent(self, lines):
    method assertNothingSent (line 154) | def assertNothingSent(self):
    method reset_mock (line 159) | def reset_mock(self):
  class IrcClient (line 164) | class IrcClient(irc3d.IrcClient):
    method __init__ (line 166) | def __init__(self):
    method dispatch (line 169) | def dispatch(self, data):
    method write (line 173) | def write(self, data):
    method reset (line 177) | def reset(self, data=False):
  class IrcServer (line 183) | class IrcServer(irc3d.IrcServer):
    method __init__ (line 185) | def __init__(self, **config):
    method add_clients (line 196) | def add_clients(self, amount=2):
  class ServerTestCase (line 210) | class ServerTestCase(IrcTestCase):
    method callFTU (line 215) | def callFTU(self, clients=2, **config):
    method assertSent (line 222) | def assertSent(self, client, data, origin=None):
    method assertNotSent (line 227) | def assertNotSent(self, client, data, origin=None):

FILE: irc3/utils.py
  function slugify (line 13) | def slugify(value):
  class IrcString (line 24) | class IrcString(str):
    method nick (line 28) | def nick(self):
    method lnick (line 48) | def lnick(self):
    method host (line 61) | def host(self):
    method username (line 66) | def username(self):
    method hostname (line 82) | def hostname(self):
    method is_user (line 98) | def is_user(self):
    method is_channel (line 102) | def is_channel(self):
    method is_server (line 115) | def is_server(self):
    method is_nick (line 128) | def is_nick(self):
    method tagdict (line 139) | def tagdict(self):
  function split_message (line 161) | def split_message(message, max_bytes, encoding, prefix=''):
  class Config (line 216) | class Config(dict):
    method __getattr__ (line 226) | def __getattr__(self, attr):
  function parse_config_env (line 230) | def parse_config_env(env=None):
  function parse_config (line 261) | def parse_config(main_section, *filenames, **kwargs):
  function extract_config (line 307) | def extract_config(config, prefix):
  function as_list (line 318) | def as_list(value):
  function as_channel (line 343) | def as_channel(value):
  function parse_modes (line 360) | def parse_modes(modes, targets=None, noargs=''):
  function wraps_with_context (line 382) | def wraps_with_context(func, context):
  function maybedotted (line 393) | def maybedotted(name):
  class Handler (line 431) | class Handler(logging.Handler):
    method __init__ (line 433) | def __init__(self, bot, *targets):
    method yield_records (line 438) | def yield_records(self, record):
    method emit (line 443) | def emit(self, record):
  class Logger (line 447) | class Logger(logging.getLoggerClass()):
    method set_irc_targets (line 450) | def set_irc_targets(self, bot, *targets):

FILE: irc3d/__init__.py
  class IrcClient (line 17) | class IrcClient(asyncio.Protocol):
    method connection_made (line 20) | def connection_made(self, transport):
    method __getattr__ (line 37) | def __getattr__(self, attr):
    method get_nick (line 40) | def get_nick(self):
    method set_nick (line 43) | def set_nick(self, nick):
    method registered (line 51) | def registered(self):
    method decode (line 54) | def decode(self, data):  # pragma: no cover
    method data_received (line 59) | def data_received(self, data):  # pragma: no cover
    method fwrite (line 69) | def fwrite(self, messages, **kwargs):
    method write (line 77) | def write(self, data):
    method connection_lost (line 85) | def connection_lost(self, exc):
    method close (line 95) | def close(self):  # pragma: no cover
    method __str__ (line 104) | def __str__(self):
  class IrcServer (line 113) | class IrcServer(base.IrcObject):
    method __init__ (line 153) | def __init__(self, *args, **kwargs):
    method connection_made (line 157) | def connection_made(self, f):  # pragma: no cover
    method notice (line 168) | def notice(self, client, message):
    method SIGHUP (line 181) | def SIGHUP(self, *args):  # pragma: no cover
    method SIGINT (line 184) | def SIGINT(self, *args):  # pragma: no cover
  function run (line 188) | def run(argv=None):

FILE: irc3d/__main__.py
  function main (line 6) | def main():  # pragma: no cover

FILE: irc3d/dec.py
  function plugin (line 7) | def plugin(wrapped):
  class event (line 14) | class event(dec.event):
    method __init__ (line 17) | def __init__(self, regexp, *args, **kwargs):
  function extend (line 23) | def extend(func):

FILE: irc3d/plugins/command.py
  class server_policy (line 16) | class server_policy:
    method __init__ (line 18) | def __init__(self, context):
    method check_oper_credentials (line 22) | def check_oper_credentials(self, user, password):
    method __call__ (line 26) | def __call__(self, predicates, meth, client, target, args, **kwargs):
  function command (line 36) | def command(*func, **predicates):
  class ServerCommands (line 52) | class ServerCommands(Commands):
    method on_command (line 59) | def on_command(self, cmd, mask=None, target=None, client=None, **kw):
    method OPER (line 68) | def OPER(self, client=None, args=None, **kwargs):
    method HELP (line 89) | def HELP(self, client=None, args=None, **kwargs):

FILE: irc3d/plugins/core.py
  class Core (line 27) | class Core:
    method __init__ (line 34) | def __init__(self, context):
    method USER (line 38) | def USER(self, client, args=None):
    method register (line 51) | def register(self, client, **kwargs):
    method VERSION (line 64) | def VERSION(self, client, args=None):
    method MOTD (line 72) | def MOTD(self, client, args=None):
    method PING (line 92) | def PING(self, client, args):
    method DIE (line 100) | def DIE(self, client=None, args=None, **kwargs):
    method WALLOPS (line 109) | def WALLOPS(self, client=None, args=None, **kwargs):
    method AWAY (line 120) | def AWAY(self, client, args):

FILE: irc3d/plugins/userlist.py
  class ServerUserlist (line 24) | class ServerUserlist(userlist.Userlist):
    method connection_made (line 26) | def connection_made(self, client=None):
    method connection_lost (line 29) | def connection_lost(self, client=None):
    method get_client (line 37) | def get_client(self, nick_or_client):
    method broadcast (line 43) | def broadcast(self, client=None, clients=None, **kwargs):
    method ISON (line 52) | def ISON(self, client, args=None, **kwargs):
    method JOIN (line 63) | def JOIN(self, client, args=None, **kwargs):
    method PART (line 88) | def PART(self, client, args=None, **kwargs):
    method QUIT (line 111) | def QUIT(self, client, args=None, **kwargs):
    method KICK (line 129) | def KICK(self, client, args=None, **kwargs):
    method NICK (line 153) | def NICK(self, client, args=None, **kwargs):
    method PRIVMSG (line 180) | def PRIVMSG(self, client=None, args=None, event='PRIVMSG', **kwargs):
    method NOTICE (line 219) | def NOTICE(self, client=None, args=None, event='PRIVMSG', **kwargs):
    method mode (line 239) | def mode(self, target=None, **kw):
    method UMODE_i (line 267) | def UMODE_i(self, client, target, char, mode):
    method UMODE_w (line 271) | def UMODE_w(self, client, target, char, mode):
    method NAMES (line 275) | def NAMES(self, client=None, args=None, **kwargs):
    method WHOIS (line 298) | def WHOIS(self, client=None, args=None, **kwargs):

FILE: tests/test_async.py
  function test_whois_fail (line 6) | async def test_whois_fail(irc3_bot_factory):
  function test_whois_success (line 18) | async def test_whois_success(irc3_bot_factory):
  function test_whois_timeout (line 38) | async def test_whois_timeout(irc3_bot_factory):
  function test_who_channel (line 48) | async def test_who_channel(irc3_bot_factory):
  function test_who_channel_flags (line 64) | async def test_who_channel_flags(irc3_bot_factory):
  function test_who_nick (line 96) | async def test_who_nick(irc3_bot_factory):
  function test_topic (line 110) | async def test_topic(irc3_bot_factory):
  function test_no_topic (line 122) | async def test_no_topic(irc3_bot_factory):
  function test_ison (line 134) | async def test_ison(irc3_bot_factory):
  function test_names (line 146) | async def test_names(irc3_bot_factory):
  function test_channel_bans (line 163) | async def test_channel_bans(irc3_bot_factory):
  function test_ctcp (line 179) | async def test_ctcp(irc3_bot_factory):

FILE: tests/test_autocommand.py
  function mock (line 6) | async def mock(*args, **kwargs):
  class TestAutoCommand (line 10) | class TestAutoCommand(BotTestCase):
    method test_autocommand (line 14) | def test_autocommand(self):
    method test_autocommand_validation (line 30) | def test_autocommand_validation(self):

FILE: tests/test_autojoins.py
  class TestAutojoin (line 6) | class TestAutojoin(BotTestCase):
    method test_autojoin_without_diese (line 8) | def test_autojoin_without_diese(self):
    method test_nomotd_events_removed (line 18) | def test_nomotd_events_removed(self):
    method test_autojoin_nomotd (line 28) | def test_autojoin_nomotd(self):
    method test_autojoin (line 35) | def test_autojoin(self):
    method test_autojoin_delay (line 66) | def test_autojoin_delay(self):
    method test_autojoin_reload (line 73) | def test_autojoin_reload(self):

FILE: tests/test_bot.py
  class TestBot (line 8) | class TestBot(BotTestCase):
    method test_config (line 10) | def test_config(self):
    method test_include_twice (line 14) | def test_include_twice(self):
    method test_plugin (line 19) | def test_plugin(self):
    method test_join (line 29) | def test_join(self):
    method test_message (line 34) | def test_message(self):
    method test_long_message (line 43) | def test_long_message(self):
    method test_log (line 52) | def test_log(self):
    method test_logger (line 58) | def test_logger(self):
    method test_quote (line 75) | def test_quote(self):
    method test_ctcp (line 84) | def test_ctcp(self):
    method test_server_config (line 89) | def test_server_config(self):
    method test_ping (line 98) | def test_ping(self):
    method test_nick (line 104) | def test_nick(self):
    method test_mode (line 115) | def test_mode(self):
    method test_kick (line 120) | def test_kick(self):
    method test_part (line 127) | def test_part(self):
    method test_quit (line 134) | def test_quit(self):
    method test_SIGINT (line 142) | def test_SIGINT(self, sleep):
    method test_SIGHUP (line 148) | def test_SIGHUP(self):
    method test_pkg_resources_entry_points (line 152) | def test_pkg_resources_entry_points(self):
    method test_pkg_resources_entry_points_exception (line 158) | def test_pkg_resources_entry_points_exception(self):

FILE: tests/test_casefold.py
  class TestCasefold (line 5) | class TestCasefold(BotTestCase):
    method test_ascii (line 9) | def test_ascii(self):
    method test_rfc1459 (line 19) | def test_rfc1459(self):

FILE: tests/test_commands.py
  function cmd (line 21) | def cmd(bot, *args):
  function cmd_view (line 29) | def cmd_view(bot, *args):
  function cmd_arg (line 37) | def cmd_arg(bot, *args):
  class TestCommands (line 45) | class TestCommands(BotTestCase):
    method test_async_plugin (line 53) | def test_async_plugin(self):
    method test_help (line 66) | def test_help(self):
    method test_help_hides (line 78) | def test_help_hides(self):
    method test_help_with_url (line 90) | def test_help_with_url(self):
    method test_print_help (line 101) | def test_print_help(self):
    method test_command_char (line 111) | def test_command_char(self):
    method test_command_alias (line 120) | def test_command_alias(self):
    method test_weird_chars (line 131) | def test_weird_chars(self):
    method test_command_trailing_space (line 140) | def test_command_trailing_space(self):
    method test_command_argument_space (line 147) | def test_command_argument_space(self):
    method test_command_argument_shlex (line 156) | def test_command_argument_shlex(self):
    method test_command_argument_quiet (line 162) | def test_command_argument_quiet(self):
    method test_command_argument_quiet_shlex (line 168) | def test_command_argument_quiet_shlex(self):
    method test_private_command (line 174) | def test_private_command(self):
    method test_help_command (line 182) | def test_help_command(self):
    method test_help_command_with_bang (line 187) | def test_help_command_with_bang(self):
    method test_reconnect_command (line 192) | def test_reconnect_command(self):
    method test_antiflood (line 203) | def test_antiflood(self):
    method test_unicode (line 217) | def test_unicode(self):
    method test_invalid_arguments (line 222) | def test_invalid_arguments(self):
    method test_invalid_arguments_shlex (line 227) | def test_invalid_arguments_shlex(self):
    method test_command_case_insensitive (line 233) | def test_command_case_insensitive(self):
    method test_command_case_sensitive (line 238) | def test_command_case_sensitive(self):
    method test_permissions (line 243) | def test_permissions(self):

FILE: tests/test_cron.py
  class MyCron (line 9) | class MyCron:
    method __init__ (line 11) | def __init__(self, bot):
    method method (line 15) | def method(self):
  function function (line 20) | async def function(bot):
  class TestCron (line 24) | class TestCron(BotTestCase):
    method test_add_remove_cron (line 28) | def test_add_remove_cron(self):
    method test_connection_made (line 40) | def test_connection_made(self):
    method test_reload (line 48) | def test_reload(self):
    method test_callable (line 59) | def test_callable(self):

FILE: tests/test_ctcp.py
  class TestCTCP (line 6) | class TestCTCP(BotTestCase):
    method test_ctcp (line 12) | def test_ctcp(self):
    method test_ctcp_flood (line 17) | def test_ctcp_flood(self):

FILE: tests/test_dcc.py
  function get_extra_info (line 17) | def get_extra_info(*args):
  function log_in (line 22) | def log_in(bot, client=None, data=None):
  function log_out (line 27) | def log_out(bot, client=None, data=None):
  function syn (line 32) | def syn(bot, mask, client, args):
  function chat_ready (line 40) | def chat_ready(client):
  class TestChat (line 49) | class TestChat(BotTestCase):
    method callDCCFTU (line 56) | def callDCCFTU(self, *args, **kwargs):
    method created (line 63) | def created(self):
    method test_create (line 73) | def test_create(self):
  class DCCTestCase (line 92) | class DCCTestCase(BotTestCase):
    method callDCCFTU (line 96) | def callDCCFTU(self, *args, **kwargs):
    method createFiles (line 104) | def createFiles(self):
    method assertFileSent (line 112) | def assertFileSent(self):
  class TestSend (line 123) | class TestSend(DCCTestCase):
    method created (line 127) | def created(self, f):
    method test_create (line 134) | def test_create(self):
  class TestResume (line 147) | class TestResume(DCCTestCase):
    method created (line 151) | def created(self, f):
    method test_create (line 164) | def test_create(self):
  class TestSendWithLimit (line 177) | class TestSendWithLimit(DCCTestCase):
    method created (line 181) | def created(self, f):
    method test_create (line 188) | def test_create(self):

FILE: tests/test_dec.py
  class OldStyleClass (line 7) | class OldStyleClass:
    method __init__ (line 8) | def __init__(self, bot):
  class NewStyleClass (line 13) | class NewStyleClass:
    method __init__ (line 14) | def __init__(self, bot):
  class TestPlugin (line 18) | class TestPlugin(BotTestCase):
    method test_registration (line 20) | def test_registration(self):

FILE: tests/test_events.py
  function msg1 (line 8) | def msg1(bot, **kwargs):
  function msg2 (line 13) | def msg2(bot, **kwargs):
  function msg3 (line 18) | def msg3(bot, target=None, event=None, data=None):
  class TestEvents (line 23) | class TestEvents(BotTestCase):
    method test_event (line 25) | def test_event(self):
    method test_bad_event (line 31) | def test_bad_event(self):
    method test_not_include_twice (line 34) | def test_not_include_twice(self):
    method test_out_event (line 41) | def test_out_event(self):
    method test_async_event (line 50) | def test_async_event(self):

FILE: tests/test_feeds.py
  function hook (line 11) | def hook(entries):
  class Hook (line 15) | class Hook:
    method __init__ (line 17) | def __init__(self, bot):
    method __call__ (line 20) | def __call__(self, entries):
  class Dispatcher (line 24) | class Dispatcher:
    method __init__ (line 26) | def __init__(self, bot):
    method reset (line 30) | def reset(self):
    method __call__ (line 34) | def __call__(self, messages):
  class TestFeeds (line 38) | class TestFeeds(BotTestCase):
    method setUp (line 42) | def setUp(self):
    method callFTU (line 52) | def callFTU(self, **kwargs):
    method test_connection_made (line 68) | def test_connection_made(self):
    method test_feed (line 74) | def test_feed(self):
    method test_hooked_feed (line 88) | def test_hooked_feed(self):
    method test_hooked_feed_with_class (line 96) | def test_hooked_feed_with_class(self):

FILE: tests/test_fifo.py
  class TestFifo (line 6) | class TestFifo(BotTestCase):
    method test_fifo_fake_event_loop (line 13) | def test_fifo_fake_event_loop(self):

FILE: tests/test_irc3d.py
  function echo (line 7) | def echo(self):
  class TestServer (line 11) | class TestServer(testing.ServerTestCase):
    method test_mock (line 13) | def test_mock(self):
    method test_connection_lost (line 18) | def test_connection_lost(self):
    method test_log (line 23) | def test_log(self):
    method test_extend (line 28) | def test_extend(self):
    method test_unknow_command (line 33) | def test_unknow_command(self):
    method test_server_notice (line 39) | def test_server_notice(self):
    method test_broadcast (line 44) | def test_broadcast(self):
    method test_privmsg (line 48) | def test_privmsg(self):
    method test_motd (line 80) | def test_motd(self):
    method test_ping (line 89) | def test_ping(self):
    method test_away (line 94) | def test_away(self):
    method test_no_away (line 105) | def test_no_away(self):
    method test_die (line 112) | def test_die(self):

FILE: tests/test_irc3d_commands.py
  class TestCommands (line 5) | class TestCommands(testing.ServerTestCase):
    method test_not_registered (line 7) | def test_not_registered(self):
    method test_help (line 14) | def test_help(self):
    method test_help_cmd (line 27) | def test_help_cmd(self):
    method test_oper (line 35) | def test_oper(self):

FILE: tests/test_irc3d_userlist.py
  class TestServerUserList (line 6) | class TestServerUserList(testing.ServerTestCase):
    method test_ison (line 8) | def test_ison(self):
    method test_whois (line 16) | def test_whois(self):
    method test_whois_err (line 24) | def test_whois_err(self):
    method test_user_modes (line 30) | def test_user_modes(self):
    method test_userlist (line 42) | def test_userlist(self):

FILE: tests/test_logger.py
  class LoggerFileTestCase (line 9) | class LoggerFileTestCase(BotTestCase):
    method setUp (line 16) | def setUp(self):
    method test_logger (line 21) | def test_logger(self):

FILE: tests/test_paginate.py
  function to_page (line 7) | def to_page(bot, mask, *args):
  class TestPager (line 18) | class TestPager(BotTestCase):
    method test_cmd (line 24) | def test_cmd(self):

FILE: tests/test_protocol.py
  function irc_conn (line 8) | def irc_conn(request):
  function test_buffer (line 16) | def test_buffer(irc_conn):
  function test_no_buffer (line 21) | def test_no_buffer(irc_conn):
  function test_with_buffer (line 27) | def test_with_buffer(irc_conn):
  function test_write (line 38) | def test_write(irc_conn):

FILE: tests/test_quakenet.py
  class TestQuakenet (line 5) | class TestQuakenet(BotTestCase):
    method test_challenge (line 12) | def test_challenge(self):
    method test_simple_auth (line 43) | def test_simple_auth(self):
    method test_challenge_auth (line 49) | def test_challenge_auth(self):

FILE: tests/test_reconn.py
  class P (line 9) | class P:
    method __init__ (line 13) | def __init__(self, bot):
    method connection_made (line 16) | def connection_made(self, *args, **kwargs):
  function test_reconn (line 23) | async def test_reconn(irc3_bot_factory):

FILE: tests/test_reload.py
  class TestReload (line 51) | class TestReload(BotTestCase):
    method test_reload (line 53) | def test_reload(self):

FILE: tests/test_run.py
  class TestRun (line 11) | class TestRun(testing.BotTestCase):
    method setUp (line 13) | def setUp(self):
    method callFTU (line 22) | def callFTU(self, *args):
    method test_args_error (line 25) | def test_args_error(self):
    method test_logdir (line 28) | def test_logdir(self):
  class TestServerRun (line 35) | class TestServerRun(testing.ServerTestCase):
    method setUp (line 37) | def setUp(self):
    method callFTU (line 46) | def callFTU(self, *args):
    method test_args_error (line 49) | def test_args_error(self):
    method test_logdir (line 52) | def test_logdir(self):

FILE: tests/test_sasl.py
  class TestSasl (line 5) | class TestSasl(BotTestCase):
    method test_sasl_plain (line 7) | def test_sasl_plain(self):
    method test_no_sasl (line 19) | def test_no_sasl(self):

FILE: tests/test_search.py
  class TestSearch (line 5) | class TestSearch(BotTestCase):
    method test_ddg (line 9) | def test_ddg(self):
    method test_ddg_redirect (line 19) | def test_ddg_redirect(self):

FILE: tests/test_slack.py
  function test_simple_matches (line 8) | async def test_simple_matches(irc3_bot_factory):
  function test_channel_matches (line 24) | async def test_channel_matches(irc3_bot_factory):
  function test_user_matches (line 37) | async def test_user_matches(irc3_bot_factory):
  function test_emoji_matches (line 50) | async def test_emoji_matches(irc3_bot_factory):

FILE: tests/test_social.py
  class TestSocial (line 6) | class TestSocial(BotTestCase):
    method test_get_conn (line 13) | def test_get_conn(self):
    method test_conns (line 18) | def test_conns(self):
    method test_tweet (line 24) | def test_tweet(self, c):
    method test_tweet_fail (line 36) | def test_tweet_fail(self, c):
    method test_retweet (line 44) | def test_retweet(self, c):
    method test_retweet_fail (line 56) | def test_retweet_fail(self, c):
    method test_search (line 63) | def test_search(self, c):
    method test_search_raise (line 69) | def test_search_raise(self, c):

FILE: tests/test_template.py
  class Template (line 11) | class Template(BotTestCase):
    method setUp (line 13) | def setUp(self):
    method test_template (line 21) | def test_template(self):

FILE: tests/test_uptime.py
  class TestUptime (line 6) | class TestUptime(BotTestCase):
    method test_uptime (line 8) | def test_uptime(self):

FILE: tests/test_userlist.py
  class TestUserList (line 5) | class TestUserList(testing.BotTestCase):
    method test_userlist (line 7) | def test_userlist(self):

FILE: tests/test_utils.py
  function test_hash (line 12) | def test_hash():
  function test_config_env (line 31) | def test_config_env():
  class TestUtils (line 39) | class TestUtils(TestCase):
    method test_ircstring (line 41) | def test_ircstring(self):
    method test_maybedotted (line 63) | def test_maybedotted(self):
    method test_slugify (line 75) | def test_slugify(self):
  class TestConfig (line 81) | class TestConfig(TestCase):
    method test_config_env (line 83) | def test_config_env(self):
  class TestSplit (line 104) | class TestSplit(TestCase):
    method test_split_message (line 106) | def test_split_message(self):
    method test_split_message_long (line 137) | def test_split_message_long(self):
    method test_split_message_no_whitespace (line 200) | def test_split_message_no_whitespace(self):
    method test_split_message_byte_max_bytes_too_small (line 237) | def test_split_message_byte_max_bytes_too_small(self):

FILE: tests/test_web.py
  class Payload (line 7) | class Payload:
    method __init__ (line 9) | def __init__(self, data):
    method readany (line 12) | async def readany(self):
  function test_web_handler (line 19) | async def test_web_handler(
  function test_web_handler_post (line 32) | async def test_web_handler_post(
  function test_web_handler_post_auth (line 48) | async def test_web_handler_post_auth(
  function test_web_handler_404 (line 73) | async def test_web_handler_404(
Condensed preview — 166 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (803K chars).
[
  {
    "path": ".coveragerc",
    "chars": 552,
    "preview": "[run]\ninclude =\n    */irc3/*.py\n    */irc3/*/*.py\nomit =\n    conftest.py\n    .tox/*\n    tests/*\n    docs/conf.py\n    */e"
  },
  {
    "path": ".github/workflows/tox.yml",
    "chars": 905,
    "preview": "name: tox\n\non: [push, pull_request]\n\njobs:\n  flake8-and-docs:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: action"
  },
  {
    "path": ".gitignore",
    "chars": 342,
    "preview": "*~\n*.bck\nbin\nbuild\n_build\n.bzr\n.bzrignore\n.eggs\n.cache\n.chutifab\n.coverage\ncoverage*\ndevelop-eggs\ndist\ndownloads\n*.egg\n*"
  },
  {
    "path": "CHANGES.rst",
    "chars": 8379,
    "preview": "1.1.11 (unreleased)\n===================\n\n- Nothing changed yet.\n\n\n1.1.10 (2023-04-17)\n===================\n\n- fix `shell_"
  },
  {
    "path": "CONTRIBUTING.rst",
    "chars": 1248,
    "preview": "Contribute\n==========\n\nFirst, if you want to add a cool plugin, consider submit a pull request to the\n`irc3_plugins <htt"
  },
  {
    "path": "LICENSE",
    "chars": 1082,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2016 Gael Pasgrimaud\n\nPermission is hereby granted, free of charge, to any person o"
  },
  {
    "path": "MANIFEST.in",
    "chars": 370,
    "preview": "graft docs\nprune docs/_build\nprune .github/\ngraft examples\ngraft irc3\ngraft irc3d\ngraft tests\ninclude Makefile *.rst *.c"
  },
  {
    "path": "Makefile",
    "chars": 448,
    "preview": "APP:=$(shell basename `pwd`)\nHOSTNAME:=$(shell hostname)\nHOST:=amandine\nPYTHON?=$(HOME)/.venvs/py3/bin/python3\n\nbuild:\n\t"
  },
  {
    "path": "README.rst",
    "chars": 1483,
    "preview": "============================================================\nirc3. pluggable irc client library based on python's asynci"
  },
  {
    "path": "conftest.py",
    "chars": 1092,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3 import testing\nimport pytest\nimport sys\nimport os\n\ntry:\n    from redis.exceptions impo"
  },
  {
    "path": "docker/Dockerfile",
    "chars": 395,
    "preview": "FROM python:3.7\n\nRUN adduser --disabled-password --gecos '' irc3\n\nRUN echo build \\\n    && cd /usr/src && git clone https"
  },
  {
    "path": "docker/Makefile",
    "chars": 175,
    "preview": "build:\n\tdocker build --rm=true -f Dockerfile -t irc3:latest .\n\nrun:\n\tdocker run -v $(PWD)/../:/usr/src/bot -v $(HOME)/.i"
  },
  {
    "path": "docs/Makefile",
    "chars": 5563,
    "preview": "# Makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS    =\nSPHINXBUILD "
  },
  {
    "path": "docs/conf.py",
    "chars": 7816,
    "preview": "# -*- coding: utf-8 -*-\n#\n# irc3 documentation build configuration file, created by\n# sphinx-quickstart on Mon Nov 25 01"
  },
  {
    "path": "docs/dcc.rst",
    "chars": 446,
    "preview": "========================\n:mod:`irc3.dcc` DCC\n========================\n\nSee :func:`~irc3.IrcBot.dcc_chat`, :func:`~irc3.I"
  },
  {
    "path": "docs/dec.rst",
    "chars": 244,
    "preview": "============================\n:mod:`irc3.dec` decorators\n============================\n\n.. automodule:: irc3.dec\n\nplugin\n="
  },
  {
    "path": "docs/hack.rst",
    "chars": 33,
    "preview": ".. include:: ../CONTRIBUTING.rst\n"
  },
  {
    "path": "docs/index.rst",
    "chars": 1497,
    "preview": ".. include:: ../README.rst\n\nInstallation\n==============\n\nUsing pip::\n\n    $ pip install irc3\n\nQuick start\n===========\n\ni"
  },
  {
    "path": "docs/irc3.rst",
    "chars": 280,
    "preview": "\n============================\n:mod:`irc3` Irc bot\n============================\n\n.. automodule:: irc3\n\nIrcBot\n======\n\n.. "
  },
  {
    "path": "docs/plugins/asynchronious.rst",
    "chars": 44,
    "preview": ".. automodule:: irc3.plugins.asynchronious\n\n"
  },
  {
    "path": "docs/plugins/autocommand.rst",
    "chars": 42,
    "preview": ".. automodule:: irc3.plugins.autocommand\n\n"
  },
  {
    "path": "docs/plugins/autojoins.rst",
    "chars": 40,
    "preview": ".. automodule:: irc3.plugins.autojoins\n\n"
  },
  {
    "path": "docs/plugins/casefold.rst",
    "chars": 39,
    "preview": ".. automodule:: irc3.plugins.casefold\n\n"
  },
  {
    "path": "docs/plugins/command.rst",
    "chars": 38,
    "preview": ".. automodule:: irc3.plugins.command\n\n"
  },
  {
    "path": "docs/plugins/core.rst",
    "chars": 35,
    "preview": ".. automodule:: irc3.plugins.core\n\n"
  },
  {
    "path": "docs/plugins/cron.rst",
    "chars": 35,
    "preview": ".. automodule:: irc3.plugins.cron\n\n"
  },
  {
    "path": "docs/plugins/ctcp.rst",
    "chars": 35,
    "preview": ".. automodule:: irc3.plugins.ctcp\n\n"
  },
  {
    "path": "docs/plugins/dcc.rst",
    "chars": 34,
    "preview": ".. automodule:: irc3.plugins.dcc\n\n"
  },
  {
    "path": "docs/plugins/feeds.rst",
    "chars": 36,
    "preview": ".. automodule:: irc3.plugins.feeds\n\n"
  },
  {
    "path": "docs/plugins/fifo.rst",
    "chars": 35,
    "preview": ".. automodule:: irc3.plugins.fifo\n\n"
  },
  {
    "path": "docs/plugins/human.rst",
    "chars": 36,
    "preview": ".. automodule:: irc3.plugins.human\n\n"
  },
  {
    "path": "docs/plugins/log.rst",
    "chars": 34,
    "preview": ".. automodule:: irc3.plugins.log\n\n"
  },
  {
    "path": "docs/plugins/logger.rst",
    "chars": 37,
    "preview": ".. automodule:: irc3.plugins.logger\n\n"
  },
  {
    "path": "docs/plugins/pager.rst",
    "chars": 36,
    "preview": ".. automodule:: irc3.plugins.pager\n\n"
  },
  {
    "path": "docs/plugins/quakenet.rst",
    "chars": 39,
    "preview": ".. automodule:: irc3.plugins.quakenet\n\n"
  },
  {
    "path": "docs/plugins/sasl.rst",
    "chars": 35,
    "preview": ".. automodule:: irc3.plugins.sasl\n\n"
  },
  {
    "path": "docs/plugins/search.rst",
    "chars": 37,
    "preview": ".. automodule:: irc3.plugins.search\n\n"
  },
  {
    "path": "docs/plugins/shell_command.rst",
    "chars": 44,
    "preview": ".. automodule:: irc3.plugins.shell_command\n\n"
  },
  {
    "path": "docs/plugins/slack.rst",
    "chars": 36,
    "preview": ".. automodule:: irc3.plugins.slack\n\n"
  },
  {
    "path": "docs/plugins/social.rst",
    "chars": 37,
    "preview": ".. automodule:: irc3.plugins.social\n\n"
  },
  {
    "path": "docs/plugins/storage.rst",
    "chars": 38,
    "preview": ".. automodule:: irc3.plugins.storage\n\n"
  },
  {
    "path": "docs/plugins/uptime.rst",
    "chars": 37,
    "preview": ".. automodule:: irc3.plugins.uptime\n\n"
  },
  {
    "path": "docs/plugins/userlist.rst",
    "chars": 39,
    "preview": ".. automodule:: irc3.plugins.userlist\n\n"
  },
  {
    "path": "docs/plugins/web.rst",
    "chars": 34,
    "preview": ".. automodule:: irc3.plugins.web\n\n"
  },
  {
    "path": "docs/reloadable.rst",
    "chars": 1249,
    "preview": "Reloadable plugins\n==================\n\n.. note:: if you just want the bot to restart when you change a file during\n    d"
  },
  {
    "path": "docs/rfc.rst",
    "chars": 45232,
    "preview": "========================\n:mod:`irc3.rfc` RFC1459\n========================\n\nReplies (REPL)\n==============\n\n259 - RPL_ADMI"
  },
  {
    "path": "docs/utils.rst",
    "chars": 386,
    "preview": "========================\n:mod:`irc3.utils` Utils\n========================\n\n.. automodule:: irc3.utils\n\n.. autoclass:: Ir"
  },
  {
    "path": "examples/async_command.py",
    "chars": 1018,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.plugins.command import command\nfrom irc3.compat import Queue\nimport irc3\n\n\n@irc3.plugi"
  },
  {
    "path": "examples/benches.ini",
    "chars": 299,
    "preview": "[bot]\nnick = malkovitch\nusername = malkovitch\nhost = localhost\nport = 6667\nname = malkovitch\nuser = malkovitch\nrealname "
  },
  {
    "path": "examples/benches.py",
    "chars": 1361,
    "preview": "# -*- coding: utf-8 -*-\nimport random\nfrom irc3.compat import asyncio\nfrom irc3d import IrcServer\nimport irc3\n\n\n@irc3.pl"
  },
  {
    "path": "examples/bot.ini",
    "chars": 1394,
    "preview": "[bot]\nnick = irc3\nusername = irc3\n\nhost = irc.freenode.net\nport = 7000\nssl = true\n\nincludes =\n    irc3.plugins.core\n    "
  },
  {
    "path": "examples/commands.rst",
    "chars": 847,
    "preview": "===============================================\nAvailable Commands for irc3 at irc.freenode.net\n========================"
  },
  {
    "path": "examples/config.ini",
    "chars": 1295,
    "preview": "[bot]\nnick = mybot\nusername = mybot\n\nhost = localhost\nport = 6667\n\n# uncomment this if you want ssl support\n# ssl = true"
  },
  {
    "path": "examples/dcc_chat.py",
    "chars": 2542,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.compat import asyncio\nfrom irc3d import IrcServer\nimport irc3\n\n\n@irc3.plugin\nclass Plu"
  },
  {
    "path": "examples/dcc_send.py",
    "chars": 734,
    "preview": "# -*- coding: utf-8 -*-\nimport os\nimport string\nimport tempfile\nimport irc3\nfrom irc3.plugins.command import command\n\n\n@"
  },
  {
    "path": "examples/dcc_send_and_get.py",
    "chars": 2232,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.compat import asyncio\nfrom irc3d import IrcServer\nimport irc3\n\n\n@irc3.plugin\nclass Plu"
  },
  {
    "path": "examples/dev.ini",
    "chars": 1286,
    "preview": "[bot]\nnick = irc3_dev\nusername = irc3\nhost = irc.freenode.net\nport = 7000\nssl = true\nincludes =\n    irc3.plugins.core\n  "
  },
  {
    "path": "examples/freenode_irc3.py",
    "chars": 2912,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.plugins.cron import cron\nimport os\n\n\nclass FeedsHook(object):\n    \"\"\"Custom hook for i"
  },
  {
    "path": "examples/humans.py",
    "chars": 783,
    "preview": "# -*- coding: utf-8 -*-\nimport asyncio\nimport irc3\n\n\n@irc3.event(irc3.rfc.JOIN)\ndef greetings(bot, mask=None, channel=No"
  },
  {
    "path": "examples/mybot.py",
    "chars": 2488,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.plugins.command import command\nimport irc3\n\n\n@irc3.plugin\nclass MyPlugin:\n    \"\"\"A plu"
  },
  {
    "path": "examples/mybot_plugin.py",
    "chars": 617,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.plugins.command import command\nimport irc3\n\n\n@irc3.plugin\nclass Plugin:\n\n    def __ini"
  },
  {
    "path": "examples/mycommands.py",
    "chars": 598,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.plugins.command import command\n\n\n@command\ndef echo(bot, mask, target, args):\n    \"\"\"Ec"
  },
  {
    "path": "examples/mycrons.py",
    "chars": 249,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.plugins.cron import cron\n\n\n@cron('30 8 * * *')\ndef wakeup(bot):\n    bot.privmsg('#irc3"
  },
  {
    "path": "examples/myextends.py",
    "chars": 336,
    "preview": "# -*- coding: utf-8 -*-\nimport irc3\n\n\n@irc3.extend\ndef my_usefull_function(bot, *args):\n    return 'my_usefull_function("
  },
  {
    "path": "examples/nickserv.py",
    "chars": 390,
    "preview": "# -*- coding: utf-8 -*-\nimport irc3\n\n\n@irc3.event(r'(@(?P<tags>\\S+) )?:(?P<ns>NickServ)!NickServ@services.'\n            "
  },
  {
    "path": "examples/paginate.py",
    "chars": 885,
    "preview": "# -*- coding: utf-8 -*-\nimport irc3\nimport requests\nfrom irc3.plugins.command import command\n\n\n@irc3.plugin\nclass SendFi"
  },
  {
    "path": "examples/proxy.py",
    "chars": 342,
    "preview": "# -*- coding: utf-8 -*-\nimport socks\nimport irc3\n\n\ndef sock_factory(bot, host, port):\n    sock = socks.socksocket()\n    "
  },
  {
    "path": "examples/slack.ini",
    "chars": 338,
    "preview": "[bot]\nnick = <nick>\nhost = chat.freenode.net\nport = 6697\nssl = true\nsasl_username = <username>\nsasl_password = <password"
  },
  {
    "path": "examples/spy.ini",
    "chars": 187,
    "preview": "[bot]\nnick = spyer\nusername = spyer\nhost = localhost\nport = 6667\nchannel = gov\nincludes =\n    spy\n\n[bot_chater]\nnick = c"
  },
  {
    "path": "examples/spy.py",
    "chars": 876,
    "preview": "# -*- coding: utf-8 -*-\nimport irc3\n\n\n@irc3.plugin\nclass Plugin(object):\n\n    chater = None\n\n    def __init__(self, cont"
  },
  {
    "path": "examples/topic.py",
    "chars": 1253,
    "preview": "# -*- coding: utf-8 -*-\nimport irc3\nfrom irc3.plugins.command import command\nfrom irc3.plugins.cron import cron\n\n\n@irc3."
  },
  {
    "path": "examples/wsgiapp.py",
    "chars": 731,
    "preview": "# -*- coding: utf-8 -*-\nimport asyncio\nfrom aiohttp_wsgi import wsgi\nfrom irc3 import plugin\nimport json\n\n\n@plugin\nclass"
  },
  {
    "path": "irc3/__init__.py",
    "chars": 14742,
    "preview": "# -*- coding: utf-8 -*-\nfrom urllib.request import urlopen\nfrom ipaddress import ip_address\nfrom collections import dequ"
  },
  {
    "path": "irc3/__main__.py",
    "chars": 59,
    "preview": "from irc3 import run\n\nif __name__ == '__main__':\n    run()\n"
  },
  {
    "path": "irc3/_gen_doc.py",
    "chars": 2996,
    "preview": "# -*- coding: utf-8 -*-\nfrom . import rfc\nfrom . import template\nimport os\n\n\ndef render_attrs(title, attrs, out):\n    ou"
  },
  {
    "path": "irc3/_parse_rfc.py",
    "chars": 5552,
    "preview": "# -*- coding: utf-8 -*-\nfrom collections import defaultdict\nimport pprint\nimport re\n\n_re_num = re.compile(r'\\s(?P<num>\\d"
  },
  {
    "path": "irc3/_rfc.py",
    "chars": 39532,
    "preview": "class retcode(int):\n    name = None\n    re = None\n\n\nRPL_TRACELINK = retcode(200)\nRPL_TRACELINK.name = \"RPL_TRACELINK\"\nRP"
  },
  {
    "path": "irc3/asynchronous.py",
    "chars": 3560,
    "preview": "# -*- coding: utf-8 -*-\nfrom .compat import asyncio\nimport re\n\n\nclass event:\n\n    iotype = 'in'\n    iscoroutine = True\n\n"
  },
  {
    "path": "irc3/base.py",
    "chars": 16360,
    "preview": "# -*- coding: utf-8 -*-\nimport os\nimport sys\nimport ssl\nimport signal\nimport logging\nimport logging.config\nfrom importli"
  },
  {
    "path": "irc3/compat.py",
    "chars": 956,
    "preview": "# -*- coding: utf-8 -*-\nimport sys\nimport types\n\nPY37 = bool(sys.version_info[0:2] >= (3, 7))\n\n\ntry:  # pragma: no cover"
  },
  {
    "path": "irc3/config.py",
    "chars": 2983,
    "preview": "# -*- coding: utf-8 -*-\n\nTIMESTAMPED_FMT = '%(asctime)s %(levelname)-4s %(name)-10s %(message)s'\n\nLOGGING = {\n    'versi"
  },
  {
    "path": "irc3/dcc/__init__.py",
    "chars": 174,
    "preview": "# -*- coding: utf-8 -*-\nfrom .manager import DCCManager  # NOQA\nfrom .manager import DCCChat  # NOQA\nfrom .manager impor"
  },
  {
    "path": "irc3/dcc/client.py",
    "chars": 6560,
    "preview": "# -*- coding: utf-8 -*-\nimport os\nimport struct\nfrom collections import deque\nfrom functools import partial\nfrom irc3.co"
  },
  {
    "path": "irc3/dcc/manager.py",
    "chars": 5449,
    "preview": "# -*- coding: utf-8 -*-\nimport os\nfrom functools import partial\nfrom collections import defaultdict\nfrom irc3.utils impo"
  },
  {
    "path": "irc3/dec.py",
    "chars": 4472,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.utils import wraps_with_context\nfrom irc3.compat import asyncio\nimport venusian\nimport"
  },
  {
    "path": "irc3/plugins/__init__.py",
    "chars": 24,
    "preview": "# -*- coding: utf-8 -*-\n"
  },
  {
    "path": "irc3/plugins/asynchronious.py",
    "chars": 13250,
    "preview": "# -*- coding: utf-8 -*-\nfrom collections import OrderedDict\nimport re\nfrom irc3.asynchronous import AsyncEvents\nfrom irc"
  },
  {
    "path": "irc3/plugins/autocommand.py",
    "chars": 3305,
    "preview": "import irc3\nfrom irc3 import utils, asyncio\nimport re\n\n__doc__ = '''\n==================================================\n"
  },
  {
    "path": "irc3/plugins/autojoins.py",
    "chars": 4191,
    "preview": "# -*- coding: utf-8 -*-\nimport irc3\nfrom irc3 import utils\n__doc__ = '''\n==============================================\n"
  },
  {
    "path": "irc3/plugins/casefold.py",
    "chars": 2105,
    "preview": "# -*- coding: utf-8 -*-\nimport functools\nimport string\nimport irc3\n__doc__ = '''\n======================================="
  },
  {
    "path": "irc3/plugins/command.py",
    "chars": 17879,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.compat import asyncio\nfrom irc3 import utils\nfrom collections import defaultdict\nimpor"
  },
  {
    "path": "irc3/plugins/core.py",
    "chars": 3837,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3 import event\nfrom irc3 import rfc\n__doc__ = '''\n======================================"
  },
  {
    "path": "irc3/plugins/cron.py",
    "chars": 2461,
    "preview": "# -*- coding: utf-8 -*-\nimport venusian\nimport logging\nimport irc3\n__doc__ = '''\n======================================="
  },
  {
    "path": "irc3/plugins/ctcp.py",
    "chars": 2248,
    "preview": "# -*- coding: utf-8 -*-\nfrom datetime import datetime\nfrom irc3.compat import Queue\nfrom irc3.compat import QueueFull\nim"
  },
  {
    "path": "irc3/plugins/dcc.py",
    "chars": 1960,
    "preview": "# -*- coding: utf-8 -*-\nimport irc3\nfrom irc3.plugins import command\n__doc__ = \"\"\"\n====================================="
  },
  {
    "path": "irc3/plugins/feeds.py",
    "chars": 8658,
    "preview": "# -*- coding: utf-8 -*-\nimport os\nimport time\nimport irc3\nimport datetime\nfrom irc3.compat import asyncio\nfrom concurren"
  },
  {
    "path": "irc3/plugins/fifo.py",
    "chars": 4299,
    "preview": "# -*- coding: utf-8 -*-\nimport os\nimport irc3\nfrom stat import S_ISFIFO\n__doc__ = r'''\n================================="
  },
  {
    "path": "irc3/plugins/human.py",
    "chars": 3008,
    "preview": "# -*- coding: utf-8 -*-\nimport os\nimport irc3\nimport stat\nimport json\nimport codecs\nimport random\nfrom urllib.request im"
  },
  {
    "path": "irc3/plugins/log.py",
    "chars": 1645,
    "preview": "# -*- coding: utf-8 -*-\nimport logging\nimport irc3d\nimport irc3\n__doc__ = '''\n=========================================="
  },
  {
    "path": "irc3/plugins/logger.py",
    "chars": 3847,
    "preview": "# -*- coding: utf-8 -*-\nimport os\nimport irc3\nimport logging\nimport codecs\nfrom datetime import datetime\n__doc__ = '''\n="
  },
  {
    "path": "irc3/plugins/pager.py",
    "chars": 2869,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.plugins.command import command\nfrom irc3 import asyncio\nimport irc3\nimport time\n__doc_"
  },
  {
    "path": "irc3/plugins/quakenet.py",
    "chars": 3924,
    "preview": "import hashlib\nimport hmac\nimport irc3\n\n__doc__ = '''\n====================================================\n:mod:`irc3.pl"
  },
  {
    "path": "irc3/plugins/sasl.py",
    "chars": 1893,
    "preview": "# -*- coding: utf-8 -*-\nimport irc3\nfrom irc3 import utils\nimport base64\n__doc__ = '''\n================================="
  },
  {
    "path": "irc3/plugins/search.py",
    "chars": 1527,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.plugins.command import command\nimport irc3\n__doc__ = '''\n============================="
  },
  {
    "path": "irc3/plugins/shell_command.py",
    "chars": 4086,
    "preview": "# -*- coding: utf-8 -*-\nimport os\nimport irc3\nfrom irc3 import asyncio\nfrom irc3.plugins.command import Commands\n__doc__"
  },
  {
    "path": "irc3/plugins/slack.py",
    "chars": 11213,
    "preview": "import irc3\nfrom irc3 import asyncio\nimport json\nimport re\nimport random\n__doc__ = '''\n================================="
  },
  {
    "path": "irc3/plugins/social.py",
    "chars": 6822,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.plugins.command import command\nimport irc3\nimport json\n__doc__ = '''\n================="
  },
  {
    "path": "irc3/plugins/storage.py",
    "chars": 12211,
    "preview": "# -*- coding: utf-8 -*-\nimport os\n\ntry:\n    import ujson as json\nexcept ImportError:\n    import json\n\nimport irc3\nimport"
  },
  {
    "path": "irc3/plugins/uptime.py",
    "chars": 1529,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.plugins.command import command\nimport time\nimport irc3\n__doc__ = '''\n================="
  },
  {
    "path": "irc3/plugins/userlist.py",
    "chars": 6805,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3 import plugin\nfrom irc3 import utils\nfrom irc3 import rfc\nfrom irc3.dec import event\nf"
  },
  {
    "path": "irc3/plugins/web.py",
    "chars": 2659,
    "preview": "import irc3\n__doc__ = '''\n==========================================\n:mod:`irc3.plugins.web` Web plugin\n================"
  },
  {
    "path": "irc3/rfc.py",
    "chars": 4399,
    "preview": "# -*- coding: utf-8 -*-\nfrom re import compile\nfrom ._rfc import *  # NOQA\n\n_re_params = compile(r'P<([^>]+)>')\n\n\ndef _e"
  },
  {
    "path": "irc3/rfc1459.txt",
    "chars": 138964,
    "preview": "\n\n\n\n\n\nNetwork Working Group                                      J. Oikarinen\nRequest for Comments: 1459                "
  },
  {
    "path": "irc3/rfc2812.txt",
    "chars": 122637,
    "preview": "\n\n\n\n\n\nNetwork Working Group                                            C. Kalt\nRequest for Comments: 2812               "
  },
  {
    "path": "irc3/tags.py",
    "chars": 3560,
    "preview": "# -*- coding: utf-8 -*-\n'''\nModule offering 2 functions, encode() and decode(), to transcode between\nIRCv3.2 tags and py"
  },
  {
    "path": "irc3/template/__init__.py",
    "chars": 1008,
    "preview": "# -*- coding: utf-8 -*-\nimport os\nimport sys\n__doc__ = \"\"\"\nUsage: python -m irc3.template <nickname>\n\"\"\"\n\ndirname = os.p"
  },
  {
    "path": "irc3/template/__main__.py",
    "chars": 95,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.template import main\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "irc3/template/config.ini",
    "chars": 1305,
    "preview": "[bot]\nnick = {nick}\nusername = {nick}\n\nhost = localhost\nport = 6667\n\n# uncomment this if you want ssl support\n# ssl = tr"
  },
  {
    "path": "irc3/template/plugin.py",
    "chars": 617,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.plugins.command import command\nimport irc3\n\n\n@irc3.plugin\nclass Plugin:\n\n    def __ini"
  },
  {
    "path": "irc3/testing.py",
    "chars": 6727,
    "preview": "# -*- coding: utf-8 -*-\nfrom unittest import TestCase\nimport irc3\nimport irc3d\nfrom irc3.compat import asyncio\nimport te"
  },
  {
    "path": "irc3/utils.py",
    "chars": 12596,
    "preview": "# -*- coding: utf-8 -*-\nfrom unicodedata import normalize\nfrom .compat import asyncio\nfrom . import tags\nimport configpa"
  },
  {
    "path": "irc3d/__init__.py",
    "chars": 5938,
    "preview": "# -*- coding: utf-8 -*-\nimport time\nimport venusian\nfrom os import path\nfrom irc3 import base\nfrom irc3 import utils\nfro"
  },
  {
    "path": "irc3d/__main__.py",
    "chars": 774,
    "preview": "import sys\nimport getpass\nfrom irc3d import IrcServer\n\n\ndef main():  # pragma: no cover\n    args = sys.argv[1:]\n    host"
  },
  {
    "path": "irc3d/dec.py",
    "chars": 1192,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3 import dec\nimport venusian\nimport functools\n\n\ndef plugin(wrapped):\n    \"\"\"register a c"
  },
  {
    "path": "irc3d/motd.txt",
    "chars": 384,
    "preview": "               ___          _____     _   ____\n              |_ _|_ __ ___|___ /  __| | / ___|  ___ _ ____   _____ _ __\n"
  },
  {
    "path": "irc3d/plugins/__init__.py",
    "chars": 24,
    "preview": "# -*- coding: utf-8 -*-\n"
  },
  {
    "path": "irc3d/plugins/command.py",
    "chars": 4694,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3 import rfc\nfrom irc3d.dec import event\nfrom irc3d.dec import plugin\nfrom irc3.plugins."
  },
  {
    "path": "irc3d/plugins/core.py",
    "chars": 3728,
    "preview": "# -*- coding: utf-8 -*-\nimport os\nimport time\nfrom irc3 import rfc\nfrom .command import command\nimport irc3d\n__doc__ = '"
  },
  {
    "path": "irc3d/plugins/userlist.py",
    "chars": 11724,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.plugins import userlist\nfrom irc3 import utils\nfrom irc3 import rfc\nimport irc3d\nimpor"
  },
  {
    "path": "pyproject.toml",
    "chars": 1394,
    "preview": "[build-system]\nrequires = [\"setuptools\"]\nbuild-backend = \"setuptools.build_meta\"\n\n[project]\nname = \"irc3\"\nversion = \"1.1"
  },
  {
    "path": "tests/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tests/feed.atom",
    "chars": 14955,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<feed xmlns=\"http://www.w3.org/2005/Atom\" xmlns:media=\"http://search.yahoo.com/mr"
  },
  {
    "path": "tests/test.ini",
    "chars": 486,
    "preview": "[bot]\nnick = irc3\n\nhost = localhost\nport = 6667\nssl = false\n\nincludes =\n    irc3.plugins.core\n    irc3.plugins.ctcp\n    "
  },
  {
    "path": "tests/test_async.py",
    "chars": 7497,
    "preview": "# -*- coding: utf-8 -*-\nimport pytest\n\n\n@pytest.mark.asyncio\nasync def test_whois_fail(irc3_bot_factory):\n    bot = irc3"
  },
  {
    "path": "tests/test_autocommand.py",
    "chars": 1997,
    "preview": "import asyncio\nfrom irc3.testing import BotTestCase, patch\nfrom irc3.plugins.autocommand import AutoCommand, SleepComman"
  },
  {
    "path": "tests/test_autojoins.py",
    "chars": 2840,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.testing import BotTestCase, MagicMock\nfrom irc3.plugins.autojoins import AutoJoins\n\n\nc"
  },
  {
    "path": "tests/test_bot.py",
    "chars": 5309,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.testing import BotTestCase\nfrom irc3.testing import patch\nfrom irc3_plugins_test impor"
  },
  {
    "path": "tests/test_casefold.py",
    "chars": 974,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.testing import BotTestCase\n\n\nclass TestCasefold(BotTestCase):\n\n    config = dict(inclu"
  },
  {
    "path": "tests/test_commands.py",
    "chars": 10242,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.testing import BotTestCase\nfrom irc3.plugins import command\nfrom irc3.plugins import d"
  },
  {
    "path": "tests/test_cron.py",
    "chars": 2215,
    "preview": "# -*- coding: utf-8 -*-\nimport pytest\nfrom irc3.testing import BotTestCase\nfrom irc3.testing import MagicMock\nfrom irc3."
  },
  {
    "path": "tests/test_ctcp.py",
    "chars": 1186,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.testing import BotTestCase\nfrom irc3.plugins.ctcp import CTCP\n\n\nclass TestCTCP(BotTest"
  },
  {
    "path": "tests/test_dcc.py",
    "chars": 6476,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.testing import BotTestCase\nfrom irc3.compat import asyncio\nfrom irc3.dcc.client import"
  },
  {
    "path": "tests/test_dec.py",
    "chars": 584,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.testing import BotTestCase\nimport irc3\n\n\n@irc3.plugin\nclass OldStyleClass:\n    def __i"
  },
  {
    "path": "tests/test_events.py",
    "chars": 1816,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.testing import BotTestCase\nfrom irc3.compat import asyncio\nimport irc3\n\n\n@irc3.event(i"
  },
  {
    "path": "tests/test_feeds.py",
    "chars": 2915,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.testing import BotTestCase\nfrom irc3.testing import MagicMock\nfrom irc3.testing import"
  },
  {
    "path": "tests/test_fifo.py",
    "chars": 1406,
    "preview": "from irc3.testing import BotTestCase, MagicMock\nfrom irc3.plugins.fifo import Fifo\nimport shutil\n\n\nclass TestFifo(BotTes"
  },
  {
    "path": "tests/test_irc3d.py",
    "chars": 3785,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3 import testing\nimport irc3d\n\n\n@irc3d.extend\ndef echo(self):\n    return self\n\n\nclass Te"
  },
  {
    "path": "tests/test_irc3d_commands.py",
    "chars": 1978,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3 import testing\n\n\nclass TestCommands(testing.ServerTestCase):\n\n    def test_not_registe"
  },
  {
    "path": "tests/test_irc3d_userlist.py",
    "chars": 5285,
    "preview": "\n# -*- coding: utf-8 -*-\nfrom irc3 import testing\n\n\nclass TestServerUserList(testing.ServerTestCase):\n\n    def test_ison"
  },
  {
    "path": "tests/test_logger.py",
    "chars": 1702,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.testing import BotTestCase\nimport tempfile\nimport shutil\nimport glob\nimport os\n\n\nclass"
  },
  {
    "path": "tests/test_paginate.py",
    "chars": 855,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.testing import BotTestCase\nfrom irc3.plugins import command\n\n\n@command.command\ndef to_"
  },
  {
    "path": "tests/test_protocol.py",
    "chars": 1144,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.testing import MagicMock\nimport pytest\nimport irc3\n\n\n@pytest.fixture(scope='function')"
  },
  {
    "path": "tests/test_quakenet.py",
    "chars": 2524,
    "preview": "from irc3.testing import BotTestCase\nfrom irc3.plugins import quakenet\n\n\nclass TestQuakenet(BotTestCase):\n\n    config = "
  },
  {
    "path": "tests/test_reconn.py",
    "chars": 1079,
    "preview": "# -*- coding: utf-8 -*-\nimport pytest\nimport irc3\nimport irc3d\nfrom irc3.compat import asyncio\n\n\n@irc3.plugin\nclass P:\n\n"
  },
  {
    "path": "tests/test_reload.py",
    "chars": 2109,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.testing import BotTestCase\nimport tempfile\nimport shutil\nimport sys\nimport os\n\nplugin "
  },
  {
    "path": "tests/test_run.py",
    "chars": 1671,
    "preview": "# -*- coding: utf-8 -*-\nfrom docopt import DocoptExit\nfrom irc3 import testing\nimport tempfile\nimport shutil\nimport irc3"
  },
  {
    "path": "tests/test_sasl.py",
    "chars": 849,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.testing import BotTestCase\n\n\nclass TestSasl(BotTestCase):\n\n    def test_sasl_plain(sel"
  },
  {
    "path": "tests/test_search.py",
    "chars": 877,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.testing import BotTestCase\n\n\nclass TestSearch(BotTestCase):\n\n    config = dict(include"
  },
  {
    "path": "tests/test_slack.py",
    "chars": 2123,
    "preview": "# -*- coding: utf-8 -*-\nimport pytest\nfrom irc3.plugins import slack\n\npytestmark = pytest.mark.asyncio\n\n\nasync def test_"
  },
  {
    "path": "tests/test_social.py",
    "chars": 2623,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.testing import BotTestCase\nfrom irc3.testing import patch\n\n\nclass TestSocial(BotTestCa"
  },
  {
    "path": "tests/test_template.py",
    "chars": 955,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3.testing import BotTestCase\nfrom irc3.template import main\nfrom irc3 import utils\nfrom "
  },
  {
    "path": "tests/test_uptime.py",
    "chars": 729,
    "preview": "\n# -*- coding: utf-8 -*-\nfrom irc3.testing import BotTestCase\n\n\nclass TestUptime(BotTestCase):\n\n    def test_uptime(self"
  },
  {
    "path": "tests/test_userlist.py",
    "chars": 2865,
    "preview": "# -*- coding: utf-8 -*-\nfrom irc3 import testing\n\n\nclass TestUserList(testing.BotTestCase):\n\n    def test_userlist(self)"
  },
  {
    "path": "tests/test_utils.py",
    "chars": 7496,
    "preview": "# -*- coding: utf-8 -*-\nfrom unittest import TestCase\nfrom irc3.utils import IrcString\nfrom irc3.utils import maybedotte"
  },
  {
    "path": "tests/test_web.py",
    "chars": 2286,
    "preview": "# -*- coding: utf-8 -*-\nimport pytest\nfrom irc3.plugins import web\nfrom aiohttp.test_utils import make_mocked_request\n\n\n"
  },
  {
    "path": "tox.ini",
    "chars": 924,
    "preview": "[tox]\nenvlist = py311,py312,py313,flake8,docs\nisolated_build=true\n\n[testenv]\nskipsdist=true\nskip_install=true\nallowlist_"
  }
]

About this extraction

This page contains the full source code of the gawel/irc3 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 166 files (746.4 KB), approximately 198.8k tokens, and a symbol index with 873 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!